1import{r,c as ue,u as Kt,f as Bt,w as zt,d as Gt,P as Wt}from"./chunk-BV7QT456.BQ71lt_D.js";import{j as s}from"./jsx-runtime.u17CrQMm.js";import{o as Yt,a as Qt,b as Xt,e as Jt,D as er,C as We,P as ye,c as tr}from"./prose.DjGFvvFR.js";import{ad as rr,d as L,ae as sr,af as or,ag as Ye,ah as nr,ai as ar,S as W,aj as ir}from"./jwt-generator.DZpDpWmD.js";import{e as pr}from"./Plus.es.Bao4C_up.js";import{c as b,B as R,an as cr,e as lr}from"./index.Bq7B3-hS.js";import"./ExternalLinks.DYQ1kwe5.js";import{S as _,n as dr}from"./SiteLink.DZj8NgI4.js";import{r as mr}from"./ArrowUpRight.es.BKcacYRL.js";import{p as f}from"./IconBase.es.DBo9aoPr.js";import{r as ur}from"./ArrowsClockwise.es.D-1KuJhL.js";import{e as yr}from"./BookOpen.es.BhdxjhA2.js";import{e as gr}from"./ClockCounterClockwise.es.D371ziKg.js";import{e as hr}from"./Code.es.CmC-fk86.js";import{e as br}from"./CreditCard.es.CtqzuZ1q.js";import{e as fr}from"./DownloadSimple.es.Glln1jtn.js";import{o as wr}from"./Envelope.es.DsY8-XUN.js";import{o as jr}from"./FileCode.es.EIpauK25.js";import{o as vr,a as C,b as xr,C as qr}from"./command.CZhrSynC.js";import{e as kr}from"./Globe.es.CM9knrAE.js";import{t as _r,e as Ar,r as Er}from"./Trash.es.DGN_A7Gb.js";import{e as Qe}from"./Info.es.BBfWdyAE.js";import{o as Ir}from"./Key.es.ClQqBiDz.js";import{t as Xe}from"./Lightning.es.Dru4ko2K.js";import{e as Tr}from"./Link.es.CkHbGvfr.js";import{c as Sr}from"./Lock.es.D9SKs7xY.js";import{e as $r}from"./Package.es.rCn8Aym4.js";import{e as Pr,o as Lr}from"./WebhooksLogo.es.B6ASKa6t.js";import{o as Rr}from"./ShieldCheck.es.DJp127z_.js";import{t as Nr}from"./Stack.es.DwCBOihs.js";import{e as Mr}from"./TerminalWindow.es.BYAmArR9.js";import{e as Cr}from"./UploadSimple.es.DIHmJHHu.js";import{o as Vr}from"./Users.es.BjeYW2PC.js";import{t as Je,a as et,b as tt}from"./tabs.BbG9WasU.js";import{S as O}from"./SlidingHighlight.DL8H39PY.js";import{r as Zr}from"./Warning.es.C_TuUWri.js";import{B as F}from"./badge.DcPQDkYT.js";import{e as rt}from"./CaretRight.es.BHIxx2Hu.js";import{e as Or}from"./LockKey.es.BTruJ5TD.js";import{r as Hr}from"./ArrowCounterClockwise.es.DZKZCvtg.js";import{b as ge}from"./field.-frmMaDK.js";import{T as Dr}from"./textarea.TSxm0oD9.js";import{L as he}from"./label.Bw1J3VIE.js";import{e as st}from"./CaretDown.es.v0qXmIHr.js";import{I as ot}from"./input.DOXS53Hb.js";import{T as _e}from"./tools.GtLVLAj0.js";import{a as Ur}from"./PaperPlaneTilt.es.Cj9lB7k-.js";import{o as Fr}from"./Eye.es.pX1VaSs6.js";import{o as Kr}from"./EyeSlash.es.CON-wYJW.js";import{o as nt}from"./MagnifyingGlass.es.BnyZmOn0.js";import{r as Br}from"./index.CqF9FHED.js";import{r as zr}from"./ArrowLeft.es.Bp96g4jV.js";import{r as Gr}from"./ArrowRight.es.JKcZaiQP.js";import{o as Wr}from"./FileText.es.DmbLYXgr.js";import{a as Yr}from"./Hash.es.YvkMOtsN.js";import{D as Ae}from"./interaction.CJtquuJa.js";import{h as Qr,l as Xr,d as Jr}from"./loadDocsModule.CroOVxD0.js";import{b as es}from"./seo.DRFtizGJ.js";import{R as ts}from"./RouteParam.BGKHcA7c.js";import"./Check.es.CGp0En6k.js";import"./Copy.es.dliWH5g9.js";import"./widgets.L_NEDZTt.js";import"./theme.DGKosm2U.js";import"./writeClipboard.CzREpoR6.js";import"./session-replay.D-oy3Zil.js";import"./skeleton.i4c8H1n4.js";import"./KeyAccessors.CfLgbGqN.js";import"./separator.Baq28S32.js";import"./GeneralNotifications.vZC5Rmas.js";import"./Notify.CgSq4mlz.js";import"./preload-helper.HAdMZFT3.js";const rs={TOKEN_STORAGE_KEY:"envless-docs-playground-token",PARAM_LOCATIONS:{PATH:"path",QUERY:"query"},STATUS_CLASSES:{SUCCESS:"bg-success/10 text-success",WARNING:"bg-warning/10 text-warning",DESTRUCTIVE:"bg-destructive/10 text-destructive",NEUTRAL:"bg-muted-foreground/15 text-muted-foreground"},LABELS:{SEND:"Send request",SENDING:"Sendingâ¦",SHOW:"Show API key",HIDE:"Hide API key",EMPTY_BODY:"(empty response body)",NETWORK_ERROR:"The API refused the request from this origin (CORS), or it could not be reached. Check that the base URL is right and that your key is a valid Envless API key.",TOKEN_REQUIRED:"Paste an API key to send the request.",PARAM_REQUIRED:"This parameter is required.",BODY_REQUIRED:"This endpoint needs a JSON body.",BODY_INVALID:"The body is not val
1id JSON: "}},ss={ArrowRight:(e,t)=>(e+1)%t,ArrowLeft:(e,t)=>(e-1+t)%t,Home:()=>0,End:(e,t)=>t-1},os=new Map([["bold",r.createElement(r.Fragment,null,r.createElement("path",{d:"M216,36H40A20,20,0,0,0,20,56V200a20,20,0,0,0,20,20H216a20,20,0,0,0,20-20V56A20,20,0,0,0,216,36Zm-4,160H44V60H212ZM60,92a16,16,0,1,1,16,16A16,16,0,0,1,60,92Zm48,0a16,16,0,1,1,16,16A16,16,0,0,1,108,92Z"}))],["duotone",r.createElement(r.Fragment,null,r.createElement("path",{d:"M224,56V200a8,8,0,0,1-8,8H40a8,8,0,0,1-8-8V56a8,8,0,0,1,8-8H216A8,8,0,0,1,224,56Z",opacity:"0.2"}),r.createElement("path",{d:"M216,40H40A16,16,0,0,0,24,56V200a16,16,0,0,0,16,16H216a16,16,0,0,0,16-16V56A16,16,0,0,0,216,40Zm0,160H40V56H216V200ZM80,84A12,12,0,1,1,68,72,12,12,0,0,1,80,84Zm40,0a12,12,0,1,1-12-12A12,12,0,0,1,120,84Z"}))],["fill",r.createElement(r.Fragment,null,r.createElement("path",{d:"M216,40H40A16,16,0,0,0,24,56V200a16,16,0,0,0,16,16H216a16,16,0,0,0,16-16V56A16,16,0,0,0,216,40ZM68,96A12,12,0,1,1,80,84,12,12,0,0,1,68,96Zm40,0a12,12,0,1,1,12-12A12,12,0,0,1,108,96Z"}))],["light",r.createElement(r.Fragment,null,r.createElement("path",{d:"M216,42H40A14,14,0,0,0,26,56V200a14,14,0,0,0,14,14H216a14,14,0,0,0,14-14V56A14,14,0,0,0,216,42Zm2,158a2,2,0,0,1-2,2H40a2,2,0,0,1-2-2V56a2,2,0,0,1,2-2H216a2,2,0,0,1,2,2ZM78,84A10,10,0,1,1,68,74,10,10,0,0,1,78,84Zm40,0a10,10,0,1,1-10-10A10,10,0,0,1,118,84Z"}))],["regular",r.createElement(r.Fragment,null,r.createElement("path",{d:"M216,40H40A16,16,0,0,0,24,56V200a16,16,0,0,0,16,16H216a16,16,0,0,0,16-16V56A16,16,0,0,0,216,40Zm0,160H40V56H216V200ZM80,84A12,12,0,1,1,68,72,12,12,0,0,1,80,84Zm40,0a12,12,0,1,1-12-12A12,12,0,0,1,120,84Z"}))],["thin",r.createElement(r.Fragment,null,r.createElement("path",{d:"M216,44H40A12,12,0,0,0,28,56V200a12,12,0,0,0,12,12H216a12,12,0,0,0,12-12V56A12,12,0,0,0,216,44Zm4,156a4,4,0,0,1-4,4H40a4,4,0,0,1-4-4V56a4,4,0,0,1,4-4H216a4,4,0,0,1,4,4ZM76,84a8,8,0,1,1-8-8A8,8,0,0,1,76,84Zm40,0a8,8,0,1,1-8-8A8,8,0,0,1,116,84Z"}))]]),ns=new Map([["bold",r.createElement(r.Fragment,null,r.createElement("path",{d:"M208.49,152.49l-72,72a12,12,0,0,1-17,0l-72-72a12,12,0,0,1,17-17L116,187V40a12,12,0,0,1,24,0V187l51.51-51.52a12,12,0,0,1,17,17Z"}))],["duotone",r.createElement(r.Fragment,null,r.createElement("path",{d:"M200,144l-72,72L56,144Z",opacity:"0.2"}),r.createElement("path",{d:"M207.39,140.94A8,8,0,0,0,200,136H136V40a8,8,0,0,0-16,0v96H56a8,8,0,0,0-5.66,13.66l72,72a8,8,0,0,0,11.32,0l72-72A8,8,0,0,0,207.39,140.94ZM128,204.69,75.31,152H180.69Z"}))],["fill",r.createElement(r.Fragment,null,r.createElement("path",{d:"M205.66,149.66l-72,72a8,8,0,0,1-11.32,0l-72-72A8,8,0,0,1,56,136h64V40a8,8,0,0,1,16,0v96h64a8,8,0,0,1,5.66,13.66Z"}))],["light",r.createElement(r.Fragment,null,r.createElement("path",{d:"M204.24,148.24l-72,72a6,6,0,0,1-8.48,0l-72-72a6,6,0,0,1,8.48-8.48L122,201.51V40a6,6,0,0,1,12,0V201.51l61.76-61.75a6,6,0,0,1,8.48,8.48Z"}))],["regular",r.createElement(r.Fragment,null,r.createElement("path",{d:"M205.66,149.66l-72,72a8,8,0,0,1-11.32,0l-72-72a8,8,0,0,1,11.32-11.32L120,196.69V40a8,8,0,0,1,16,0V196.69l58.34-58.35a8,8,0,0,1,11.32,11.32Z"}))],["thin",r.createElement(r.Fragment,null,r.createElement("path",{d:"M202.83,146.83l-72,72a4,4,0,0,1-5.66,0l-72-72a4,4,0,0,1,5.66-5.66L124,206.34V40a4,4,0,0,1,8,0V206.34l65.17-65.17a4,4,0,0,1,5.66,5.66Z"}))]]),as=new Map([["bold",r.createElement(r.Fragment,null,r.createElement("path",{d:"M204,32V176a12,12,0,0,1-12,12H77l27.52,27.51a12,12,0,0,1-17,17l-48-48a12,12,0,0,1,0-17l48-48a12,12,0,1,1,17,17L77,164H180V32a12,12,0,0,1,24,0Z"}))],["duotone",r.createElement(r.Fragment,null,r.createElement("path",{d:"M96,128v96L48,176Z",opacity:"0.2"}),r.createElement("path",{d:"M192,24a8,8,0,0,0-8,8V168H104V128a8,8,0,0,0-13.66-5.66l-48,48a8,8,0,0,0,0,11.32l48,48A8,8,0,0,0,104,224V184h88a8,8,0,0,0,8-8V32A8,8,0,0,0,192,24ZM88,204.69,59.31,176,88,147.31Z"}))],["fill",r.createElement(r.Fragment,null,r.createElement("path",{d:"M200,32V176a8,8,0,0,1-8,8H104v40a8,8,0,0,1-13.66,5.66l-48-48a8,8,0,0,1,0-11.32l48-48A8,8,0,0,1,104,128v40h80V32a8,8,0,0,1,16,0Z"}))],["light",r.createElement(r.Fragment,null,r.createElement("path",{d:"M198,32V176a6,6,0,0,1-6,6H62.49l37.75,37.76a6,6,0,1,1-8.48,8.48l-48-48a6,6,0,0,1,0-8.48l48-48a6,6,0,1,1,8.48,8.48L62.49,170H186V32a6,6,0,0,1,12,0Z"}))],["regular",r.createElement(r.Fragment,null,r.createElement("path",{d:"M200,32V176a8,8,0,0,1-8,8H67.31l34.35,34.34a8,8,0,0,1-11.32,11.32l-48-48a8,8,0,0,1,0-11.32l48-48a8,8,0,0,1,11.32,11.32L67.31,168H184V32a8,8,0,0,1,16,0Z"}))],["thin",r.createElement(r.Fragment,null,r.createElement("path",{d:"M196,32V176a4,4,0,0,1-4,4H57.66l41.17,41.17a4,4,0,0,1-5.66,5.66l-48-48a4,4,0,0,1,0-5.66l48-48a4,4,0,1,1,5.66,5.66L57.66,172H188V32a4,4,0,0,1,8,0Z"}))]]),is=new Map([["bold",r.createElement(r.Fragment,null,r.createElement("path",{d:"M208.49,143.51a12,12,0,0,1-17,17L140,109V224a12,12,0,0,1-24,0V109L64.49,160.49a12,12,0,0,1-17-17l72-72a12,12,0,0,1,17,0ZM216,28H4
10a12,12,0,0,0,0,24H216a12,12,0,0,0,0-24Z"}))],["duotone",r.createElement(r.Fragment,null,r.createElement("path",{d:"M200,144H56l72-72Z",opacity:"0.2"}),r.createElement("path",{d:"M133.66,66.34a8,8,0,0,0-11.32,0l-72,72A8,8,0,0,0,56,152h64v72a8,8,0,0,0,16,0V152h64a8,8,0,0,0,5.66-13.66ZM75.31,136,128,83.31,180.69,136ZM224,40a8,8,0,0,1-8,8H40a8,8,0,0,1,0-16H216A8,8,0,0,1,224,40Z"}))],["fill",r.createElement(r.Fragment,null,r.createElement("path",{d:"M205.66,138.34A8,8,0,0,1,200,152H136v72a8,8,0,0,1-16,0V152H56a8,8,0,0,1-5.66-13.66l72-72a8,8,0,0,1,11.32,0ZM216,32H40a8,8,0,0,0,0,16H216a8,8,0,0,0,0-16Z"}))],["light",r.createElement(r.Fragment,null,r.createElement("path",{d:"M204.24,139.76a6,6,0,1,1-8.48,8.48L134,86.49V224a6,6,0,0,1-12,0V86.49L60.24,148.24a6,6,0,0,1-8.48-8.48l72-72a6,6,0,0,1,8.48,0ZM216,34H40a6,6,0,0,0,0,12H216a6,6,0,0,0,0-12Z"}))],["regular",r.createElement(r.Fragment,null,r.createElement("path",{d:"M205.66,138.34a8,8,0,0,1-11.32,11.32L136,91.31V224a8,8,0,0,1-16,0V91.31L61.66,149.66a8,8,0,0,1-11.32-11.32l72-72a8,8,0,0,1,11.32,0ZM216,32H40a8,8,0,0,0,0,16H216a8,8,0,0,0,0-16Z"}))],["thin",r.createElement(r.Fragment,null,r.createElement("path",{d:"M202.83,141.17a4,4,0,0,1-5.66,5.66L132,81.66V224a4,4,0,0,1-8,0V81.66L58.83,146.83a4,4,0,0,1-5.66-5.66l72-72a4,4,0,0,1,5.66,0ZM216,36H40a4,4,0,0,0,0,8H216a4,4,0,0,0,0-8Z"}))]]),ps=new Map([["bold",r.createElement(r.Fragment,null,r.createElement("path",{d:"M208.49,120.49a12,12,0,0,1-17,0L140,69V216a12,12,0,0,1-24,0V69L64.49,120.49a12,12,0,0,1-17-17l72-72a12,12,0,0,1,17,0l72,72A12,12,0,0,1,208.49,120.49Z"}))],["duotone",r.createElement(r.Fragment,null,r.createElement("path",{d:"M200,112H56l72-72Z",opacity:"0.2"}),r.createElement("path",{d:"M205.66,106.34l-72-72a8,8,0,0,0-11.32,0l-72,72A8,8,0,0,0,56,120h64v96a8,8,0,0,0,16,0V120h64a8,8,0,0,0,5.66-13.66ZM75.31,104,128,51.31,180.69,104Z"}))],["fill",r.createElement(r.Fragment,null,r.createElement("path",{d:"M207.39,115.06A8,8,0,0,1,200,120H136v96a8,8,0,0,1-16,0V120H56a8,8,0,0,1-5.66-13.66l72-72a8,8,0,0,1,11.32,0l72,72A8,8,0,0,1,207.39,115.06Z"}))],["light",r.createElement(r.Fragment,null,r.createElement("path",{d:"M204.24,116.24a6,6,0,0,1-8.48,0L134,54.49V216a6,6,0,0,1-12,0V54.49L60.24,116.24a6,6,0,0,1-8.48-8.48l72-72a6,6,0,0,1,8.48,0l72,72A6,6,0,0,1,204.24,116.24Z"}))],["regular",r.createElement(r.Fragment,null,r.createElement("path",{d:"M205.66,117.66a8,8,0,0,1-11.32,0L136,59.31V216a8,8,0,0,1-16,0V59.31L61.66,117.66a8,8,0,0,1-11.32-11.32l72-72a8,8,0,0,1,11.32,0l72,72A8,8,0,0,1,205.66,117.66Z"}))],["thin",r.createElement(r.Fragment,null,r.createElement("path",{d:"M202.83,114.83a4,4,0,0,1-5.66,0L132,49.66V216a4,4,0,0,1-8,0V49.66L58.83,114.83a4,4,0,0,1-5.66-5.66l72-72a4,4,0,0,1,5.66,0l72,72A4,4,0,0,1,202.83,114.83Z"}))]]),cs=new Map([["bold",r.createElement(r.Fragment,null,r.createElement("path",{d:"M128,20A108,108,0,1,0,236,128,108.12,108.12,0,0,0,128,20Zm0,192a84,84,0,1,1,84-84A84.09,84.09,0,0,1,128,212ZM163.27,77l-56,24a12,12,0,0,0-6.3,6.3l-24,56A12,12,0,0,0,92.73,179l56-24a12,12,0,0,0,6.3-6.3l24-56A12,12,0,0,0,163.27,77Zm-28.41,57.89-24,10.29,10.29-24,24-10.29Z"}))],["duotone",r.createElement(r.Fragment,null,r.createElement("path",{d:"M128,32a96,96,0,1,0,96,96A96,96,0,0,0,128,32Zm16,112L80,176l32-64,64-32Z",opacity:"0.2"}),r.createElement("path",{d:"M128,24A104,104,0,1,0,232,128,104.11,104.11,0,0,0,128,24Zm0,192a88,88,0,1,1,88-88A88.1,88.1,0,0,1,128,216ZM172.42,72.84l-64,32a8.05,8.05,0,0,0-3.58,3.58l-32,64A8,8,0,0,0,80,184a8.1,8.1,0,0,0,3.58-.84l64-32a8.05,8.05,0,0,0,3.58-3.58l32-64a8,8,0,0,0-10.74-10.74ZM138,138,97.89,158.11,118,118l40.15-20.07Z"}))],["fill",r.createElement(r.Fragment,null,r.createElement("path",{d:"M128,24A104,104,0,1,0,232,128,104.11,104.11,0,0,0,128,24Zm51.58,57.79-32,64a4.08,4.08,0,0,1-1.79,1.79l-64,32a4,4,0,0,1-5.37-5.37l32-64a4.08,4.08,0,0,1,1.79-1.79l64-32A4,4,0,0,1,179.58,81.79Z"}))],["light",r.createElement(r.Fragment,null,r.createElement("path",{d:"M128,26A102,102,0,1,0,230,128,102.12,102.12,0,0,0,128,26Zm0,192a90,90,0,1,1,90-90A90.1,90.1,0,0,1,128,218ZM173.32,74.63l-64,32a6,6,0,0,0-2.69,2.69l-32,64A6,6,0,0,0,80,182a6.06,6.06,0,0,0,2.68-.63l64-32a6,6,0,0,0,2.69-2.69l32-64a6,6,0,0,0-8.05-8.05Zm-33.79,64.9L93.42,162.58l23-46.11,46.11-23Z"}))],["regular",r.createElement(r.Fragment,null,r.createElement("path",{d:"M128,24A104,104,0,1,0,232,128,104.11,104.11,0,0,0,128,24Zm0,192a88,88,0,1,1,88-88A88.1,88.1,0,0,1,128,216ZM172.42,72.84l-64,32a8.05,8.05,0,0,0-3.58,3.58l-32,64A8,8,0,0,0,80,184a8.1,8.1,0,0,0,3.58-.84l64-32a8.05,8.05,0,0,0,3.58-3.58l32-64a8,8,0,0,0-10.74-10.74ZM138,138,97.89,158.11,118,118l40.15-20.07Z"}))],["thin",r.createElement(r.Fragment,null,r.createElement("path",{d:"M128,28A100,100,0,1,0,228,128,100.11,100.11,0,0,0,128,28Zm0,192a92,92,0,1,1,92-92A92.1,92.1,0,0,1,128,220ZM174.21,76.42l-64,32a4.08,4.08,0,0,0-1.79,1.79l-32,64A4,4,0,0,0,80,180a4.05,4.05,0,0,0,1.79-.42l64-32a4.08,4.08,0,0,0,1.79-1.79l32-64a4,4,0,0,0-5.37-5.37ZM141,141l-52.08,26L115,115l52.08-26Z"}))]]),ls=new Map([["bold",r.createElement(r.Fragment,null,r.createElement("path",{d:"M225.6,62.64l-88-48.17a19.91,19.91,0,0,0-19.2,0l-88,48.17A20,20,0,0,0,20,80.19v95.62a20,20,0,0,0,10.4,17.55l88,48.17a19.89,19.89,0,0,0,19.2,0l88-48.17A20,20,0,0,0,236,175.81V80.19A20,20,0,0,0,225.6,62.64ZM128,36.57,200,76,128,115.4,56,76ZM44,96.79l72,39.4v76.67L44,173.44Zm96,116.07V136.19l72-39.4v76.65Z"}))],["duotone",r.createElement(r.Fragment,null,r.createElement("path",{d:"M128,129.09V232a8,8,0,0,1-3.84-1l-88-48.16a8,8,0,0,1-4.16-7V80.2a8,8,0,0,1,.7-3.27Z",o
1pacity:"0.2"}),r.createElement("path",{d:"M223.68,66.15,135.68,18h0a15.88,15.88,0,0,0-15.36,0l-88,48.17a16,16,0,0,0-8.32,14v95.64a16,16,0,0,0,8.32,14l88,48.17a15.88,15.88,0,0,0,15.36,0l88-48.17a16,16,0,0,0,8.32-14V80.18A16,16,0,0,0,223.68,66.15ZM128,32h0l80.34,44L128,120,47.66,76ZM40,90l80,43.78v85.79L40,175.82Zm96,129.57V133.82L216,90v85.78Z"}))],["fill",r.createElement(r.Fragment,null,r.createElement("path",{d:"M223.68,66.15,135.68,18a15.88,15.88,0,0,0-15.36,0l-88,48.17a16,16,0,0,0-8.32,14v95.64a16,16,0,0,0,8.32,14l88,48.17a15.88,15.88,0,0,0,15.36,0l88-48.17a16,16,0,0,0,8.32-14V80.18A16,16,0,0,0,223.68,66.15ZM128,120,47.65,76,128,32l80.35,44Zm8,99.64V133.83l80-43.78v85.76Z"}))],["light",r.createElement(r.Fragment,null,r.createElement("path",{d:"M222.72,67.9l-88-48.17a13.9,13.9,0,0,0-13.44,0l-88,48.18A14,14,0,0,0,26,80.18v95.64a14,14,0,0,0,7.28,12.27l88,48.18a13.92,13.92,0,0,0,13.44,0l88-48.18A14,14,0,0,0,230,175.82V80.18A14,14,0,0,0,222.72,67.9ZM127,30.25a2,2,0,0,1,1.92,0L212.51,76,128,122.24,43.49,76ZM39,177.57a2,2,0,0,1-1-1.75V86.66l84,46V223Zm177.92,0L134,223V132.64l84-46v89.16A2,2,0,0,1,217,177.57Z"}))],["regular",r.createElement(r.Fragment,null,r.createElement("path",{d:"M223.68,66.15,135.68,18h0a15.88,15.88,0,0,0-15.36,0l-88,48.17a16,16,0,0,0-8.32,14v95.64a16,16,0,0,0,8.32,14l88,48.17a15.88,15.88,0,0,0,15.36,0l88-48.17a16,16,0,0,0,8.32-14V80.18A16,16,0,0,0,223.68,66.15ZM128,32h0l80.34,44L128,120,47.66,76ZM40,90l80,43.78v85.79L40,175.82Zm96,129.57V133.82L216,90v85.78Z"}))],["thin",r.createElement(r.Fragment,null,r.createElement("path",{d:"M221.76,69.66l-88-48.18a12,12,0,0,0-11.52,0l-88,48.18A12,12,0,0,0,28,80.18v95.64a12,12,0,0,0,6.24,10.52l88,48.18a11.95,11.95,0,0,0,11.52,0l88-48.18A12,12,0,0,0,228,175.82V80.18A12,12,0,0,0,221.76,69.66ZM126.08,28.5a3.94,3.94,0,0,1,3.84,0L216.67,76,128,124.52,39.33,76Zm-88,150.83A4,4,0,0,1,36,175.82V83.29l88,48.16v94.91Zm179.84,0-85.92,47V131.45l88-48.16v92.53A4,4,0,0,1,217.92,179.32Z"}))]]),ds=new Map([["bold",r.createElement(r.Fragment,null,r.createElement("path",{d:"M250.18,105.17,186.71,41.25a100.11,100.11,0,0,0-141.43,0l-.13.14L31.37,55.61a12,12,0,1,0,17.24,16.7L62.32,58.16A75.68,75.68,0,0,1,77.49,46.43L119,88,25.85,181.16a20,20,0,0,0,0,28.29l20.69,20.69a20,20,0,0,0,28.28,0L168,137l1.51,1.51h0l23.65,23.66a20,20,0,0,0,28.29,0l28.69-28.7A20,20,0,0,0,250.18,105.17ZM60.68,210.34l-15-15L108,133l15,15ZM140,131l-15-15,19.51-19.51a12,12,0,0,0,0-17L102.24,37.24a75.94,75.94,0,0,1,67.47,20.95l31.44,31.67L178,113l-1.51-1.51a12,12,0,0,0-17,0Zm67.32,11.31L195,130l23.09-23.09,12.3,12.39Z"}))],["duotone",r.createElement(r.Fragment,null,r.createElement("path",{d:"M245.66,129,217,157.66a8,8,0,0,1-11.3,0L168.1,120l-28,28-32-32,28-28L80,31.78a87.81,87.81,0,0,1,98.31,18l67.35,67.89A8,8,0,0,1,245.66,129Z",opacity:"0.2"}),r.createElement("path",{d:"M251.34,112,183.88,44.08a96.1,96.1,0,0,0-135.77,0l-.09.09L34.25,58.4A8,8,0,0,0,45.74,69.53L59.47,55.35a79.92,79.92,0,0,1,18.71-13.9L124.68,88l-96,96a16,16,0,0,0,0,22.63l20.69,20.69a16,16,0,0,0,22.63,0l96-96,14.34,14.34h0L200,163.3a16,16,0,0,0,22.63,0l28.69-28.69A16,16,0,0,0,251.34,112ZM60.68,216,40,195.31l68-68L128.68,148ZM162.34,114.32,140,136.67,119.31,116l22.35-22.35a8,8,0,0,0,0-11.32L94.32,35a80,80,0,0,1,78.23,20.41l44.22,44.51L188,128.66l-14.34-14.34A8,8,0,0,0,162.34,114.32Zm49,37.66-12-12L228,111.25l12,12Z"}))],["fill",r.createElement(r.Fragment,null,r.createElement("path",{d:"M251.34,112,183.88,44.08a96.1,96.1,0,0,0-135.77,0l-.09.09L34.25,58.4A8,8,0,0,0,45.74,69.53L59.47,55.35a79.92,79.92,0,0,1,18.71-13.9L124.68,88l-96,96a16,16,0,0,0,0,22.63l20.69,20.69a16,16,0,0,0,22.63,0l96-96,32,32a16,16,0,0,0,22.63,0l28.69-28.69A16,16,0,0,0,251.34,112Zm-89,2.33L140,136.67,119.31,116l22.35-22.35a8,8,0,0,0,0-11.32L94.32,35a80,80,0,0,1,78.23,20.41l44.22,44.51L188,128.66l-14.34-14.34A8,8,0,0,0,162.34,114.32Zm49,37.66-12-12L228,111.25l12,12Z"}))],["light",r.createElement(r.Fragment,null,r.createElement("path",{d:"M249.92,113.4,182.47,45.49a94.12,94.12,0,0,0-133,.06L35.68,59.78a6,6,0,0,0,8.63,8.35L58,54A82,82,0,0,1,78.55,39l49,49L30.09,185.4a14,14,0,0,0,0,19.81L50.78,225.9a14,14,0,0,0,19.8,0L168,128.46l33.42,33.42a14,14,0,0,0,19.8,0l28.68-28.69A14,14,0,0,0,249.92,113.4ZM62.1,217.41a2,2,0,0,1-2.83,0L38.58,196.72a2,2,0,0,1,0-2.83L108,124.46,131.51,148ZM163.76,115.73,140,139.49,116.48,116l23.76-23.76a6,6,0,0,0,0-8.49L90.54,34A82.07,82.07,0,0,1,174,54l45.62,45.93L188,131.49l-15.76-15.76A6,6,0,0,0,163.76,115.73Zm77.66,9-28.69,28.7a2,2,0,0,1-2.83,0L196.49,140l31.56-31.57,13.37,13.46A2,2,0,0,1,241.42,124.7Z"}))],["regular",r.createElement(r.Fragment,null,r.createElement("path",{d:"M251.34,112,183.88,44.08a96.1,96.1,0,0,0-135.77,0l-.09.09L34.25,58.4A8,8,0,0,0,45.74,69.53L59.47,55.35a79.92,79.92,0,0,1,18.71-13.9L124.68,88l-96,96a16,16,0,0,0,0,22.63l20.69,20.69a16,16,0,0,0,22.63,0l96-96,14.34,14.34h0L200,163.3a16,16,0,0,0,22.63,0l28.69-28.69A16,16,0,0,0,251.34,112ZM60.
168,216,40,195.31l68-68L128.68,148ZM162.34,114.32,140,136.67,119.31,116l22.35-22.35a8,8,0,0,0,0-11.32L94.32,35a80,80,0,0,1,78.23,20.41l44.22,44.51L188,128.66l-14.34-14.34A8,8,0,0,0,162.34,114.32Zm49,37.66-12-12L228,111.25l12,12Z"}))],["thin",r.createElement(r.Fragment,null,r.createElement("path",{d:"M248.5,114.81,181.05,46.9A92.1,92.1,0,0,0,50.9,47L37.12,61.18a4,4,0,1,0,5.75,5.56L56.6,52.56a83.75,83.75,0,0,1,22.34-16L130.34,88,31.51,186.82a12,12,0,0,0,0,17L52.2,224.48a12,12,0,0,0,17,0L168,125.63l17.17,17.18h0l17.66,17.66a12,12,0,0,0,17,0l28.69-28.69A12,12,0,0,0,248.5,114.81Zm-185,104a4,4,0,0,1-5.66,0L37.17,198.14a4,4,0,0,1,0-5.66L108,121.63,134.34,148ZM165.17,117.15,140,142.32,113.65,116,138.83,90.8a4,4,0,0,0,0-5.66l-52-52a84.11,84.11,0,0,1,88.52,19.38l47,47.35L188,134.32l-17.17-17.17A4,4,0,0,0,165.17,117.15Zm77.66,9-28.68,28.69a4,4,0,0,1-5.66,0L193.66,140l34.39-34.4,14.78,14.88A4,4,0,0,1,242.83,126.12Z"}))]]),ms=new Map([["bold",r.createElement(r.Fragment,null,r.createElement("path",{d:"M234.49,111.07,90.41,22.94A20,20,0,0,0,60,39.87V216.13a20,20,0,0,0,30.41,16.93l144.08-88.13a19.82,19.82,0,0,0,0-33.86ZM84,208.85V47.15L216.16,128Z"}))],["duotone",r.createElement(r.Fragment,null,r.createElement("path",{d:"M228.23,134.69,84.15,222.81A8,8,0,0,1,72,216.12V39.88a8,8,0,0,1,12.15-6.69l144.08,88.12A7.82,7.82,0,0,1,228.23,134.69Z",opacity:"0.2"}),r.createElement("path",{d:"M232.4,114.49,88.32,26.35a16,16,0,0,0-16.2-.3A15.86,15.86,0,0,0,64,39.87V216.13A15.94,15.94,0,0,0,80,232a16.07,16.07,0,0,0,8.36-2.35L232.4,141.51a15.81,15.81,0,0,0,0-27ZM80,215.94V40l143.83,88Z"}))],["fill",r.createElement(r.Fragment,null,r.createElement("path",{d:"M240,128a15.74,15.74,0,0,1-7.6,13.51L88.32,229.65a16,16,0,0,1-16.2.3A15.86,15.86,0,0,1,64,216.13V39.87a15.86,15.86,0,0,1,8.12-13.82,16,16,0,0,1,16.2.3L232.4,114.49A15.74,15.74,0,0,1,240,128Z"}))],["light",r.createElement(r.Fragment,null,r.createElement("path",{d:"M231.36,116.19,87.28,28.06a14,14,0,0,0-14.18-.27A13.69,13.69,0,0,0,66,39.87V216.13a13.69,13.69,0,0,0,7.1,12.08,14,14,0,0,0,14.18-.27l144.08-88.13a13.82,13.82,0,0,0,0-23.62Zm-6.26,13.38L81,217.7a2,2,0,0,1-2.06,0,1.78,1.78,0,0,1-1-1.61V39.87a1.78,1.78,0,0,1,1-1.61A2.06,2.06,0,0,1,80,38a2,2,0,0,1,1,.31L225.1,126.43a1.82,1.82,0,0,1,0,3.14Z"}))],["regular",r.createElement(r.Fragment,null,r.createElement("path",{d:"M232.4,114.49,88.32,26.35a16,16,0,0,0-16.2-.3A15.86,15.86,0,0,0,64,39.87V216.13A15.94,15.94,0,0,0,80,232a16.07,16.07,0,0,0,8.36-2.35L232.4,141.51a15.81,15.81,0,0,0,0-27ZM80,215.94V40l143.83,88Z"}))],["thin",r.createElement(r.Fragment,null,r.createElement("path",{d:"M230.32,117.9,86.24,29.79a11.91,11.91,0,0,0-12.17-.23A11.71,11.71,0,0,0,68,39.89V216.11a11.71,11.71,0,0,0,6.07,10.33,11.91,11.91,0,0,0,12.17-.23L230.32,138.1a11.82,11.82,0,0,0,0-20.2Zm-4.18,13.37L82.06,219.39a4,4,0,0,1-4.07.07,3.77,3.77,0,0,1-2-3.35V39.89a3.77,3.77,0,0,1,2-3.35,4,4,0,0,1,4.07.07l144.08,88.12a3.8,3.8,0,0,1,0,6.54Z"}))]]),us=new Map([["bold",r.createElement(r.Fragment,null,r.createElement("path",{d:"M208,36H48A20,20,0,0,0,28,56v56c0,54.29,26.32,87.22,48.4,105.29,23.71,19.39,47.44,26,48.44,26.29a12.1,12.1,0,0,0,6.32,0c1-.28,24.73-6.9,48.44-26.29,22.08-18.07,48.4-51,48.4-105.29V56A20,20,0,0,0,208,36Zm-4,76c0,35.71-13.09,64.69-38.91,86.15A126.28,126.28,0,0,1,128,219.38a126.14,126.14,0,0,1-37.09-21.23C65.09,176.69,52,147.71,52,112V60H204Z"}))],["duotone",r.createElement(r.Fragment,null,r.createElement("path",{d:"M216,56v56c0,96-88,120-88,120S40,208,40,112V56a8,8,0,0,1,8-8H208A8,8,0,0,1,216,56Z",opacity:"0.2"}),r.createElement("path",{d:"M208,40H48A16,16,0,0,0,32,56v56c0,52.72,25.52,84.67,46.93,102.19,23.06,18.86,46,25.27,47,25.53a8,8,0,0,0,4.2,0c1-.26,23.91-6.67,47-25.53C198.48,196.67,224,164.72,224,112V56A16,16,0,0,0,208,40Zm0,72c0,37.07-13.66,67.16-40.6,89.42A129.3,129.3,0,0,1,128,223.62a128.25,128.25,0,0,1-38.92-21.81C61.82,179.51,48,149.3,48,112l0-56,160,0Z"}))],["fill",r.createElement(r.Fragment,null,r.createElement("path",{d:"M224,56v56c0,52.72-25.52,84.67-46.93,102.19-23.06,18.86-46,25.27-47,25.53a8,8,0,0,1-4.2,0c-1-.26-23.91-6.67-47-25.53C57.52,196.67,32,164.72,32,112V56A16,16,0,0,1,48,40H208A16,16,0,0,1,224,56Z"}))],["light",r.createElement(r.Fragment,null,r.createElement("path",{d:"M208,42H48A14,14,0,0,0,34,56v56c0,51.94,25.12,83.4,46.2,100.64,22.73,18.6,45.27,24.89,46.22,25.15a6,6,0,0,0,3.16,0c.95-.26,23.49-6.55,46.22-25.15C196.88,195.4,222,163.94,222,112V56A14,14,0,0,0,208,42Zm2,70c0,37.76-13.94,68.39-41.44,91.06A131.17,131.17,0,0,1,128,225.72a130.94,130.94,0,0,1-40.56-22.66C59.94,180.39,46,149.76,46,112V56a2,2,0,0,1,2-2H208a2,2,0,0,1,2,2Z"}))],["regular",r.createElement(r.Fragment,null,r.createElement("path",{d:"M208,40H48A16,16,0,0,0,32,56v56c0,52.72,25.52,84.67,46.93,102.19,23.06,18.86,46,25.27,47,25.53a8,8,0,0,0,4.2,0c1-.26,23.91-6.67,47-25.53C198.48,196.67,224,164.72,224,112V56A16,16,0,0,0,208,40Zm0,72c0,37.07-13.66,67.16-40.6,89.42A129.3,129.3,0,0,1,128,223.62a128.25,128.25,0,0,1-38.92-21.81C61.82,179.51,48,149.3,48,112l0-56,160,0Z"}))],["thin",r.createElement(r.Fragment,null,r.createElement("path",{d:"M208,44H48A12,12,0,0,0,36,56v56c0,51.16,24.73,82.12,45.47,99.1,22.4,18.32,44.55,24.5,45.48,24.76a4,4,0,0,0,2.1,0c.93-.26,23.08-6.44,45.48-24.76,20.74-17,45.47-47.94,45.47-99.1V56A12,12,0,0,0,208,44Zm4,68c0,38.44-14.23,69.63-42.29,92.71A132.45,132.45,0,0,1,128,227.82a132.23,132.23,0,0,1-41.71-23.11C58.23,181.63,44,150.44,44,112V56a4,4,0,0,1,4-4H208a4,4,0,0,1,4,4Z"}))]]),ys=new Map([["bold",r.createElement(r.Fragment,null,r.createElement("path",{d:"M144.49,136.49l-40,40a12,12,0,0,1-17-17L107,140H24a12,12,0,0,1,0-24h83L87.51,96.49a12,12,0,0,1,17-17l40,40A12,12,0,0,1,144.49,136.49ZM200,28H136a12,12,0,0,0,0,24h52V204H136a12,12,0,0,0,0,24h64a12,12,0,0,0,12-12V40A12,12,0,0,0,200,28Z"}))],["duotone",r.createElement(r.Fragment,null,r.createElement("path",{d:"M200,40V216H40a16,16,0,0,1-16-16V56A16,16,0,0,1,40,40Z",opacity:"0.2"}),r.createElement("path",{d:"M141.66,133.66l-40,40a8,8,0,0,1-11.32-11.32L116.69,136H24a8,8,0,0,1,0-16h92.69L90.34,93.66a8,8,0,0,1,11.32-11.32l40,40A8,8,0,0,1,141.66,133.66ZM200,32H136a8,8,0,0,0,0,16h56V208H136a8,8,0,0,0,0,16h64a8,8,0,0,0,8-8V40A8,8,0,0,0,200,32Z"}))],["fill",r.createElement(r.Fragment,null,r.createElement("path",{d:"M141.66,133.66l-40,40A8,8,0,0,1,88,168V136H24a8,8,0,0,1,0-16H88V88a8,8,0,0,1,13.66-5.66l40,40A8,8,0,0,1,141.66,133.66ZM200,32H136a8,8,0,0,0,0,16h56V208H136a8,8,0,0,0,0,16h64a8,8,0,0,0,8-8V40A8,8,0,0,0,200,32Z"}))],["light",r.createElement(r.Fragment,null,r.createElement("path",{d:"M140.24,132.24l-40,40a6,
16,0,0,1-8.48-8.48L121.51,134H24a6,6,0,0,1,0-12h97.51L91.76,92.24a6,6,0,0,1,8.48-8.48l40,40A6,6,0,0,1,140.24,132.24ZM200,34H136a6,6,0,0,0,0,12h58V210H136a6,6,0,0,0,0,12h64a6,6,0,0,0,6-6V40A6,6,0,0,0,200,34Z"}))],["regular",r.createElement(r.Fragment,null,r.createElement("path",{d:"M141.66,133.66l-40,40a8,8,0,0,1-11.32-11.32L116.69,136H24a8,8,0,0,1,0-16h92.69L90.34,93.66a8,8,0,0,1,11.32-11.32l40,40A8,8,0,0,1,141.66,133.66ZM200,32H136a8,8,0,0,0,0,16h56V208H136a8,8,0,0,0,0,16h64a8,8,0,0,0,8-8V40A8,8,0,0,0,200,32Z"}))],["thin",r.createElement(r.Fragment,null,r.createElement("path",{d:"M138.83,130.83l-40,40a4,4,0,0,1-5.66-5.66L126.34,132H24a4,4,0,0,1,0-8H126.34L93.17,90.83a4,4,0,0,1,5.66-5.66l40,40A4,4,0,0,1,138.83,130.83ZM200,36H136a4,4,0,0,0,0,8h60V212H136a4,4,0,0,0,0,8h64a4,4,0,0,0,4-4V40A4,4,0,0,0,200,36Z"}))]]),gs=new Map([["bold",r.createElement(r.Fragment,null,r.createElement("path",{d:"M208,28H48A20,20,0,0,0,28,48V208a20,20,0,0,0,20,20H208a20,20,0,0,0,20-20V48A20,20,0,0,0,208,28Zm-4,176H52V52H204Z"}))],["duotone",r.createElement(r.Fragment,null,r.createElement("path",{d:"M216,48V208a8,8,0,0,1-8,8H48a8,8,0,0,1-8-8V48a8,8,0,0,1,8-8H208A8,8,0,0,1,216,48Z",opacity:"0.2"}),r.createElement("path",{d:"M208,32H48A16,16,0,0,0,32,48V208a16,16,0,0,0,16,16H208a16,16,0,0,0,16-16V48A16,16,0,0,0,208,32Zm0,176H48V48H208V208Z"}))],["fill",r.createElement(r.Fragment,null,r.createElement("path",{d:"M224,48V208a16,16,0,0,1-16,16H48a16,16,0,0,1-16-16V48A16,16,0,0,1,48,32H208A16,16,0,0,1,224,48Z"}))],["light",r.createElement(r.Fragment,null,r.createElement("path",{d:"M208,34H48A14,14,0,0,0,34,48V208a14,14,0,0,0,14,14H208a14,14,0,0,0,14-14V48A14,14,0,0,0,208,34Zm2,174a2,2,0,0,1-2,2H48a2,2,0,0,1-2-2V48a2,2,0,0,1,2-2H208a2,2,0,0,1,2,2Z"}))],["regular",r.createElement(r.Fragment,null,r.createElement("path",{d:"M208,32H48A16,16,0,0,0,32,48V208a16,16,0,0,0,16,16H208a16,16,0,0,0,16-16V48A16,16,0,0,0,208,32Zm0,176H48V48H208V208Z"}))],["thin",r.createElement(r.Fragment,null,r.createElement("path",{d:"M208,36H48A12,12,0,0,0,36,48V208a12,12,0,0,0,12,12H208a12,12,0,0,0,12-12V48A12,12,0,0,0,208,36Zm4,172a4,4,0,0,1-4,4H48a4,4,0,0,1-4-4V48a4,4,0,0,1,4-4H208a4,4,0,0,1,4,4Z"}))]]),hs=new Map([["bold",r.createElement(r.Fragment,null,r.createElement("path",{d:"M224,44H32A12,12,0,0,0,20,56V192a20,20,0,0,0,20,20H216a20,20,0,0,0,20-20V56A12,12,0,0,0,224,44ZM44,116H76v24H44Zm56,0H212v24H100ZM212,68V92H44V68ZM44,164H76v24H44Zm56,24V164H212v24Z"}))],["duotone",r.createElement(r.Fragment,null,r.createElement("path",{d:"M88,104v96H32V104Z",opacity:"0.2"}),r.createElement("path",{d:"M224,48H32a8,8,0,0,0-8,8V192a16,16,0,0,0,16,16H216a16,16,0,0,0,16-16V56A8,8,0,0,0,224,48ZM40,112H80v32H40Zm56,0H216v32H96ZM216,64V96H40V64ZM40,160H80v32H40Zm176,32H96V160H216v32Z"}))],["fill",r.createElement(r.Fragment,null,r.createElement("path",{d:"M224,48H32a8,8,0,0,0-8,8V192a16,16,0,0,0,16,16H216a16,16,0,0,0,16-16V56A8,8,0,0,0,224,48ZM40,112H80v32H40Zm56,0H216v32H96ZM40,160H80v32H40Zm176,32H96V160H216v32Z"}))],["light",r.createElement(r.Fragment,null,r.createElement("path",{d:"M224,50H32a6,6,0,0,0-6,6V192a14,14,0,0,0,14,14H216a14,14,0,0,0,14-14V56A6,6,0,0,0,224,50ZM38,110H82v36H38Zm56,0H218v36H94ZM218,62V98H38V62ZM38,192V158H82v36H40A2,2,0,0,1,38,192Zm178,2H94V158H218v34A2,2,0,0,1,216,194Z"}))],["regular",r.createElement(r.Fragment,null,r.createElement("path",{d:"M224,48H32a8,8,0,0,0-8,8V192a16,16,0,0,0,16,16H216a16,16,0,0,0,16-16V56A8,8,0,0,0,224,48ZM40,112H80v32H40Zm56,0H216v32H96ZM216,64V96H40V64ZM40,160H80v32H40Zm176,32H96V160H216v32Z"}))],["thin",r.createElement(r.Fragment,null,r.createElement("path",{d:"M224,52H32a4,4,0,0,0-4,4V192a12,12,0,0,0,12,12H216a12,12,0,0,0,12-12V56A4,4,0,0,0,224,52ZM36,108H84v40H36Zm56,0H220v40H92ZM220,60v40H36V60ZM36,192V156H84v40H40A4,4,0,0,1,36,192Zm180,4H92V156H220v36A4,4,0,0,1,216,196Z"}))]]),bs=new Map([["bold",r.createElement(r.Fragment,null,r.createElement("path",{d:"M120,137,48,201A12,12,0,1,1,32,183l61.91-55L32,73A12,12,0,1,1,48,55l72,64A12,12,0,0,1,120,137Zm96,43H120a12,12,0,0,0,0,24h96a12,12,0,0,0,0-24Z"}))],["duotone",r.createElement(r.Fragment,null,r.createElement("path",{d:"M216,80V192H40V64H200A16,16,0,0,1,216,80Z",opacity:"0.2"}),r.createElement("path",{d:"M117.31,134l-72,64a8,8,0,1,1-10.63-12L100,128,34.69,70A8,8,0,1,1,45.32,58l72,64a8,8,0,0,1,0,12ZM216,184H120a8,8,0,0,0,0,16h96a8,8,0,0,0,0-16Z"}))],["fill",r.createElement(r.Fragment,null,r.createElement("path",{d:"M216,40H40A16,16,0,0,0,24,56V200a16,16,0,0,0,16,16H216a16,16,0,0,0,16-16V56A16,16,0,0,0,216,40ZM77.66,173.66a8,8,0,0,1-11.32-11.32L100.69,128,66.34,93.66A8,8,0,0,1,77.66,82.34l40,40a8,8,0,0,1,0,11.32ZM192,176H128a8,8,0,0,1,0-16h64a8,8,0,0,1,0,16Z"}))],["light",r.createElement(r.Fragment,null,r.createElement("path",{d:"M116,132.48l-72,64a6,6,0,0,1-8-9L103,128,36,68.49a6,6,0,0,1,8-9l72,64a6,6,0,0,1,0,9ZM216,186H120a6,6,0,0,0,0,12h96a6,6,0,0,0,0-12Z"}))],["regular",r.createElement(r.Fragment,null,r.createElement("path",{d:"M117.31,134l-72,64a8,8,0,1,1-10.63-12L100,128,34.69,70A8,8,0,1,1,45.32,58l72,64a8,8,0,0,1,0,12ZM216,184H120a8,8,0,0,0,0,16h96a8,8,0,0,0,0-16Z"}))],["thin",r.createElement(r.Fragment,null,r.createElement("path",{d:"M116,128a4,4,0,0,1-1.34,3l-72,64a4,4,0,1,1-5.32-6L106,128,37.34,67a4,4,0,0,1,5.32-6l72,64A4,4,0,0,1,116,128Zm100,60H120a4,4,0,0,0,0,8h96a4,4,0,0,0,0-8Z"}))]]),fs=new Map([["bold",r.createElement(r.Fragment,null,r.createElement("path",{d:"M234.38,210a123.36,123.36,0,0,0-60.78-53.23,76,76,0,1,0-91.2,0A123.3
16,123.36,0,0,0,21.62,210a12,12,0,1,0,20.77,12c18.12-31.32,50.12-50,85.61-50s67.49,18.69,85.61,50a12,12,0,0,0,20.77-12ZM76,96a52,52,0,1,1,52,52A52.06,52.06,0,0,1,76,96Z"}))],["duotone",r.createElement(r.Fragment,null,r.createElement("path",{d:"M192,96a64,64,0,1,1-64-64A64,64,0,0,1,192,96Z",opacity:"0.2"}),r.createElement("path",{d:"M230.92,212c-15.23-26.33-38.7-45.21-66.09-54.16a72,72,0,1,0-73.66,0C63.78,166.78,40.31,185.66,25.08,212a8,8,0,1,0,13.85,8c18.84-32.56,52.14-52,89.07-52s70.23,19.44,89.07,52a8,8,0,1,0,13.85-8ZM72,96a56,56,0,1,1,56,56A56.06,56.06,0,0,1,72,96Z"}))],["fill",r.createElement(r.Fragment,null,r.createElement("path",{d:"M230.93,220a8,8,0,0,1-6.93,4H32a8,8,0,0,1-6.92-12c15.23-26.33,38.7-45.21,66.09-54.16a72,72,0,1,1,73.66,0c27.39,8.95,50.86,27.83,66.09,54.16A8,8,0,0,1,230.93,220Z"}))],["light",r.createElement(r.Fragment,null,r.createElement("path",{d:"M229.19,213c-15.81-27.32-40.63-46.49-69.47-54.62a70,70,0,1,0-63.44,0C67.44,166.5,42.62,185.67,26.81,213a6,6,0,1,0,10.38,6C56.4,185.81,90.34,166,128,166s71.6,19.81,90.81,53a6,6,0,1,0,10.38-6ZM70,96a58,58,0,1,1,58,58A58.07,58.07,0,0,1,70,96Z"}))],["regular",r.createElement(r.Fragment,null,r.createElement("path",{d:"M230.92,212c-15.23-26.33-38.7-45.21-66.09-54.16a72,72,0,1,0-73.66,0C63.78,166.78,40.31,185.66,25.08,212a8,8,0,1,0,13.85,8c18.84-32.56,52.14-52,89.07-52s70.23,19.44,89.07,52a8,8,0,1,0,13.85-8ZM72,96a56,56,0,1,1,56,56A56.06,56.06,0,0,1,72,96Z"}))],["thin",r.createElement(r.Fragment,null,r.createElement("path",{d:"M227.46,214c-16.52-28.56-43-48.06-73.68-55.09a68,68,0,1,0-51.56,0c-30.64,7-57.16,26.53-73.68,55.09a4,4,0,0,0,6.92,4C55,184.19,89.62,164,128,164s73,20.19,92.54,54a4,4,0,0,0,3.46,2,3.93,3.93,0,0,0,2-.54A4,4,0,0,0,227.46,214ZM68,96a60,60,0,1,1,60,60A60.07,60.07,0,0,1,68,96Z"}))]]),ws=new Map([["bold",r.createElement(r.Fragment,null,r.createElement("path",{d:"M148.5,156.53a72,72,0,1,0-89,0,124,124,0,0,0-48.69,35.75,12,12,0,0,0,18.38,15.44C48.54,184.69,75.11,172,104,172c37,0,61.12,19.42,74.81,35.72a12,12,0,1,0,18.38-15.44A124,124,0,0,0,148.5,156.53ZM56,100a48,48,0,1,1,48,48A48.05,48.05,0,0,1,56,100Zm190.53,40-7.11,2.31,4.39,6.05a12,12,0,1,1-19.41,14.11l-4.4-6.06-4.4,6.06a12,12,0,1,1-19.41-14.11l4.39-6.05L193.47,140a12,12,0,1,1,7.41-22.83l7.12,2.31V112a12,12,0,0,1,24,0v7.48l7.12-2.31A12,12,0,1,1,246.53,140Z"}))],["duotone",r.createElement(r.Fragment,null,r.createElement("path",{d:"M168,100a60,60,0,1,1-60-60A60,60,0,0,1,168,100Z",opacity:"0.2"}),r.createElement("path",{d:"M144,157.68a68,68,0,1,0-71.9,0c-20.65,6.76-39.23,19.39-54.17,37.17a8,8,0,1,0,12.24,10.3C50.25,181.19,77.91,168,108,168s57.75,13.19,77.87,37.15a8,8,0,0,0,12.26-10.3C183.18,177.07,164.6,164.44,144,157.68ZM56,100a52,52,0,1,1,52,52A52.06,52.06,0,0,1,56,
1100Zm196.25,43.07-4.66-2.69a23.6,23.6,0,0,0,0-8.76l4.66-2.69a8,8,0,1,0-8-13.86l-4.67,2.7a23.92,23.92,0,0,0-7.58-4.39V108a8,8,0,0,0-16,0v5.38a23.92,23.92,0,0,0-7.58,4.39l-4.67-2.7a8,8,0,1,0-8,13.86l4.66,2.69a23.6,23.6,0,0,0,0,8.76l-4.66,2.69a8,8,0,0,0,8,13.86l4.67-2.7a23.92,23.92,0,0,0,7.58,4.39V164a8,8,0,0,0,16,0v-5.38a23.92,23.92,0,0,0,7.58-4.39l4.67,2.7a7.92,7.92,0,0,0,4,1.07,8,8,0,0,0,4-14.93ZM224,144a8,8,0,1,1,8-8A8,8,0,0,1,224,144Z"}))],["fill",r.createElement(r.Fragment,null,r.createElement("path",{d:"M198.13,194.85A8,8,0,0,1,192,208H24a8,8,0,0,1-6.12-13.15c14.94-17.78,33.52-30.41,54.17-37.17a68,68,0,1,1,71.9,0C164.6,164.44,183.18,177.07,198.13,194.85ZM255.18,154a8,8,0,0,1-6.94,4,7.92,7.92,0,0,1-4-1.07l-4.67-2.7a23.92,23.92,0,0,1-7.58,4.39V164a8,8,0,0,1-16,0v-5.38a23.92,23.92,0,0,1-7.58-4.39l-4.67,2.7a7.92,7.92,0,0,1-4,1.07,8,8,0,0,1-4-14.93l4.66-2.69a23.6,23.6,0,0,1,0-8.76l-4.66-2.69a8,8,0,1,1,8-13.86l4.67,2.7a23.92,23.92,0,0,1,7.58-4.39V108a8,8,0,0,1,16,0v5.38a23.92,23.92,0,0,1,7.58,4.39l4.67-2.7a8,8,0,1,1,8,13.86l-4.66,2.69a23.6,23.6,0,0,1,0,8.76l4.66,2.69A8,8,0,0,1,255.18,154ZM224,144a8,8,0,1,0-8-8A8,8,0,0,0,224,144Z"}))],["light",r.createElement(r.Fragment,null,r.createElement("path",{d:"M139,158.25a66,66,0,1,0-62,0c-22,6.23-41.88,19.16-57.61,37.89a6,6,0,0,0,9.18,7.72C49.1,179.44,77.31,166,108,166s58.9,13.44,79.41,37.86a6,6,0,1,0,9.18-7.72C180.86,177.41,161,164.48,139,158.25ZM54,100a54,54,0,1,1,54,54A54.06,54.06,0,0,1,54,100Zm197.25,44.8-5.92-3.41a22,22,0,0,0,0-10.78l5.92-3.41a6,6,0,0,0-6-10.4l-5.93,3.43a22,22,0,0,0-9.32-5.39V108a6,6,0,0,0-12,0v6.84a22,22,0,0,0-9.32,5.39l-5.93-3.43a6,6,0,0,0-6,10.4l5.92,3.41a22,22,0,0,0,0,10.78l-5.92,3.41a6,6,0,0,0,6,10.4l5.93-3.43a22,22,0,0,0,9.32,5.39V164a6,6,0,0,0,12,0v-6.84a22,22,0,0,0,9.32-5.39l5.93,3.43a6,6,0,0,0,6-10.4ZM224,146a10,10,0,1,1,10-10A10,10,0,0,1,224,146Z"}))],["regular",r.createElement(r.Fragment,null,r.createElement("path",{d:"M144,157.68a68,68,0,1,0-71.9,0c-20.65,6.76-39.23,19.39-54.17,37.17a8,8,0,1,0,12.24,10.3C50.25,181.19,77.91,168,108,168s57.75,13.19,77.87,37.15a8,8,0,0,0,12.26-10.3C183.18,177.07,164.6,164.44,144,157.68ZM56,100a52,52,0,1,1,52,52A52.06,52.06,0,0,1,56,
1100Zm196.25,43.07-4.66-2.69a23.6,23.6,0,0,0,0-8.76l4.66-2.69a8,8,0,1,0-8-13.86l-4.67,2.7a23.92,23.92,0,0,0-7.58-4.39V108a8,8,0,0,0-16,0v5.38a23.92,23.92,0,0,0-7.58,4.39l-4.67-2.7a8,8,0,1,0-8,13.86l4.66,2.69a23.6,23.6,0,0,0,0,8.76l-4.66,2.69a8,8,0,0,0,8,13.86l4.67-2.7a23.92,23.92,0,0,0,7.58,4.39V164a8,8,0,0,0,16,0v-5.38a23.92,23.92,0,0,0,7.58-4.39l4.67,2.7a7.92,7.92,0,0,0,4,1.07,8,8,0,0,0,4-14.93ZM216,136a8,8,0,1,1,8,8A8,8,0,0,1,216,136Z"}))],["thin",r.createElement(r.Fragment,null,r.createElement("path",{d:"M133.17,158.84a64,64,0,1,0-50.34,0c-23.76,5.46-45.18,18.69-61.89,38.59a4,4,0,1,0,6.12,5.14C48,177.7,76.7,164,108,164s60,13.7,80.94,38.57a4,4,0,0,0,6.12-5.14C178.35,177.53,156.93,164.3,133.17,158.84ZM52,100a56,56,0,1,1,56,56A56.06,56.06,0,0,1,52,100Zm198.25,46.54L243,142.33a19.78,19.78,0,0,0,0-12.66l7.29-4.21a4,4,0,1,0-4-6.92l-7.31,4.21A20,20,0,0,0,228,116.4V108a4,4,0,0,0-8,0v8.4a20,20,0,0,0-10.94,6.35l-7.31-4.21a4,4,0,1,0-4,6.92l7.29,4.21a19.78,19.78,0,0,0,0,12.66l-7.29,4.21a4,4,0,0,0,2,7.46,3.92,3.92,0,0,0,2-.54l7.31-4.21A20,20,0,0,0,220,155.6V164a4,4,0,0,0,8,0v-8.4a20,20,0,0,0,10.94-6.35l7.31,4.21a3.92,3.92,0,0,0,2,.54,4,4,0,0,0,2-7.46ZM224,148a12,12,0,1,1,12-12A12,12,0,0,1,224,148Z"}))]]),at=r.forwardRef((e,t)=>r.createElement(f,{ref:t,...e,weights:os}));at.displayName="AppWindowIcon";const it=r.forwardRef((e,t)=>r.createElement(f,{ref:t,...e,weights:ns}));it.displayName="ArrowDownIcon";const pt=r.forwardRef((e,t)=>r.createElement(f,{ref:t,...e,weights:as}));pt.displayName="ArrowElbowDownLeftIcon";const ct=r.forwardRef((e,t)=>r.createElement(f,{ref:t,...e,weights:is}));ct.displayName="ArrowLineUpIcon";const lt=r.forwardRef((e,t)=>r.createElement(f,{ref:t,...e,weights:ps}));lt.displayName="ArrowUpIcon";const dt=r.forwardRef((e,t)=>r.createElement(f,{ref:t,...e,weights:cs}));dt.displayName="CompassIcon";const mt=r.forwardRef((e,t)=>r.createElement(f,{ref:t,...e,weights:ls}));mt.displayName="CubeIcon";const ut=r.forwardRef((e,t)=>r.createElement(f,{ref:t,...e,weights:ds}));ut.displayName="HammerIcon";const yt=r.forwardRef((e,t)=>r.createElement(f,{ref:t,...e,weights:ms}));yt.displayName="PlayIcon";const gt=r.forwardRef((e,t)=>r.createElement(f,{ref:t,...e,weights:us}));gt.displayName="ShieldIcon";const ht=r.forwardRef((e,t)=>r.createElement(f,{ref:t,...e,weights:ys}));ht.displayName="SignInIcon";const bt=r.forwardRef((e,t)=>r.createElement(f,{ref:t,...e,weights:gs}));bt.displayName="SquareIcon";const ft=r.forwardRef((e,t)=>r.createElement(f,{ref:t,...e,weights:hs}));ft.displayName="TableIcon";const wt=r.forwardRef((e,t)=>r.createElement(f,{ref:t,...e,weights:bs}));wt.displayName="TerminalIcon";const jt=r.forwardRef((e,t)=>r.createElement(f,{ref:t,...e,weights:fs}));jt.displayName="UserIcon";const vt=r.forwardRef((e,t)=>r.createElement(f,{ref:t,...e,weights:ws}));vt.displayName="UserGearIcon";const H=e=>{const t=rr.get(L(e));return t===void 0?void 0:sr[t]},se=e=>{const t=H(e);return t?or.get(t.tab):void 0},js=e=>{var t;return((t=se(e))==null?void 0:t.groups)??[]},vs=e=>{const t=se(e);if(!t)return{};const o=t.pageIds.indexOf(L(e)),n=t.pageIds[o-1],a=t.pageIds[o+1];return{prev:n?H(n):void 0,next:a?H(a):void 0}},xs=e=>{const t=new Map;for(const o of e)t.set(L(o.id),o.data);return o=>t.get(L(o))},qs=e=>(e.split("/").pop()??e).replace(/[-_]+/g," ").replace(/^\w/,o=>o.toUpperCase()),ee=(e,t)=>{const o=t==null?void 0:t(e);return(o==null?void 0:o.sidebarTitle)||(o==null?void 0:o.title)||qs(e)},ks={[nr]:{status:301,destination:Ye}},_s=[{url:"https://api.envless.cloud",description:"Production"},{url:"https://api.envless.cloud/v1",description:"Production (versioned alias, kept for older clients)"},{url:"http://localhost:2222",description:"Local development"}],As=JSON.parse('{"securitySchemes":{"bearerAuth":{"type":"http","scheme":"bearer","description":"An Envless API key: `Authorization: Bearer ev_sk_...`. Create one in the dashboard or via POST /keys."}},"schemas":{"ApiError":{"type":"object","description":"Machine-readable failure detail. Null on success.","properties":{"code":{"type":"string","description":"Stable error code. Branch on this, never on `message`.","enum":["auth.api_key_required","auth.api_key_not_found","auth.api_key_user_missing","auth.api_key_owner_not_member","auth.scope_missing","auth.scope_ceiling_exceeded","auth.key_project_restricted","auth.product_restricted","auth.permission_denied","auth.self_mutation_forbidden","auth.step_up_required","auth.step_up_fresh_required","auth.cli_token_not_accepted","auth.two_factor_required","auth.workspace_two_factor_required","auth.two_factor_invalid","auth.two_factor_replayed","auth.two_factor_locked","auth.two_factor_not_enabled","auth.two_factor_already_enabled","request.body_must_be_json","request.body_invali
1d","request.body_too_large","request.rate_limited","request.invalid_pagination","workspace.not_found","workspace.slug_conflict","workspace.limit_reached","workspace.delete_last","workspace.delete_too_early","workspace.delete_has_projects","domain.not_configured","domain.not_found","domain.invalid","domain.taken","domain.attempt_limit","product.not_found","product.slug_conflict","product.locked","project.not_found","project.ambiguous_product","project.slug_conflict","environment.not_found","environment.slug_conflict","environment.expose_disabled","environment.expose_private_product","variable.not_found","variable.name_conflict","variable.ciphertext_invalid","variable.baseline_drifted","version.not_found","member.not_found","member.already_exists","member.self_invite","member.self_mutation","member.owner_immutable","member.owner_cannot_leave","member.seat_limit","invite.already_pending","role.owner_not_assignable","role.limit_reached","role.immutable","role.in_use","invite.not_found","invite.expired","role.not_found","role.name_conflict","key.not_found","key.limit_reached","webhook.not_found","webhook.delivery_not_found","plan.limit_reached","plan.upgrade_required","request.not_found","request.conflict","auth.unauthorized","auth.forbidden","request.invalid","server.error"]},"resource":{"type":"string","description":"The resource or scope the failure relates to."},"field":{"type":"string","description":"The request field that caused the failure."}},"required":["code"]},"Pagination":{"type":"object","properties":{"limit":{"type":"integer"},"offset":{"type":"integer"},"totalCount":{"type":"integer"},"hasMore":{"type":"boolean"}},"required":["limit","offset","totalCount","hasMore"]},"Workspace":{"type":"object","properties":{"id":{"type":"string"},"name":{"type":"string"},"slug":{"type":"string"},"icon":{"type":["string","null"]},"plan":{"type":"string","description":"The workspace billing plan."},"virtualEnvsEnabled":{"type":"boolean","description":"Whether exposed (virtual) environments are allowed in this workspace."},"customDomain":{"type":["string","null"],"description":"The active custom domain hostname, or null when none is verified."},"current":{"type":"boolean","description":"True for the workspace the API key is bound to. Every other endpoint operates inside that one."},"createdAt":{"type":"string","format":"date-time"}},"required":["id","name","slug","plan","virtualEnvsEnabled","current","createdAt"]},"CustomDomainRecord":{"type":"object","description":"A DNS record you must publish for the domain to progress.","properties":{"type":{"type":"string","description":"Record type, such as `TXT` or `CNAME`."},"name":{"type":"string","description":"Record name to create at your DNS provider."},"value":{"type":"string","description":"Record value to publish."},"note":{"type":["string","null"]}},"required":["type","name","value"]},"CustomDomain":{"type":"object","properties":{"uniqueId":{"type":"string"},"hostname":{"type":"string","description":"The canonical ASCII hostname."},"hostnameUnicode":{"type":["string","null"]},"status":{"type":"string","description":"Lifecycle state, such as `pending_challenge`, `ownership_failed`, `taken`, `active`, `plan_grace`, `removing` or `deleted`."},"records":{"type":"array","items":{"$ref":"#/components/schemas/CustomDomainRecord"}},"verificationErrors":{"type":"array","items":{"type":"string"}},"failureReason":{"type":["string","null"]},"hint":{"type":["string","null"],"description":"A neutral progress note for a domain that is still settling, such as a certificate record that Cloudflare has not issued yet. Null when there is nothing to say, and never an error."},"lastCheckedAt":{"type":["string","null"],"format":"date-time"},"retryAfterSeconds":{"type":["integer","null"],"description":"Seconds until another verify attempt is accepted. Null when you can verify now."},"canReattempt":{"type":"boolean"},"lockedByPlan":{"type":"boolean","description":"True while the workspace plan no longer includes a custom domain. The domain keeps serving until `graceEndsAt`, then it is detached."},"graceEndsAt":{"type":["string","null"],"format":"date-time","description":"When the plan grace window closes. Null unless `lockedByPlan` is true. Upgrading before this restores the domain with
1no DNS changes."},"verifiedAt":{"type":["string","null"],"format":"date-time"},"createdAt":{"type":"string","format":"date-time"}},"required":["uniqueId","hostname","status","records","canReattempt","lockedByPlan","createdAt"]},"Product":{"type":"object","properties":{"id":{"type":"string"},"name":{"type":"string"},"slug":{"type":"string"},"icon":{"type":["string","null"]},"isPrivate":{"type":"boolean"},"locked":{"type":"boolean","description":"True when the product exceeds the plan limit and is read-only until you upgrade."},"createdAt":{"type":"string","format":"date-time"},"updatedAt":{"type":["string","null"],"format":"date-time"}},"required":["id","name","slug","isPrivate","createdAt"]},"Project":{"type":"object","properties":{"id":{"type":"string"},"name":{"type":"string"},"slug":{"type":"string"},"icon":{"type":["string","null"]},"product":{"type":["object","null"],"properties":{"id":{"type":"string"},"slug":{"type":["string","null"]},"name":{"type":["string","null"]}},"required":["id"]},"createdAt":{"type":"string","format":"date-time"},"updatedAt":{"type":["string","null"],"format":"date-time"}},"required":["id","name","slug","product","createdAt"]},"Environment":{"type":"object","properties":{"id":{"type":"string"},"name":{"type":"string"},"slug":{"type":"string"},"projectId":{"type":"string"},"exposed":{"type":"boolean","description":"When true every published version is readable without an API key. Read-only here; change it in the dashboard."},"createdAt":{"type":"string","format":"date-time"},"updatedAt":{"type":["string","null"],"format":"date-time"}},"required":["id","name","slug","projectId","exposed","createdAt"]},"Variable":{"type":"object","properties":{"id":{"type":"string"},"name":{"type":"string","description":"Returned with the casing it was stored with. Live variables in one environment are unique without regard to case."},"value":{"type":["string","null"],"description":"Ciphertext. Decrypt client-side with the workspace key."},"type":{"type":"string","enum":["string","number","boolean"]},"visibility":{"type":"string","enum":["server","client"]},"required":{"type":"boolean"},"defaultValue":{"type":["string","null"],"description":"Ciphertext, encrypted with the same workspace key as `value`."},"environmentId":{"type":"string"},"createdAt":{"type":"string","format":"date-time"},"updatedAt":{"type":["string","null"],"format":"date-time"}},"required":["id","name","type","visibility","required","environmentId","createdAt"]},"Version":{"type":"object","properties":{"id":{"type":"string"},"label":{"type":"string"},"note":{"type":["string","null"]},"variableCount":{"type":"integer"},"createdBy":{"type":["object","null"],"properties":{"id":{"type":["string","null"]},"name":{"type":["string","null"]},"email":{"type":["string","null"]},"key":{"type":["object","null"],"description":"Set when the version was published by an API key. The id/name/email fields identify the key owner, not the actor.","properties":{"id":{"type":["string","null"]},"name":{"type":["string","null"]},"prefix":{"type":["string","null"]}}}}},"createdAt":{"type":"string","format":"date-time"}},"required":["id","label","variableCount","createdAt"]},"VersionEntry":{"type":"object","properties":{"id":{"type":"string"},"value":{"type":["string","null"],"description":"Ciphertext."},"defaultValue":{"type":["string","null"],"description":"Ciphertext."}},"required":["id"]},"Member":{"type":"object","properties":{"id":{"type":"string","description":"Workspace member id. This is the id used by PATCH /members/{id} and the product-access routes."},"role":{"type":["object","null"],"properties":{"id":{"type":"string"},"name":{"type":"string"},"isSystem":{"type":"boolean"}}},"user":{"type":["object","null"],"properties":{"id":{"type":"string"},"name":{"type":"string"},"email":{"type":"string"},"avatar":{"type":["string","null"]}}},"createdAt":{"type":"string","format":"date-time"}},"required":["id","role","user","createdAt"]},"Invite":{"type":"object","properties":{"id":{"type":"string"},"email":{"type":"string"},"status":{"type":"string","enum":["pending","expired"]},"role":{"type":["object","null"],"properties":{"id":{"type":"string"},"name":{"type":"string"},"isSystem":{"type":"boolean"}}},"resendCount":{"type":"integer"}
1,"lastResendAt":{"type":["string","null"],"format":"date-time"},"expiresAt":{"type":["string","null"],"format":"date-time"},"sentAt":{"type":"string","format":"date-time"}},"required":["id","email","status","sentAt"]},"Role":{"type":"object","properties":{"id":{"type":"string"},"name":{"type":"string"},"description":{"type":["string","null"]},"isSystem":{"type":"boolean"},"systemKey":{"type":["string","null"]},"permissions":{"type":"array","items":{"type":"string"}},"createdAt":{"type":"string","format":"date-time"},"updatedAt":{"type":["string","null"],"format":"date-time"}},"required":["id","name","isSystem","permissions","createdAt"]},"KeyScopes":{"type":"object","description":"Per-resource access level for an API key.","propertyNames":{"enum":["workspace","products","product-access","projects","environments","variables","versions","members","roles","keys","webhooks"]},"additionalProperties":{"type":"string","enum":["none","read","write"]}},"Key":{"type":"object","properties":{"id":{"type":"string"},"name":{"type":"string"},"prefix":{"type":["string","null"],"description":"The non-secret leading segment, for identifying a key in a list."},"scopes":{"$ref":"#/components/schemas/KeyScopes"},"projectIds":{"type":"array","items":{"type":"string"},"description":"Projects this key is fenced to. An empty array means unrestricted."},"active":{"type":"boolean"},"lastUsedAt":{"type":["string","null"],"format":"date-time"},"keyRolls":{"type":"integer"},"createdAt":{"type":"string","format":"date-time"},"lastRolledAt":{"type":["string","null"],"format":"date-time"}},"required":["id","name","scopes","projectIds","active","createdAt"]},"Webhook":{"type":"object","properties":{"id":{"type":"string"},"name":{"type":["string","null"]},"url":{"type":"string","format":"uri"},"description":{"type":["string","null"]},"eventTypes":{"type":"array","items":{"type":"string"}},"enabled":{"type":"boolean"},"secretLastFour":{"type":["string","null"],"description":"Last four characters of the signing secret. The full secret is returned only on create and rotate."},"lastSuccessAt":{"type":["string","null"],"format":"date-time"},"lastFailureAt":{"type":["string","null"],"format":"date-time"},"createdAt":{"type":"string","format":"date-time"},"updatedAt":{"type":["string","null"],"format":"date-time"}},"required":["id","url","eventTypes","enabled","createdAt"]},"WebhookDelivery":{"type":"object","properties":{"id":{"type":"string"},"webhookId":{"type":"string"},"eventId":{"type":"string"},"eventType":{"type":"string"},"status":{"type":"string"},"attempts":{"type":"integer"},"responseStatus":{"type":["integer","null"]},"error":{"type":["string","null"]},"lastAttemptAt":{"type":["string","null"],"format":"date-time"},"nextAttemptAt":{"type":["string","null"],"format":"date-time"},"succeededAt":{"type":["string","null"],"format":"date-time"},"failedAt":{"type":["string","null"],"format":"date-time"},"createdAt":{"type":"string","format":"date-time"}},"required":["id","webhookId","eventId","eventType","status","createdAt"]}}}'),Es=JSON.parse('{"/invites":{"get":{"operationId":"listInvites","tags":["Invites"],"summary":"List pending invites","description":"Lists invitations that have been sent and not yet accepted or revoked. Accepted invites disappear from this list and show up in GET /members; revoked ones are soft-deleted and never come back.\\n\\nInvites that have passed their 3-day expiry are still listed, with `status: \\"expired\\"`. `status` is computed from `expiresAt` at read time, so it flips without any write. An expired invite cannot be salvaged by resending - revoke it and send a fresh one with POST /members. Expired invites stay listed for 24 hours; after that a background sweep soft-deletes them and they drop off this list.\\n\\n`search` matches the invited email address only. Sorting is newest-sent first and is not configurable. `role` is null when the role behind the invite has since been deleted.","responses":{"200":{"description":"List pending invites succeeded.","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","const":true},"code":{"type":"integer","example":200},"message":{"type":"string","example":"OK"},"error":{"type":"null"},"data":{"type":"object","properties":{"invites":{"type":"array","items":{"$ref":"#/components/schemas/Invite"}},"pagination":{"$ref":"#/components/schemas/Pagination"}},"required":["invites","pagination"]},"_req":{"type":"object","properties":{"reqId":{"type":"string"},"resTime":{"type":["integer","null"]}}}},"required":["success","code","message","error","data"]}}}}
1,"400":{"description":"`request.invalid_pagination` - `limit` or `offset` is not a whole number, or `limit` is outside 1 to 100; `error.field` names the offending parameter.","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","const":false},"code":{"type":"integer","example":400},"message":{"type":"string","example":"Something went wrong."},"error":{"$ref":"#/components/schemas/ApiError"},"data":{"type":"null"},"_req":{"type":"object","properties":{"reqId":{"type":"string"},"resTime":{"type":["integer","null"]}}}},"required":["success","code","message","error","data"]}}}},"401":{"description":"Missing, malformed, revoked or non-member API key (`auth.api_key_*`).","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","const":false},"code":{"type":"integer","example":400},"message":{"type":"string","example":"Something went wrong."},"error":{"$ref":"#/components/schemas/ApiError"},"data":{"type":"null"},"_req":{"type":"object","properties":{"reqId":{"type":"string"},"resTime":{"type":["integer","null"]}}}},"required":["success","code","message","error","data"]}}}},"500":{"description":"Unexpected server error (`server.error`).","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","const":false},"code":{"type":"integer","example":400},"message":{"type":"string","example":"Something went wrong."},"error":{"$ref":"#/components/schemas/ApiError"},"data":{"type":"null"},"_req":{"type":"object","properties":{"reqId":{"type":"string"},"resTime":{"type":["integer","null"]}}}},"required":["success","code","message","error","data"]}}}}},"x-envless-scopes":["members:read"],"parameters":[{"name":"limit","in":"query","schema":{"type":"integer","minimum":1,"maximum":100,"default":25},"description":"Rows per page, 1 to 100."},{"name":"offset","in":"query","schema":{"type":"integer","minimum":0,"default":0},"description":"Rows to skip."},{"name":"search","in":"query","schema":{"type":"string"},"description":"Case-insensitive substring match on the invited email address. Does not search role names."}]}},"/invites/{id}":{"delete":{"operationId":"revokeInvite","tags":["Invites"],"summary":"Revoke an invite","description":"Revokes a pending invitation. The invite is soft-deleted and the link in the email stops working immediately; the recipient is not notified. Revoking also frees the seat it was holding against the plan limit.\\n\\nThere is no un-revoke. To invite the address again, call POST /members, which will now succeed because no pending invite exists. Emits `member.invite_revoked`.","responses":{"200":{"description":"Revoke an invite succeeded.","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","const":true},"code":{"type":"integer","example":200},"message":{"type":"string","example":"OK"},"error":{"type":"null"},"data":{"type":"object","properties":{"id":{"type":"string"},"email":{"type":"string","description":"Address the revoked invite was sent to."}},"required":["id","email"]},"_req":{"type":"object","properties":{"reqId":{"type":"string"},"resTime":{"type":["integer","null"]}}}},"required":["success","code","message","error","data"]}}}},"401":{"description":"Missing, malformed, revoked or non-member API key (`auth.api_key_*`).","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","const":false},"code":{"type":"integer","example":400},"message":{"type":"string","example":"Something went wrong."},"error":{"$ref":"#/components/schemas/ApiError"},"data":{"type":"null"},"_req":{"type":"object","properties":{"reqId":{"type":"string"},"resTime":{"type":["integer","null"]}}}},"required":["success","code","message","error","data"]}}}},"404":{"description":"`invite.not_found` - no pending invite with that id exists in this workspace, including when it was already revoked or already accepted.","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","const":false},"code":{"type":"integer","example":400},"message":{"type":"string","example":"Something went wrong."},"error":{"$ref":"#/components/schemas/ApiError"},"data":{"type":"null"},"_req":{"type":"object","properties":{"reqId":{"type":"string"},"resTime":{"type":["integer","null"]}}}},"required":["success","code","message","error","data"]}}}},"500":{"description":"Unexpected server error (`server.error`).","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","const":false},"code":{"type":"integer","example":400},"message":{"type":"string","example":"Something went wrong."},"error":{"$ref":"#/components/schemas/ApiError"},"data":{"type":"null"},"_req":{"type":"object","properties":{"reqId":{"type":"string"},"resTime":{"type":["integer","null"]}}}},"required":["success","code","message","error","data"]}}}}},"x-envless-scopes":["members:write"],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"},"description":"Invite id from GET /invites. Ids only, no email address or slug form."}]}},"/invites/{id}/resend":{"post":{"operationId":"resendInvite","tags":["Invites"],"summary":"Resend an invite email","description":"Sends the invitation email again for an existing pending invite. Takes no request body and returns 200, not 201 - nothing new is created. The invite
1keeps its original id, token and `expiresAt`; resending does not extend the 3-day expiry, so an invite that has run out cannot be revived by resending it.\\n\\nOnce an invite expires the endpoint returns 409 `invite.expired` - revoke it and POST /members again to send a fresh link.\\n\\nThe returned Invite always has `role: null` on this endpoint, because the controller does not re-resolve the role. Read the role from GET /invites if you need it. `resendCount` counts operator resends only. `lastResendAt` is the last time any email went out for this invite, so it also moves when the automatic expiry reminder is sent 24 hours before `expiresAt`. Emits `member.invite_resent`.","responses":{"200":{"description":"Resend an invite email succeeded.","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","const":true},"code":{"type":"integer","example":200},"message":{"type":"string","example":"OK"},"error":{"type":"null"},"data":{"$ref":"#/components/schemas/Invite"},"_req":{"type":"object","properties":{"reqId":{"type":"string"},"resTime":{"type":["integer","null"]}}}},"required":["success","code","message","error","data"]}}}},"401":{"description":"Missing, malformed, revoked or non-member API key (`auth.api_key_*`).","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","const":false},"code":{"type":"integer","example":400},"message":{"type":"string","example":"Something went wrong."},"error":{"$ref":"#/components/schemas/ApiError"},"data":{"type":"null"},"_req":{"type":"object","properties":{"reqId":{"type":"string"},"resTime":{"type":["integer","null"]}}}},"required":["success","code","message","error","data"]}}}},"404":{"description":"`invite.not_found` - no pending invite with that id exists in this workspace; a 404 with `workspace.not_found` is returned instead if the workspace itself has been soft-deleted.","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","const":false},"code":{"type":"integer","example":400},"message":{"type":"string","example":"Something went wrong."},"error":{"$ref":"#/components/schemas/ApiError"},"data":{"type":"null"},"_req":{"type":"object","properties":{"reqId":{"type":"string"},"resTime":{"type":["integer","null"]}}}},"required":["success","code","message","error","data"]}}}},"409":{"description":"`invite.expired` - the invite is past its `expiresAt`; resending cannot extend it, so revoke it and invite the address again.","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","const":false},"code":{"type":"integer","example":400},"message":{"type":"string","example":"Something went wrong."},"error":{"$ref":"#/components/schemas/ApiError"},"data":{"type":"null"},"_req":{"type":"object","properties":{"reqId":{"type":"string"},"resTime":{"type":["integer","null"]}}}},"required":["success","code","message","error","data"]}}}},"500":{"description":"`server.error` - the email could not be sent; the resend bookkeeping is rolled back, so the invite is left exactly as it was.","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","const":false},"code":{"type":"integer","example":400},"message":{"type":"string","example":"Something went wrong."},"error":{"$ref":"#/components/schemas/ApiError"},"data":{"type":"null"},"_req":{"type":"object","properties":{"reqId":{"type":"string"},"resTime":{"type":["integer","null"]}}}},"required":["success","code","message","error","data"]}}}}},"x-envless-scopes":["members:write"],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"},"description":"Invite id from GET /invites."}]}},"/keys":{"get":{"operationId":"listKeys","tags":["API keys"],"summary":"List API keys","description":"Lists the API keys in the current workspace. Secrets and secret hashes are never returned by this or any read endpoint - only `prefix`, the non-secret leading 12 characters, which is what you match against when you need to identify a key you already hold.\\n\\nRevoked keys are soft-deleted and are excluded from this list permanently.\\n\\nOrdering defaults to `name`, **A to Z**. `order=asc` and `order=desc` switch to `createdAt`, oldest or newest first; any other value, including a typo, silently falls back to name order.\\n\\n`search` matches `name` and `prefix` only. Pagination is applied after the workspace\'s keys are loaded, so `totalCount` always reflects the full filtered set.\\n\\nUnlike the webhook endpoints, the key endpoints are not refused for project-restr
1icted keys: a key fenced to specific projects can still read the workspace\'s key list. It just cannot mint or edit a key outside its own project fence.","responses":{"200":{"description":"List API keys succeeded.","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","const":true},"code":{"type":"integer","example":200},"message":{"type":"string","example":"OK"},"error":{"type":"null"},"data":{"type":"object","properties":{"keys":{"type":"array","items":{"$ref":"#/components/schemas/Key"}},"pagination":{"$ref":"#/components/schemas/Pagination"}},"required":["keys","pagination"]},"_req":{"type":"object","properties":{"reqId":{"type":"string"},"resTime":{"type":["integer","null"]}}}},"required":["success","code","message","error","data"]}}}},"400":{"description":"`request.invalid_pagination` - `limit` or `offset` is not a whole number, or `limit` is outside 1-100.","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","const":false},"code":{"type":"integer","example":400},"message":{"type":"string","example":"Something went wrong."},"error":{"$ref":"#/components/schemas/ApiError"},"data":{"type":"null"},"_req":{"type":"object","properties":{"reqId":{"type":"string"},"resTime":{"type":["integer","null"]}}}},"required":["success","code","message","error","data"]}}}},"401":{"description":"Missing, malformed, revoked or non-member API key (`auth.api_key_*`).","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","const":false},"code":{"type":"integer","example":400},"message":{"type":"string","example":"Something went wrong."},"error":{"$ref":"#/components/schemas/ApiError"},"data":{"type":"null"},"_req":{"type":"object","properties":{"reqId":{"type":"string"},"resTime":{"type":["integer","null"]}}}},"required":["success","code","message","error","data"]}}}},"500":{"description":"Unexpected server error (`server.error`).","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","const":false},"code":{"type":"integer","example":400},"message":{"type":"string","example":"Something went wrong."},"error":{"$ref":"#/components/schemas/ApiError"},"data":{"type":"null"},"_req":{"type":"object","properties":{"reqId":{"type":"string"},"resTime":{"type":["integer","null"]}}}},"required":["success","code","message","error","data"]}}}}},"x-envless-scopes":["keys:read"],"parameters":[{"name":"limit","in":"query","required":false,"schema":{"type":"integer","minimum":1,"maximum":100,"default":25},"description":"Page size. Must be a whole number between 1 and 100."},{"name":"offset","in":"query","required":false,"schema":{"type":"integer","minimum":0,"default":0},"description":"Number of keys to skip. Must be a whole number of 0 or greater."},{"name":"search","in":"query","required":false,"schema":{"type":"string"},"description":"Case-insensitive substring match against the key `name` and `prefix`. Never matches the secret."},{"name":"order","in":"query","required":false,"schema":{"type":"string","enum":["name","asc","desc"],"default":"name"},"description":"`asc` and `desc` sort oldest and newest first by `createdAt`. Anything else, including omitting it, sorts by `name` A to Z."}]},"post":{"operationId":"createKey","tags":["API keys"],"summary":"Create an API key","description":"Mints a new API key for the workspace and returns the plaintext secret.\\n\\n**`data.secret` is returned exactly once, on this response, and is unrecoverable.** It is not stored in plaintext - only a hash is kept - so no endpoint, dashboard screen or support request can ever show it again. Write it to your secret store before you read anything else off the response. If you lose it, the only remedy is to create a replacement key and delete this one.\\n\\nThe secret looks like `ev_sk_<base64url>`. `prefix` on the returned object is its first 12 characters and is safe to log.\\n\\n**Scopes are subject to two independent reductions, in this order.**\\n\\n1. *Ceiling.* A key can never mint a key more powerful than itself. If any requested `resource:level` outranks what the calling key holds, the whole request is rejected with 403 `auth.scope_ceiling_exceeded` and `error.resource` lists the offending `resource:level` pairs. Nothing is created.\\n2. *Clamp.* Whatever survives the ceiling is then clamped down to the permissions of the **key owner\'s workspace role** - the human who owns the calling key, not the target key. This clamp is silent: a requested `write` becomes `read` if the owner can read but not write that resource, and becomes `none` if they cannot even read it. **Always read `data.scopes` off the response** rather than assuming you got what you asked for; the created key may hold strictly less.\\n\\nOmitting `scopes` entirely is legal and produces a key with every resource at `none` - it authenticates but can call nothing except `GET /me`.\\n\\n`projectIds` fences the key to
1specific projects and takes project **`id` values (UUIDv7)**, not slugs. An empty array or an omitted field means workspace-wide. If the *calling* key is itself project-restricted, `projectIds` is mandatory and must be a non-empty subset of the caller\'s own projects, otherwise you get 403 `auth.key_project_restricted`.\\n\\n**Rotation is deliberately not exposed on the public API.** There is no `POST /keys/{id}/rotate`. To roll a credential: create a replacement key with the scopes you want, deploy it everywhere, confirm the old key\'s `lastUsedAt` has stopped advancing, then `DELETE /keys/{old_id}`. Doing it in that order gives you the overlap window that an in-place rotate would not.\\n\\nA workspace is capped at 100 keys, counting only live ones.\\n\\nScope resources and levels are enumerated on the request schema below. Every resource accepts `none`, `read` or `write`; `write` implies `read`.","responses":{"201":{"description":"Create an API key succeeded.","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","const":true},"code":{"type":"integer","example":200},"message":{"type":"string","example":"OK"},"error":{"type":"null"},"data":{"allOf":[{"$ref":"#/components/schemas/Key"},{"type":"object","properties":{"secret":{"type":"string","description":"The plaintext API key, e.g. `ev_sk_...`. Returned on this response only, never again, and unrecoverable if lost. Store it before doing anything else.","writeOnly":false}},"required":["secret"]}
1]},"_req":{"type":"object","properties":{"reqId":{"type":"string"},"resTime":{"type":["integer","null"]}}}},"required":["success","code","message","error","data"]}}}},"400":{"description":"`request.body_invalid` - `name` is missing, is not a string, or is outside 4-34 characters (`error.field` is `name`); or `scopes` names an unknown resource, uses a level other than none/read/write, or `projectIds` is not an array of UUIDv7 project ids.","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","const":false},"code":{"type":"integer","example":400},"message":{"type":"string","example":"Something went wrong."},"error":{"$ref":"#/components/schemas/ApiError"},"data":{"type":"null"},"_req":{"type":"object","properties":{"reqId":{"type":"string"},"resTime":{"type":["integer","null"]}}}},"required":["success","code","message","error","data"]}}}},"401":{"description":"`auth.api_key_user_missing` - the owner of the calling key could not be resolved, so there is no role to clamp the new key\'s scopes against.","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","const":false},"code":{"type":"integer","example":400},"message":{"type":"string","example":"Something went wrong."},"error":{"$ref":"#/components/schemas/ApiError"},"data":{"type":"null"},"_req":{"type":"object","properties":{"reqId":{"type":"string"},"resTime":{"type":["integer","null"]}}}},"required":["success","code","message","error","data"]}}}},"403":{"description":"`auth.key_project_restricted` - the calling key is fenced to projects and `projectIds` is missing, empty, or contains a project outside that fence.","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","const":false},"code":{"type":"integer","example":400},"message":{"type":"string","example":"Something went wrong."},"error":{"$ref":"#/components/schemas/ApiError"},"data":{"type":"null"},"_req":{"type":"object","properties":{"reqId":{"type":"string"},"resTime":{"type":["integer","null"]}}}},"required":["success","code","message","error","data"]}}}},"409":{"description":"`key.limit_reached` - the workspace already has 100 live keys.","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","const":false},"code":{"type":"integer","example":400},"message":{"type":"string","example":"Something went wrong."},"error":{"$ref":"#/components/schemas/ApiError"},"data":{"type":"null"},"_req":{"type":"object","properties":{"reqId":{"type":"string"},"resTime":{"type":["integer","null"]}}}},"required":["success","code","message","error","data"]}}}},"500":{"description":"Unexpected server error (`server.error`).","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","const":false},"code":{"type":"integer","example":400},"message":{"type":"string","example":"Something went wrong."},"error":{"$ref":"#/components/schemas/ApiError"},"data":{"type":"null"},"_req":{"type":"object","properties":{"reqId":{"type":"string"},"resTime":{"type":["integer","null"]}}}},"required":["success","code","message","error","data"]}}}}},"x-envless-scopes":["keys:write"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"name":{"type":"string","minLength":4,"maxLength":34,"description":"Human label for the key. Required. 4 to 34 characters.","example":"Billing"},"scopes":{"type":"object","description":"Per-resource access level. Unknown resource names are rejected with 400. Any resource you omit defaults to `none`. Subject to the ceiling check and then the owner-role clamp described above.","propertyNames":{"enum":["workspace","products","product-access","projects","environments","variables","versions","members","roles","keys","webhooks"]},"additionalProperties":{"type":"string","enum":["none","read","write"]},"example":{"projects":"read","environments":"read","variables":"write"}},"projectIds":{"type":"array","items":{"type":"string","format":"uuid"},"description":"Project `id` values (UUIDv7) to fence this key to. Slugs are rejected. Omit or send `[]` for a workspace-wide key. Duplicates are de-duplicated.","example":[]}},"required":["name"]}}}}}},"/keys/{id}":{"get":{"operationId":"getKey","tags":["API keys"],"summary":"Get an API key","description":"Returns a single API key by its `id`. Never returns the secret or its hash - if you have lost the secret, the key is unrecoverable and must be replaced (create a new key, then delete this one).\\n\\nUse this to check `active`, the effective `scopes` after clamping, the `projectIds` fence, and `lastUsedAt` before revoking a key you think is unused.\\n\\nA key soft-deleted by `DELETE /keys/{id}` returns 404 here.","responses":{"200":{"description":"Get an API key succeeded.","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","const":true},"code":{"type":"integer","example":200},"message":{"type":"string","example":"OK"},"error":{"type":"null"},"data":{"$ref":"#/components/schemas/Key"},"_req":{"type":"object","properties":{"reqId":{"type":"string"},"resTime":{"type":["integer","null"]}}}},"required":["success","code","message","error","data"]}}}},"401":{"description":"Missing, malformed, revoked or non-member API key (`auth.api_key_*`).","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","const":false},"code":{"type":"integer","example":400},"message":{"type":"string","example":"Something went wrong."},"error":{"$ref":"#/components/schemas/ApiError"},"data":{"type":"null"},"_req":{"type":"object","properties":{"reqId":{"type":"string"},"resTime":{"type":["integer","null"]}}}},"required":["success","code","message","error","data"]}}}}
1,"404":{"description":"`key.not_found` - no live key with that id exists in this workspace, or it has already been revoked.","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","const":false},"code":{"type":"integer","example":400},"message":{"type":"string","example":"Something went wrong."},"error":{"$ref":"#/components/schemas/ApiError"},"data":{"type":"null"},"_req":{"type":"object","properties":{"reqId":{"type":"string"},"resTime":{"type":["integer","null"]}}}},"required":["success","code","message","error","data"]}}}},"500":{"description":"Unexpected server error (`server.error`).","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","const":false},"code":{"type":"integer","example":400},"message":{"type":"string","example":"Something went wrong."},"error":{"$ref":"#/components/schemas/ApiError"},"data":{"type":"null"},"_req":{"type":"object","properties":{"reqId":{"type":"string"},"resTime":{"type":["integer","null"]}}}},"required":["success","code","message","error","data"]}}}}},"x-envless-scopes":["keys:read"],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"},"description":"The key\'s `id` (UUIDv7), as returned by `GET /keys` or `POST /keys`. This is not the `prefix` and not the secret; there is no slug form for keys."}]},"patch":{"operationId":"updateKey","tags":["API keys"],"summary":"Update an API key","description":"Updates a key\'s label, enabled state, scopes or project fence. Send only the fields you want to change.\\n\\n**`scopes` merges, it does not replace.** The map you send is layered on top of the key\'s stored scopes, so omitting a resource leaves it exactly as it was. To take a permission away you must explicitly send that resource with the level `none` - `{\\"scopes\\": {\\"variables\\": \\"none\\"}}`. Sending `{\\"scopes\\": {}}` changes nothing. `projectIds`, by contrast, replaces wholesale: whatever array you send becomes the fence, and `[]` removes the fence entirely.\\n\\nThe same two reductions as `POST /keys` apply to the merged result: the ceiling check first (403 `auth.scope_ceiling_exceeded` if you ask for more than the calling key holds), then a silent clamp down to the **calling key owner\'s** workspace role. Read `data.scopes` back off the response.\\n\\n**A key cannot re-scope, re-fence or disable itself.** If `id` is the key making the request and the body contains `scopes`, `projectIds`, or `active: false`, the request fails with 409 `auth.self_mutation_forbidden`. Renaming yourself is allowed, and so is `active: true` on yourself, because neither can lock you out. Use a second key, or the dashboard.\\n\\nOrdering gotcha: the scope-ceiling and project-subset checks run *before* the key is looked up, so a request with an over-privileged `scopes` map against an id that does not exist returns 403, not 404. Fix the scopes first, then trust the 404.\\n\\nUnrecognised field types are ignored rather than rejected: a non-string `name` or a non-boolean `active` is dropped silently. A PATCH that ends up touching nothing succeeds with 200 and the unchanged key.\\n\\nKeys are plan-independent: the API, SDK and CLI are included on every plan, including Free, so a plan change never switches a key off and `active: true` works on every tier.\\n\\nThere is no way to change a key\'s secret here. Rotation is not exposed - create a replacement key and delete this one.","responses":{"200":{"description":"Update an API key succeeded.","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","const":true},"code":{"type":"integer","example":200},"message":{"type":"string","example":"OK"},"error":{"type":"null"},"data":{"$ref":"#/components/schemas/Key"},"_req":{"type":"object","properties":{"reqId":{"type":"string"},"resTime":{"type":["integer","null"]}}}},"required":["success","code","message","error","data"]}}}}
1,"400":{"description":"`request.body_invalid` - `scopes` names an unknown resource or uses a level other than none/read/write, `projectIds` is not an array of UUIDv7 project ids, or `name` is outside 4-34 characters.","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","const":false},"code":{"type":"integer","example":400},"message":{"type":"string","example":"Something went wrong."},"error":{"$ref":"#/components/schemas/ApiError"},"data":{"type":"null"},"_req":{"type":"object","properties":{"reqId":{"type":"string"},"resTime":{"type":["integer","null"]}}}},"required":["success","code","message","error","data"]}}}},"401":{"description":"Missing, malformed, revoked or non-member API key (`auth.api_key_*`).","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","const":false},"code":{"type":"integer","example":400},"message":{"type":"string","example":"Something went wrong."},"error":{"$ref":"#/components/schemas/ApiError"},"data":{"type":"null"},"_req":{"type":"object","properties":{"reqId":{"type":"string"},"resTime":{"type":["integer","null"]}}}},"required":["success","code","message","error","data"]}}}},"403":{"description":"`auth.key_project_restricted` - the calling key is fenced to projects and `projectIds` is missing, empty, or contains a project outside that fence.","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","const":false},"code":{"type":"integer","example":400},"message":{"type":"string","example":"Something went wrong."},"error":{"$ref":"#/components/schemas/ApiError"},"data":{"type":"null"},"_req":{"type":"object","properties":{"reqId":{"type":"string"},"resTime":{"type":["integer","null"]}}}},"required":["success","code","message","error","data"]}}}},"404":{"description":"`key.not_found` - no live key with that id exists in this workspace.","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","const":false},"code":{"type":"integer","example":400},"message":{"type":"string","example":"Something went wrong."},"error":{"$ref":"#/components/schemas/ApiError"},"data":{"type":"null"},"_req":{"type":"object","properties":{"reqId":{"type":"string"},"resTime":{"type":["integer","null"]}}}},"required":["success","code","message","error","data"]}}}},"409":{"description":"`auth.self_mutation_forbidden` - the key is patching itself with `scopes`, `projectIds`, or `active: false`.","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","const":false},"code":{"type":"integer","example":400},"message":{"type":"string","example":"Something went wrong."},"error":{"$ref":"#/components/schemas/ApiError"},"data":{"type":"null"},"_req":{"type":"object","properties":{"reqId":{"type":"string"},"resTime":{"type":["integer","null"]}}}},"required":["success","code","message","error","data"]}}}},"500":{"description":"Unexpected server error (`server.error`).","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","const":false},"code":{"type":"integer","example":400},"message":{"type":"string","example":"Something went wrong."},"error":{"$ref":"#/components/schemas/ApiError"},"data":{"type":"null"},"_req":{"type":"object","properties":{"reqId":{"type":"string"},"resTime":{"type":["integer","null"]}}}},"required":["success","code","message","error","data"]}}}}},"x-envless-scopes":["keys:write"],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"},"description":"The key\'s `id` (UUIDv7). Not the `prefix`, not the secret; keys have no slug form."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"name":{"type":"string","minLength":4,"maxLength":34,"description":"New label. 4 to 34 characters. Non-string values are ignored.","example":"Billing"},"active":{"type":"boolean","description":"`false` disables the key immediately; every subsequent request with it gets 401. `true` re-enables it. A key may not send `false` for itself. Non-boolean values are ignored.","example":true},"scopes":{"type":"object","description":"Partial scope map, MERGED onto the key\'s current scopes. Omitted resources are left untouched - send an explicit `none` to revoke. Unknown resource names are rejected with 400.","propertyNames":{"enum":["workspace","products","product-access","projects","environments","variables","versions","members","roles","keys","webhooks"]},"additionalProperties":{"type":"string","enum":["none","read","write"]},"example":{"variables":"read","versions":"read"}},"projectIds":{"type":"array","items":{"type":"string","format":"uuid"},"description":"REPLACES the project fence with exactly this set of project `id` values (UUIDv7). `[]` removes the fence and makes the key workspace-wide.","example":[]}}}}}}},"delete":{"operationId":"deleteKey","tags":["API keys"],"summary":"Revoke an API key","description":"Revokes a key. The revocation is immediate: the next request presenting that secret gets 401. The row is soft-deleted, so the key disappears from `GET /keys` and returns 404 from `GET /keys/{id}` afterwards, and the id is never reused.\\n\\nThis is irreversible - there is no undelete, and the secret was never recoverable in the first place. If you need continuity, create the replacement key *first*, deploy it, watch `lastUsedAt` on the old key stop advancing, and only then revoke.\\n\\n**A key cannot revoke itself**: passing the id of the key making the request fails with 409 `auth.self_mutation_forbidden`. Use a second key, or revoke from the dashboard.\\n\\nThe response body echoes the revoked key\'s `id` and `name`. It does not include a `deleted` boolean - that shape belongs to `DELETE /webhooks/{id}`.\\n\\nA `key.deleted` event is emitted to any webhook endpoint subscribed to it.","responses":{"200":{"description":"Revoke an API key succeeded.","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","const":true},"code":{"type":"integer","example":200},"message":{"type":"string","example":"OK"},"error":{"type":"null"},"data":{"type":"object","properties":{"id":{"type":"string","description":"The revoked key\'s id."},"name":{"type":"string","description":"The revoked key\'s label, echoed back for audit logs."}},"required":["id","name"]},"_req":{"type":"object","properties":{"reqId":{"type":"string"},"resTime":{"type":["integer","null"]}}}},"required":["success","code","message","error","data"]}}}},"401":{"description":"Missing, malformed, revoked or non-member API key (`auth.api_key_*`).","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","const":false},"code":{"type":"integer","example":400},"message":{"type":"string","example":"Something went wrong."},"error":{"$ref":"#/components/schemas/ApiError"},"data":{"type":"null"},"_req":{"type":"object","properties":{"reqId":{"type":"string"},"resTime":{"type":["integer","null"]}}}},"required":["success","code","message","error","data"]}}}},"403":{"description":"`auth.key_project_restricted` - the calling key is fenced to specific projects;
1 key management is workspace-wide and has no project dimension.","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","const":false},"code":{"type":"integer","example":400},"message":{"type":"string","example":"Something went wrong."},"error":{"$ref":"#/components/schemas/ApiError"},"data":{"type":"null"},"_req":{"type":"object","properties":{"reqId":{"type":"string"},"resTime":{"type":["integer","null"]}}}},"required":["success","code","message","error","data"]}}}},"404":{"description":"`key.not_found` - no live key with that id exists in this workspace, or it was already revoked.","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","const":false},"code":{"type":"integer","example":400},"message":{"type":"string","example":"Something went wrong."},"error":{"$ref":"#/components/schemas/ApiError"},"data":{"type":"null"},"_req":{"type":"object","properties":{"reqId":{"type":"string"},"resTime":{"type":["integer","null"]}}}},"required":["success","code","message","error","data"]}}}},"409":{"description":"`auth.self_mutation_forbidden` - the key is trying to revoke itself.","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","const":false},"code":{"type":"integer","example":400},"message":{"type":"string","example":"Something went wrong."},"error":{"$ref":"#/components/schemas/ApiError"},"data":{"type":"null"},"_req":{"type":"object","properties":{"reqId":{"type":"string"},"resTime":{"type":["integer","null"]}}}},"required":["success","code","message","error","data"]}}}},"500":{"description":"Unexpected server error (`server.error`).","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","const":false},"code":{"type":"integer","example":400},"message":{"type":"string","example":"Something went wrong."},"error":{"$ref":"#/components/schemas/ApiError"},"data":{"type":"null"},"_req":{"type":"object","properties":{"reqId":{"type":"string"},"resTime":{"type":["integer","null"]}}}},"required":["success","code","message","error","data"]}}}}},"x-envless-scopes":["keys:write"],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"},"description":"The key\'s `id` (UUIDv7). Keys have no slug form."}]}},"/me":{"get":{"operationId":"getMe","tags":["Account"],"summary":"Get the calling identity","description":"Returns the user the API key belongs to, the workspace the key is bound to, and a summary of the key itself. This is the only public endpoint with no scope requirement, so it works with any valid key regardless of its scopes - use it as a cheap credential check and to discover `workspaceId` at startup.\\n\\nA key is permanently bound to one workspace at creation time. There is no way to switch workspaces on a request; to reach a second workspace, create a key inside it. `key.name` and `key.createdAt` are read from the key row and come back `null` in the rare case the row cannot be re-read.","responses":{"200":{"description":"Get the calling identity succeeded.","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","const":true},"code":{"type":"integer","example":200},"message":{"type":"string","example":"OK"},"error":{"type":"null"},"data":{"type":"object","properties":{"user":{"type":"object","description":"The user who owns the API key. All writes are attributed to this user in the audit trail and in webhook `actor` payloads.","properties":{"id":{"type":"string"},"name":{"type":"string"},"email":{"type":"string"},"avatar":{"type":["string","null"]}},"required":["id","name","email"]},"workspaceId":{"type":["string","null"],"description":"The workspace this key is bound to. Every other endpoint operates inside it implicitly."},"key":{"type":["object","null"],"description":"The key used for this request. Null only if the request was authenticated by something other than an API key.","properties":{"id":{"type":"string"},"name":{"type":["string","null"]},"createdAt":{"type":["string","null"],"format":"date-time"}},"required":["id"]}},"required":["user","workspaceId","key"]},"_req":{"type":"object","properties":{"reqId":{"type":"string"},"resTime":{"type":["integer","null"]}}}},"required":["success","code","message","error","data"]}}}},"401":{"description":"Missing, malformed, revoked or non-member API key (`auth.api_key_*`).","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","const":false},"code":{"type":"integer","example":400},"message":{"type":"string","example":"Something went wrong."},"error":{"$ref":"#/components/schemas/ApiError"},"data":{"type":"null"},"_req":{"type":"object","properties":{"reqId":{"type":"string"},"resTime":{"type":["integer","null"]}}}},"required":["success","code","message","error","data"]}}}},"500":{"description":"Unexpected server error (`server.error`).","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","const":false},"code":{"type":"integer","example":400},"message":{"type":"string","example":"Something went wrong."},"error":{"$ref":"#/components/schemas/ApiError"},"data":{"type":"null"},"_req":{"type":"object","properties":{"reqId":{"type":"string"},"resTime":{"type":["integer","null"]}}}},"required":["success","code","message","error","data"]}}}}}}},"/members":{"get":{"operationId":"listMembers","tags":["Members"],"summary":"List workspace members","description":"Lists everyone who has accepted membership of the workspace. Pending invites are not included here - read them from GET /invites.\\n\\nEach row carries the member id (the id PATCH/DELETE /members/{id} and the product-access routes expect), the assigned role, and the underlying user. `user` can be null if the user record cannot be resolved; `role` is always populated for real members.\\n\\nThis endpoint accepts only `limit` and `offset`. There is no `search` and n
1o role filter: the controller passes neither to the service, so any such query parameter is ignored. The full member set is read from the database and paginated in memory, so `pagination.totalCount` is exact.","responses":{"200":{"description":"List workspace members succeeded.","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","const":true},"code":{"type":"integer","example":200},"message":{"type":"string","example":"OK"},"error":{"type":"null"},"data":{"type":"object","properties":{"members":{"type":"array","items":{"$ref":"#/components/schemas/Member"}},"pagination":{"$ref":"#/components/schemas/Pagination"}},"required":["members","pagination"]},"_req":{"type":"object","properties":{"reqId":{"type":"string"},"resTime":{"type":["integer","null"]}}}},"required":["success","code","message","error","data"]}}}},"400":{"description":"`request.invalid_pagination` - `limit` or `offset` is not a whole number, or `limit` is outside 1 to 100; `error.field` names the offending parameter.","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","const":false},"code":{"type":"integer","example":400},"message":{"type":"string","example":"Something went wrong."},"error":{"$ref":"#/components/schemas/ApiError"},"data":{"type":"null"},"_req":{"type":"object","properties":{"reqId":{"type":"string"},"resTime":{"type":["integer","null"]}}}},"required":["success","code","message","error","data"]}}}},"401":{"description":"Missing, malformed, revoked or non-member API key (`auth.api_key_*`).","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","const":false},"code":{"type":"integer","example":400},"message":{"type":"string","example":"Something went wrong."},"error":{"$ref":"#/components/schemas/ApiError"},"data":{"type":"null"},"_req":{"type":"object","properties":{"reqId":{"type":"string"},"resTime":{"type":["integer","null"]}}}},"required":["success","code","message","error","data"]}}}},"500":{"description":"Unexpected server error (`server.error`).","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","const":false},"code":{"type":"integer","example":400},"message":{"type":"string","example":"Something went wrong."},"error":{"$ref":"#/components/schemas/ApiError"},"data":{"type":"null"},"_req":{"type":"object","properties":{"reqId":{"type":"string"},"resTime":{"type":["integer","null"]}}}},"required":["success","code","message","error","data"]}}}}},"x-envless-scopes":["members:read"],"parameters":[{"name":"limit","in":"query","schema":{"type":"integer","minimum":1,"maximum":100,"default":25},"description":"Rows per page, 1 to 100. Must be a whole number."},{"name":"offset","in":"query","schema":{"type":"integer","minimum":0,"default":0},"description":"Rows to skip. Must be a whole number of 0 or more."}]},"post":{"operationId":"inviteMember","tags":["Members"],"summary":"Invite a member","description":"Sends an email invitation to join the workspace. This does not create a member: it creates a pending invite that appears in GET /invites and becomes a member only when the recipient accepts. The response payload is therefore an Invite, not a Member, and the status is 201.\\n\\n`roleId` is required and must be a role id from GET /roles - the id field of a role, not its name. The owner system role cannot be handed out by invite; pick `admin`, `viewer` or one of your custom roles.\\n\\nThe invite email is sent synchronously. If delivery fails the invite is rolled back and you get a 500, so a 201 means the email was accepted by the provider. Invites expire 3 days after they are sent, and the recipient gets one reminder email 24 hours before that. Emails are normalised to lowercase. Emits `member.invited`.\\n\\nSeats are plan-limited and pending invites count against the limit: Free and Dev workspaces allow 1 member total, so on those plans every invite fails with 409 until the workspace upgrades; Team allows 10 members and Enterprise is unlimited.","responses":{"201":{"description":"Invite a member succeeded.","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","const":true},"code":{"type":"integer","example":200},"message":{"type":"string","example":"OK"},"error":{"type":"null"},"data":{"$ref":"#/components/schemas/Invite"},"_req":{"type":"object","properties":{"reqId":{"type":"string"},"resTime":{"type":["integer","null"]}}}},"required":["success","code","message","error","data"]}}}}
1,"400":{"description":"`request.body_invalid` - `email` or `roleId` is missing or malformed.","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","const":false},"code":{"type":"integer","example":400},"message":{"type":"string","example":"Something went wrong."},"error":{"$ref":"#/components/schemas/ApiError"},"data":{"type":"null"},"_req":{"type":"object","properties":{"reqId":{"type":"string"},"resTime":{"type":["integer","null"]}}}},"required":["success","code","message","error","data"]}}}},"401":{"description":"Missing, malformed, revoked or non-member API key (`auth.api_key_*`).","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","const":false},"code":{"type":"integer","example":400},"message":{"type":"string","example":"Something went wrong."},"error":{"$ref":"#/components/schemas/ApiError"},"data":{"type":"null"},"_req":{"type":"object","properties":{"reqId":{"type":"string"},"resTime":{"type":["integer","null"]}}}},"required":["success","code","message","error","data"]}}}},"402":{"description":"`member.seat_limit` - the workspace has used every seat on its plan.","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","const":false},"code":{"type":"integer","example":400},"message":{"type":"string","example":"Something went wrong."},"error":{"$ref":"#/components/schemas/ApiError"},"data":{"type":"null"},"_req":{"type":"object","properties":{"reqId":{"type":"string"},"resTime":{"type":["integer","null"]}}}},"required":["success","code","message","error","data"]}}}},"403":{"description":"`auth.scope_missing` - the key lacks members:write.","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","const":false},"code":{"type":"integer","example":400},"message":{"type":"string","example":"Something went wrong."},"error":{"$ref":"#/components/schemas/ApiError"},"data":{"type":"null"},"_req":{"type":"object","properties":{"reqId":{"type":"string"},"resTime":{"type":["integer","null"]}}}},"required":["success","code","message","error","data"]}}}},"404":{"description":"`role.not_found` - no role in this workspace matches `roleId`.","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","const":false},"code":{"type":"integer","example":400},"message":{"type":"string","example":"Something went wrong."},"error":{"$ref":"#/components/schemas/ApiError"},"data":{"type":"null"},"_req":{"type":"object","properties":{"reqId":{"type":"string"},"resTime":{"type":["integer","null"]}}}},"required":["success","code","message","error","data"]}}}},"409":{"description":"`role.owner_not_assignable` - `roleId` is the owner role, which cannot be granted by invite.","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","const":false},"code":{"type":"integer","example":400},"message":{"type":"string","example":"Something went wrong."},"error":{"$ref":"#/components/schemas/ApiError"},"data":{"type":"null"},"_req":{"type":"object","properties":{"reqId":{"type":"string"},"resTime":{"type":["integer","null"]}}}},"required":["success","code","message","error","data"]}}}},"500":{"description":"Unexpected server error (`server.error`).","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","const":false},"code":{"type":"integer","example":400},"message":{"type":"string","example":"Something went wrong."},"error":{"$ref":"#/components/schemas/ApiError"},"data":{"type":"null"},"_req":{"type":"object","properties":{"reqId":{"type":"string"},"resTime":{"type":["integer","null"]}}}},"required":["success","code","message","error","data"]}}}}},"x-envless-scopes":["members:write"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"email":{"type":"string","format":"email","maxLength":255,"description":"Address to invite. Lowercased on save.","example":"[email protected]"},"roleId":{"type":"string","description":"Role id from GET /roles. Must belong to this workspace. The owner role is rejected.","example":"019faa4c-6f6e-716a-a548-fc2ea447953b"}},"required":["email","roleId"]}}}}}},"/members/me":{"delete":{"operationId":"leaveWorkspace","tags":["Members"],"summary":"Leave the workspace","description":"Removes the API key\'s owner from the current workspace. This is the self-service counterpart to `DELETE /members/{id}`, which refuses self-removal.\\n\\n**It revokes the calling key along with the membership.** Every key in the workspace belongs to a member, so the request that succeeds is the last one this key can make. Do not use it in a script that has work left to do.\\n\\nThe workspace owner cannot leave, because a workspace with no owner is unrecoverable. Transfer ownership first, or delete the workspace with `DELETE /workspace`.\\n\\nEmits `member.removed` with `left: true`, which is how a webhook consumer tells a voluntary departure from an admin removing somebody.","responses":{"200":{"description":"Leave the workspace succeeded.","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","const":true},"code":{"type":"integer","example":200},"message":{"type":"string","example":"OK"},"error":{"type":"null"},"data":{"type":"object","properties":{"id":{"type":"string","description":"The membership row that was removed."}
1,"left":{"type":"boolean","const":true}},"required":["id","left"]},"_req":{"type":"object","properties":{"reqId":{"type":"string"},"resTime":{"type":["integer","null"]}}}},"required":["success","code","message","error","data"]}}}},"401":{"description":"Missing, malformed, revoked or non-member API key (`auth.api_key_*`).","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","const":false},"code":{"type":"integer","example":400},"message":{"type":"string","example":"Something went wrong."},"error":{"$ref":"#/components/schemas/ApiError"},"data":{"type":"null"},"_req":{"type":"object","properties":{"reqId":{"type":"string"},"resTime":{"type":["integer","null"]}}}},"required":["success","code","message","error","data"]}}}},"403":{"description":"`auth.scope_missing` - the key lacks members:write.","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","const":false},"code":{"type":"integer","example":400},"message":{"type":"string","example":"Something went wrong."},"error":{"$ref":"#/components/schemas/ApiError"},"data":{"type":"null"},"_req":{"type":"object","properties":{"reqId":{"type":"string"},"resTime":{"type":["integer","null"]}}}},"required":["success","code","message","error","data"]}}}},"404":{"description":"`member.not_found` - the key owner is not a member of this workspace.","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","const":false},"code":{"type":"integer","example":400},"message":{"type":"string","example":"Something went wrong."},"error":{"$ref":"#/components/schemas/ApiError"},"data":{"type":"null"},"_req":{"type":"object","properties":{"reqId":{"type":"string"},"resTime":{"type":["integer","null"]}}}},"required":["success","code","message","error","data"]}}}},"409":{"description":"`member.owner_cannot_leave` - the key owner holds the owner role.","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","const":false},"code":{"type":"integer","example":400},"message":{"type":"string","example":"Something went wrong."},"error":{"$ref":"#/components/schemas/ApiError"},"data":{"type":"null"},"_req":{"type":"object","properties":{"reqId":{"type":"string"},"resTime":{"type":["integer","null"]}}}},"required":["success","code","message","error","data"]}}}},"500":{"description":"Unexpected server error (`server.error`).","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","const":false},"code":{"type":"integer","example":400},"message":{"type":"string","example":"Something went wrong."},"error":{"$ref":"#/components/schemas/ApiError"},"data":{"type":"null"},"_req":{"type":"object","properties":{"reqId":{"type":"string"},"resTime":{"type":["integer","null"]}}}},"required":["success","code","message","error","data"]}}}}},"x-envless-scopes":["members:write"]}},"/members/{id}":{"patch":{"operationId":"updateMember","tags":["Members"],"summary":"Change a member\'s role","description":"Reassigns a member to a different role. `roleId` is the only mutable field, and role ids come from GET /roles.\\n\\nSending the member\'s current `roleId` is a no-op that still returns 200 with the unchanged member. You cannot change your own role (the key owner\'s membership), you cannot change the workspace owner\'s role, and you cannot promote anyone into the owner role.\\n\\nSide effect worth knowing: after a successful change every API key owned by that member is re-clamped against the new role\'s permissions, so keys that held scopes the new role does not grant lose them immediately. Emits `member.updated`.","responses":{"200":{"description":"Change a member\'s role succeeded.","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","const":true},"code":{"type":"integer","example":200},"message":{"type":"string","example":"OK"},"error":{"type":"null"},"data":{"$ref":"#/components/schemas/Member"},"_req":{"type":"object","properties":{"reqId":{"type":"string"},"resTime":{"type":["integer","null"]}}}},"required":["success","code","message","error","data"]}}}}
1,"400":{"description":"`request.body_invalid` - `roleId` is missing.","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","const":false},"code":{"type":"integer","example":400},"message":{"type":"string","example":"Something went wrong."},"error":{"$ref":"#/components/schemas/ApiError"},"data":{"type":"null"},"_req":{"type":"object","properties":{"reqId":{"type":"string"},"resTime":{"type":["integer","null"]}}}},"required":["success","code","message","error","data"]}}}},"401":{"description":"Missing, malformed, revoked or non-member API key (`auth.api_key_*`).","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","const":false},"code":{"type":"integer","example":400},"message":{"type":"string","example":"Something went wrong."},"error":{"$ref":"#/components/schemas/ApiError"},"data":{"type":"null"},"_req":{"type":"object","properties":{"reqId":{"type":"string"},"resTime":{"type":["integer","null"]}}}},"required":["success","code","message","error","data"]}}}},"403":{"description":"`auth.scope_missing` - the key lacks members:write.","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","const":false},"code":{"type":"integer","example":400},"message":{"type":"string","example":"Something went wrong."},"error":{"$ref":"#/components/schemas/ApiError"},"data":{"type":"null"},"_req":{"type":"object","properties":{"reqId":{"type":"string"},"resTime":{"type":["integer","null"]}}}},"required":["success","code","message","error","data"]}}}},"404":{"description":"`member.not_found` - no member or role matches.","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","const":false},"code":{"type":"integer","example":400},"message":{"type":"string","example":"Something went wrong."},"error":{"$ref":"#/components/schemas/ApiError"},"data":{"type":"null"},"_req":{"type":"object","properties":{"reqId":{"type":"string"},"resTime":{"type":["integer","null"]}}}},"required":["success","code","message","error","data"]}}}},"409":{"description":"`role.owner_not_assignable` - the owner role cannot be assigned to another member.","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","const":false},"code":{"type":"integer","example":400},"message":{"type":"string","example":"Something went wrong."},"error":{"$ref":"#/components/schemas/ApiError"},"data":{"type":"null"},"_req":{"type":"object","properties":{"reqId":{"type":"string"},"resTime":{"type":["integer","null"]}}}},"required":["success","code","message","error","data"]}}}},"500":{"description":"Unexpected server error (`server.error`).","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","const":false},"code":{"type":"integer","example":400},"message":{"type":"string","example":"Something went wrong."},"error":{"$ref":"#/components/schemas/ApiError"},"data":{"type":"null"},"_req":{"type":"object","properties":{"reqId":{"type":"string"},"resTime":{"type":["integer","null"]}}}},"required":["success","code","message","error","data"]}}}}},"x-envless-scopes":["members:write"],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"},"description":"Workspace member id (the `id` from GET /members). This is not the user id, and no slug form is accepted."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"roleId":{"type":"string","description":"Target role id from GET /roles. Must belong to this workspace and must not be the owner role.","example":"019faa4c-6f6e-716a-a548-fc2ea447953b"}},"required":["roleId"]}}}}},"delete":{"operationId":"deleteMember","tags":["Members"],"summary":"Remove a member","description":"Removes someone from the workspace. The membership is soft-deleted; the user account itself is untouched and can be invited again later.\\n\\nYou cannot remove yourself (the key owner), and the workspace owner cannot be removed at all - transfer ownership in the dashboard first. Emits `member.removed`. The payload is just the removed member id.","responses":{"200":{"description":"Remove a member succeeded.","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","const":true},"code":{"type":"integer","example":200},"message":{"type":"string","example":"OK"},"error":{"type":"null"},"data":{"type":"object","properties":{"id":{"type":"string","description":"Id of the removed member."}},"required":["id"]},"_req":{"type":"object","properties":{"reqId":{"type":"string"},"resTime":{"type":["integer","null"]}}}},"required":["success","code","message","error","data"]}}}},"401":{"description":"Missing, malformed, revoked or non-member API key (`auth.api_key_*`).","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","const":false},"code":{"type":"integer","example":400},"message":{"type":"string","example":"Something went wrong."},"error":{"$ref":"#/components/schemas/ApiError"},"data":{"type":"null"},"_req":{"type":"object","properties":{"reqId":{"type":"string"},"resTime":{"type":["integer","null"]}}}},"required":["success","code","message","error","data"]}}}},"403":{"description":"`auth.scope_missing` - the key lacks members:write.","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","const":false},"code":{"type":"integer","example":400},"message":{"type":"string","example":"Something went wrong."},"error":{"$ref":"#/components/schemas/ApiError"},"data":{"type":"null"},"_req":{"type":"object","properties":{"reqId":{"type":"string"},"resTime":{"type":["integer","null"]}}}},"required":["success","code","message","error","data"]}}}}
1,"404":{"description":"`member.not_found` - no member matches.","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","const":false},"code":{"type":"integer","example":400},"message":{"type":"string","example":"Something went wrong."},"error":{"$ref":"#/components/schemas/ApiError"},"data":{"type":"null"},"_req":{"type":"object","properties":{"reqId":{"type":"string"},"resTime":{"type":["integer","null"]}}}},"required":["success","code","message","error","data"]}}}},"409":{"description":"`member.owner_immutable` - the target is the workspace owner.","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","const":false},"code":{"type":"integer","example":400},"message":{"type":"string","example":"Something went wrong."},"error":{"$ref":"#/components/schemas/ApiError"},"data":{"type":"null"},"_req":{"type":"object","properties":{"reqId":{"type":"string"},"resTime":{"type":["integer","null"]}}}},"required":["success","code","message","error","data"]}}}},"500":{"description":"Unexpected server error (`server.error`).","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","const":false},"code":{"type":"integer","example":400},"message":{"type":"string","example":"Something went wrong."},"error":{"$ref":"#/components/schemas/ApiError"},"data":{"type":"null"},"_req":{"type":"object","properties":{"reqId":{"type":"string"},"resTime":{"type":["integer","null"]}}}},"required":["success","code","message","error","data"]}}}}},"x-envless-scopes":["members:write"],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"},"description":"Workspace member id (the `id` from GET /members), not the user id."}]}},"/permissions":{"get":{"operationId":"listPermissions","tags":["Roles"],"summary":"List the permission catalogue","description":"Returns the complete, static catalogue of permission strings the platform understands. Read it before building a role payload: POST /roles and PATCH /roles/{id} reject any string that is not in `permissions`.\\n\\n`assignableToCustomRoles` is false for the permissions no custom role may ever hold - today `workspace:delete` and `billing:manage`. Requesting one of those in a role payload fails with 400 `request.body_invali
1d`, so filter on this flag when rendering a permission picker.\\n\\n`byResource` is the same catalogue grouped by the part of the string before the colon, convenient for building a grouped UI. `systemRoles` gives the exact permission list behind owner, admin and viewer, which is what makes it possible to predict what a role change will grant. Beyond the catalogue ceiling, a caller can still only grant permissions they hold themselves.\\n\\nThe payload is static and not paginated; `limit` and `offset` are accepted by the middleware but have no effect.","responses":{"200":{"description":"List the permission catalogue succeeded.","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","const":true},"code":{"type":"integer","example":200},"message":{"type":"string","example":"OK"},"error":{"type":"null"},"data":{"type":"object","properties":{"permissions":{"type":"array","description":"Every permission the platform recognises.","items":{"type":"object","properties":{"name":{"type":"string","description":"The permission string, e.g. `variables:read`. Use this verbatim in role payloads."},"resource":{"type":"string","description":"The part before the colon, e.g. `variables`."},"assignableToCustomRoles":{"type":"boolean","description":"False for permissions no custom role may hold (`workspace:delete`, `billing:manage`). Only owner holds those."}},"required":["name","resource","assignableToCustomRoles"]}},"byResource":{"type":"object","description":"The same permissions grouped by resource, keyed by resource name.","additionalProperties":{"type":"array","items":{"type":"string"}}},"systemRoles":{"type":"object","description":"The permission list behind each system role, keyed by system role key.","properties":{"owner":{"type":"array","items":{"type":"string"},"description":"Every permission in the catalogue."},"admin":{"type":"array","items":{"type":"string"}},"viewer":{"type":"array","items":{"type":"string"}}}}},"required":["permissions","byResource","systemRoles"]},"_req":{"type":"object","properties":{"reqId":{"type":"string"},"resTime":{"type":["integer","null"]}}}},"required":["success","code","message","error","data"]}}}},"401":{"description":"Missing, malformed, revoked or non-member API key (`auth.api_key_*`).","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","const":false},"code":{"type":"integer","example":400},"message":{"type":"string","example":"Something went wrong."},"error":{"$ref":"#/components/schemas/ApiError"},"data":{"type":"null"},"_req":{"type":"object","properties":{"reqId":{"type":"string"},"resTime":{"type":["integer","null"]}}}},"required":["success","code","message","error","data"]}}}},"500":{"description":"Unexpected server error (`server.error`).","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","const":false},"code":{"type":"integer","example":400},"message":{"type":"string","example":"Something went wrong."},"error":{"$ref":"#/components/schemas/ApiError"},"data":{"type":"null"},"_req":{"type":"object","properties":{"reqId":{"type":"string"},"resTime":{"type":["integer","null"]}}}},"required":["success","code","message","error","data"]}}}}},"x-envless-scopes":["roles:read"]}},"/products":{"get":{"operationId":"listProducts","tags":["Products"],"summary":"List products","description":"Returns the products in the workspace the key\'s owner can see. Products the owner cannot reach (private products with no grant, and no `products.manage_private` permission) are filtered out entirely rather than returned as stubs. Each row carries a `locked` flag: products beyond the plan\'s product allowance (Free 1, Dev 3, Team 15, Enterprise unlimited) are ordered by internal insertion order and everything past the cap is locked. Locked products still list and still read, but PATCH on them fails with 402 `product.locked`. Pagination is offset-based and applied in memory after the access filter, so `pagination.totalCount` is the count the caller can actually see, not the raw workspace total. `search` matches name and slug; `order` defaults to `name` and sorts A to Z, with `asc` and `desc` sorting oldest and newest first on `createdAt`.","responses":{"200":{"description":"List products succeeded.","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","const":true},"code":{"type":"integer","example":200},"message":{"type":"string","example":"OK"},"error":{"type":"null"},"data":{"type":"object","properties":{"products":{"type":"array","items":{"$ref":"#/components/schemas/Product"}},"pagination":{"$ref":"#/components/schemas/Pagination"}},"required":["products","pagination"]},"_req":{"type":"object","properties":{"reqId":{"type":"string"},"resTime":{"type":["integer","null"]}}}},"required":["success","code","message","error","data"]}}}}
1,"400":{"description":"`request.invalid_pagination` - `limit` or `offset` is not a whole number, or `limit` falls outside 1-100.","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","const":false},"code":{"type":"integer","example":400},"message":{"type":"string","example":"Something went wrong."},"error":{"$ref":"#/components/schemas/ApiError"},"data":{"type":"null"},"_req":{"type":"object","properties":{"reqId":{"type":"string"},"resTime":{"type":["integer","null"]}}}},"required":["success","code","message","error","data"]}}}},"401":{"description":"Missing, malformed, revoked or non-member API key (`auth.api_key_*`).","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","const":false},"code":{"type":"integer","example":400},"message":{"type":"string","example":"Something went wrong."},"error":{"$ref":"#/components/schemas/ApiError"},"data":{"type":"null"},"_req":{"type":"object","properties":{"reqId":{"type":"string"},"resTime":{"type":["integer","null"]}}}},"required":["success","code","message","error","data"]}}}},"403":{"description":"`auth.scope_missing` - the key lacks products:read.","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","const":false},"code":{"type":"integer","example":400},"message":{"type":"string","example":"Something went wrong."},"error":{"$ref":"#/components/schemas/ApiError"},"data":{"type":"null"},"_req":{"type":"object","properties":{"reqId":{"type":"string"},"resTime":{"type":["integer","null"]}}}},"required":["success","code","message","error","data"]}}}},"500":{"description":"Unexpected server error (`server.error`).","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","const":false},"code":{"type":"integer","example":400},"message":{"type":"string","example":"Something went wrong."},"error":{"$ref":"#/components/schemas/ApiError"},"data":{"type":"null"},"_req":{"type":"object","properties":{"reqId":{"type":"string"},"resTime":{"type":["integer","null"]}}}},"required":["success","code","message","error","data"]}}}}},"x-envless-scopes":["products:read"],"parameters":[{"name":"limit","in":"query","schema":{"type":"integer","minimum":1,"maximum":100,"default":25},"description":"Rows per page. Must be a whole number; anything outside 1-100 is rejected with 400 `request.invalid_pagination`."},{"name":"offset","in":"query","schema":{"type":"integer","minimum":0,"default":0},"description":"Rows to skip. Must be a whole number of 0 or greater."},{"name":"search","in":"query","schema":{"type":"string"},"description":"Case-insensitive substring match against product name and slug."},{"name":"order","in":"query","schema":{"type":"string","enum":["name","asc","desc"],"default":"name"},"description":"`name` sorts A to Z, `asc` and `desc` sort oldest and newest first on createdAt. Any other value, including omitting it, sorts by name."}]},"post":{"operationId":"createProduct","tags":["Products"],"summary":"Create a product","description":"Creates a product in the caller\'s workspace. Only `name` is required: when `slug` is omitted the slug is derived from the name, and when it is supplied it is still slugified before validation, so `My Product` and `my-product` both land on `my-product`. The plan allowance is checked **before** the slug uniqueness check, so a workspace at its cap gets 402/409 even when the slug would also have collided. New products are always public (`isPrivate: false`) - use PATCH to make one private. Icons cannot be set here or in PATCH. The response is built from the freshly inserted row, so `isPrivate` is always `false`, `updatedAt` is always `null`, and there is no `locked` field; call GET /products/{slug} if you need the settled shape.","responses":{"201":{"description":"Create a product succeeded.","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","const":true},"code":{"type":"integer","example":200},"message":{"type":"string","example":"OK"},"error":{"type":"null"},"data":{"$ref":"#/components/schemas/Product"},"_req":{"type":"object","properties":{"reqId":{"type":"string"},"resTime":{"type":["integer","null"]}}}},"required":["success","code","message","error","data"]}}}}
1,"400":{"description":"`request.body_invalid` - `name` is not a string (field `name`), or name/slug fails length or slug-pattern validation.","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","const":false},"code":{"type":"integer","example":400},"message":{"type":"string","example":"Something went wrong."},"error":{"$ref":"#/components/schemas/ApiError"},"data":{"type":"null"},"_req":{"type":"object","properties":{"reqId":{"type":"string"},"resTime":{"type":["integer","null"]}}}},"required":["success","code","message","error","data"]}}}},"401":{"description":"Missing, malformed, revoked or non-member API key (`auth.api_key_*`).","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","const":false},"code":{"type":"integer","example":400},"message":{"type":"string","example":"Something went wrong."},"error":{"$ref":"#/components/schemas/ApiError"},"data":{"type":"null"},"_req":{"type":"object","properties":{"reqId":{"type":"string"},"resTime":{"type":["integer","null"]}}}},"required":["success","code","message","error","data"]}}}},"402":{"description":"`plan.upgrade_required` - the workspace already holds its plan\'s product allowance (Free 1, Dev 3, Team 15; Enterprise is unlimited and never hits this). `data` carries `{ limit, current }`.","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","const":false},"code":{"type":"integer","example":400},"message":{"type":"string","example":"Something went wrong."},"error":{"$ref":"#/components/schemas/ApiError"},"data":{"type":"null"},"_req":{"type":"object","properties":{"reqId":{"type":"string"},"resTime":{"type":["integer","null"]}}}},"required":["success","code","message","error","data"]}}}},"403":{"description":"`auth.scope_missing` - the key lacks products:write.","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","const":false},"code":{"type":"integer","example":400},"message":{"type":"string","example":"Something went wrong."},"error":{"$ref":"#/components/schemas/ApiError"},"data":{"type":"null"},"_req":{"type":"object","properties":{"reqId":{"type":"string"},"resTime":{"type":["integer","null"]}}}},"required":["success","code","message","error","data"]}}}},"409":{"description":"`product.slug_conflict` - another product in the workspace already owns the resolved slug.","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","const":false},"code":{"type":"integer","example":400},"message":{"type":"string","example":"Something went wrong."},"error":{"$ref":"#/components/schemas/ApiError"},"data":{"type":"null"},"_req":{"type":"object","properties":{"reqId":{"type":"string"},"resTime":{"type":["integer","null"]}}}},"required":["success","code","message","error","data"]}}}},"500":{"description":"Unexpected server error (`server.error`).","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","const":false},"code":{"type":"integer","example":400},"message":{"type":"string","example":"Something went wrong."},"error":{"$ref":"#/components/schemas/ApiError"},"data":{"type":"null"},"_req":{"type":"object","properties":{"reqId":{"type":"string"},"resTime":{"type":["integer","null"]}}}},"required":["success","code","message","error","data"]}}}}},"x-envless-scopes":["products:write"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"name":{"type":"string","minLength":3,"maxLength":50,"description":"Display name. Required.","example":"Billing"},"slug":{"type":"string","minLength":3,"maxLength":50,"pattern":"^[a-z0-9]+(?:-[a-z0-9]+)*$","description":"Optional URL slug, unique per workspace. Slugified server-side before validation; derived from `name` when omitted or blank.","example":"billing"}},"required":["name"]}}}}}},"/products/{slug}":{"get":{"operationId":"getProduct","tags":["Products"],"summary":"Get a product","description":"Fetches a single product by slug or by id. Unlike the project routes there is no id-then-slug fallback: if the path segment matches the UUID shape it is looked up as an id only, otherwise as a slug only. Private products the key owner has no grant on return 404 rather than 403, so callers cannot probe for their existence. This is the only product read that includes `locked`, computed against the workspace\'s current plan.","responses":{"200":{"description":"Get a product succeeded.","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","const":true},"code":{"type":"integer","example":200},"message":{"type":"string","example":"OK"},"error":{"type":"null"},"data":{"$ref":"#/components/schemas/Product"},"_req":{"type":"object","properties":{"reqId":{"type":"string"},"resTime":{"type":["integer","null"]}}}},"required":["success","code","message","error","data"]}}}},"401":{"description":"Missing, malformed, revoked or non-member API key (`auth.api_key_*`).","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","const":false},"code":{"type":"integer","example":400},"message":{"type":"string","example":"Something went wrong."},"error":{"$ref":"#/components/schemas/ApiError"},"data":{"type":"null"},"_req":{"type":"object","properties":{"reqId":{"type":"string"},"resTime":{"type":["integer","null"]}}}},"required":["success","code","message","error","data"]}}}},"403":{"description":"`auth.scope_missing` - the key lacks products:read.","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","const":false},"code":{"type":"integer","example":400},"message":{"type":"string","example":"Something went wrong."},"error":{"$ref":"#/components/schemas/ApiError"},"data":{"type":"null"},"_req":{"type":"object","properties":{"reqId":{"type":"string"},"resTime":{"type":["integer","null"]}}}},"required":["success","code","message","error","data"]}}}}
1,"404":{"description":"`product.not_found` - no product matches, or the product is private and the key owner has no grant on it.","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","const":false},"code":{"type":"integer","example":400},"message":{"type":"string","example":"Something went wrong."},"error":{"$ref":"#/components/schemas/ApiError"},"data":{"type":"null"},"_req":{"type":"object","properties":{"reqId":{"type":"string"},"resTime":{"type":["integer","null"]}}}},"required":["success","code","message","error","data"]}}}},"500":{"description":"Unexpected server error (`server.error`).","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","const":false},"code":{"type":"integer","example":400},"message":{"type":"string","example":"Something went wrong."},"error":{"$ref":"#/components/schemas/ApiError"},"data":{"type":"null"},"_req":{"type":"object","properties":{"reqId":{"type":"string"},"resTime":{"type":["integer","null"]}}}},"required":["success","code","message","error","data"]}}}}},"x-envless-scopes":["products:read"],"parameters":[{"name":"slug","in":"path","required":true,"schema":{"type":"string"},"description":"Product slug, or the product\'s uniqueId. A UUID-shaped value is resolved as an id and never falls back to a slug lookup."}]},"patch":{"operationId":"updateProduct","tags":["Products"],"summary":"Update a product","description":"Partial update: only the keys you send are touched. Sending an `icon` key of any value (including `null`) is rejected with 400 `request.body_invali
1d` and field `icon` - product icons are upload-only from the dashboard. That check runs before the product is resolved, so an `icon` key plus an unknown slug still returns 400, not 404. Flipping `isPrivate` from false to true automatically grants the key owner access to the product, so an integrator cannot lock themselves out with one call; flipping it back to false does not revoke any grant already recorded. Renaming the slug is validated against the workspace, not the product. Locked products (over the plan cap) reject every PATCH with 402 `product.locked`.","responses":{"200":{"description":"Update a product succeeded.","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","const":true},"code":{"type":"integer","example":200},"message":{"type":"string","example":"OK"},"error":{"type":"null"},"data":{"$ref":"#/components/schemas/Product"},"_req":{"type":"object","properties":{"reqId":{"type":"string"},"resTime":{"type":["integer","null"]}}}},"required":["success","code","message","error","data"]}}}}
1,"400":{"description":"`request.body_invalid` - an `icon` key is present at all (field `icon`), or `name`/`slug` fails length or slug-pattern validation.","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","const":false},"code":{"type":"integer","example":400},"message":{"type":"string","example":"Something went wrong."},"error":{"$ref":"#/components/schemas/ApiError"},"data":{"type":"null"},"_req":{"type":"object","properties":{"reqId":{"type":"string"},"resTime":{"type":["integer","null"]}}}},"required":["success","code","message","error","data"]}}}},"401":{"description":"Missing, malformed, revoked or non-member API key (`auth.api_key_*`).","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","const":false},"code":{"type":"integer","example":400},"message":{"type":"string","example":"Something went wrong."},"error":{"$ref":"#/components/schemas/ApiError"},"data":{"type":"null"},"_req":{"type":"object","properties":{"reqId":{"type":"string"},"resTime":{"type":["integer","null"]}}}},"required":["success","code","message","error","data"]}}}},"402":{"description":"`product.locked` - the product sits beyond the plan\'s product allowance. `data` carries `{ locked: true, resource: \'product\', plan }`.","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","const":false},"code":{"type":"integer","example":400},"message":{"type":"string","example":"Something went wrong."},"error":{"$ref":"#/components/schemas/ApiError"},"data":{"type":"null"},"_req":{"type":"object","properties":{"reqId":{"type":"string"},"resTime":{"type":["integer","null"]}}}},"required":["success","code","message","error","data"]}}}},"403":{"description":"`auth.scope_missing` - the key lacks products:write.","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","const":false},"code":{"type":"integer","example":400},"message":{"type":"string","example":"Something went wrong."},"error":{"$ref":"#/components/schemas/ApiError"},"data":{"type":"null"},"_req":{"type":"object","properties":{"reqId":{"type":"string"},"resTime":{"type":["integer","null"]}}}},"required":["success","code","message","error","data"]}}}},"404":{"description":"`product.not_found` - no product matches, or it is private and the key owner has no grant.","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","const":false},"code":{"type":"integer","example":400},"message":{"type":"string","example":"Something went wrong."},"error":{"$ref":"#/components/schemas/ApiError"},"data":{"type":"null"},"_req":{"type":"object","properties":{"reqId":{"type":"string"},"resTime":{"type":["integer","null"]}}}},"required":["success","code","message","error","data"]}}}},"409":{"description":"`product.slug_conflict` - another product in the workspace already owns the new slug.","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","const":false},"code":{"type":"integer","example":400},"message":{"type":"string","example":"Something went wrong."},"error":{"$ref":"#/components/schemas/ApiError"},"data":{"type":"null"},"_req":{"type":"object","properties":{"reqId":{"type":"string"},"resTime":{"type":["integer","null"]}}}},"required":["success","code","message","error","data"]}}}},"500":{"description":"Unexpected server error (`server.error`).","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","const":false},"code":{"type":"integer","example":400},"message":{"type":"string","example":"Something went wrong."},"error":{"$ref":"#/components/schemas/ApiError"},"data":{"type":"null"},"_req":{"type":"object","properties":{"reqId":{"type":"string"},"resTime":{"type":["integer","null"]}}}},"required":["success","code","message","error","data"]}}}}},"x-envless-scopes":["products:write"],"parameters":[{"name":"slug","in":"path","required":true,"schema":{"type":"string"},"description":"Product slug, or the product\'s uniqueId. A UUID-shaped value is resolved as an id only."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"name":{"type":"string","minLength":3,"maxLength":50,"example":"Billing"},"slug":{"type":"string","minLength":3,"maxLength":50,"pattern":"^[a-z0-9]+(?:-[a-z0-9]+)*$","description":"Not slugified on update - it is validated as-is, so send an already-valid slug.","example":"billing"},"isPrivate":{"type":"boolean","description":"Set true to restrict the product to explicitly granted members. Doing so grants the calling key\'s owner access in the same request.","example":false}}}}}}},"delete":{"operationId":"deleteProduct","tags":["Products"],"summary":"Delete a product","description":"Soft-deletes a product along with everything under it, in one transaction: its projects, their environments, and every variable in those environments. There is no has-children guard and no undo over the API, so `products:write` on its own is enough to remove a
1whole tree - scope the key to the projects it should touch if that is not what you want. Note this route deliberately does not run the plan-lock check, so a product locked by a downgrade can still be deleted (that is how you get back under the cap). The payload is a tombstone of the deleted product plus a count of what the cascade removed, not the full Product schema.","responses":{"200":{"description":"Delete a product succeeded.","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","const":true},"code":{"type":"integer","example":200},"message":{"type":"string","example":"OK"},"error":{"type":"null"},"data":{"type":"object","properties":{"id":{"type":"string"},"name":{"type":"string"},"slug":{"type":"string"},"deletedProjects":{"type":"integer"},"deletedEnvironments":{"type":"integer"},"deletedVariables":{"type":"integer"}},"required":["id","name","slug","deletedProjects","deletedEnvironments","deletedVariables"]},"_req":{"type":"object","properties":{"reqId":{"type":"string"},"resTime":{"type":["integer","null"]}}}},"required":["success","code","message","error","data"]}}}},"401":{"description":"Missing, malformed, revoked or non-member API key (`auth.api_key_*`).","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","const":false},"code":{"type":"integer","example":400},"message":{"type":"string","example":"Something went wrong."},"error":{"$ref":"#/components/schemas/ApiError"},"data":{"type":"null"},"_req":{"type":"object","properties":{"reqId":{"type":"string"},"resTime":{"type":["integer","null"]}}}},"required":["success","code","message","error","data"]}}}},"403":{"description":"`auth.scope_missing` - the key lacks products:write.","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","const":false},"code":{"type":"integer","example":400},"message":{"type":"string","example":"Something went wrong."},"error":{"$ref":"#/components/schemas/ApiError"},"data":{"type":"null"},"_req":{"type":"object","properties":{"reqId":{"type":"string"},"resTime":{"type":["integer","null"]}}}},"required":["success","code","message","error","data"]}}}},"404":{"description":"`product.not_found` - no product matches, or it is private and the key owner has no grant.","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","const":false},"code":{"type":"integer","example":400},"message":{"type":"string","example":"Something went wrong."},"error":{"$ref":"#/components/schemas/ApiError"},"data":{"type":"null"},"_req":{"type":"object","properties":{"reqId":{"type":"string"},"resTime":{"type":["integer","null"]}}}},"required":["success","code","message","error","data"]}}}},"500":{"description":"Unexpected server error (`server.error`).","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","const":false},"code":{"type":"integer","example":400},"message":{"type":"string","example":"Something went wrong."},"error":{"$ref":"#/components/schemas/ApiError"},"data":{"type":"null"},"_req":{"type":"object","properties":{"reqId":{"type":"string"},"resTime":{"type":["integer","null"]}}}},"required":["success","code","message","error","data"]}}}}},"x-envless-scopes":["products:write"],"parameters":[{"name":"slug","in":"path","required":true,"schema":{"type":"string"},"description":"Product slug, or the product\'s uniqueId. A UUID-shaped value is resolved as an id only."}]}},"/products/{slug}/access":{"get":{"operationId":"listProductAccess","tags":["Product access"],"summary":"List product access grants","description":"Lists the explicit member grants recorded on a product, plus the product\'s current `isPrivate` state. Read the two together: grants are stored regardless of privacy, so a public product (`isPrivate: false`) is readable by every workspace member even when `access` comes back empty, and the grant list only becomes an access-control list once `isPrivate` is true. Entries are ordered by when each member joined the workspace, oldest first, then paginated in memory. `access[].id` is the workspace member id - the same id space as PATCH /members/{id} and the grant/revoke routes below - not the user id; the user id is on `access[].user.id`.","responses":{"200":{"description":"List product access grants succeeded.","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","const":true},"code":{"type":"integer","example":200},"message":{"type":"string","example":"OK"},"error":{"type":"null"},"data":{"type":"object","properties":{"access":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","description":"Workspace member id. Pass this as {memberId} to the grant and revoke routes."},"user":{"type":["object","null"],"properties":{"id":{"type":"string"},"name":{"type":"string"},"email":{"type":"string"},"avatar":{"type":["string","null"]}},"required":["id","name","email","avatar"]}},"required":["id","user"]}},"isPrivate":{"type":"boolean","description":"When false, every workspace member can reach the product regardless of what `access` contains."},"pagination":{"$ref":"#/components/schemas/Pagination"}},"required":["access","isPrivate","pagination"]},"_req":{"type":"object","properties":{"reqId":{"type":"string"},"resTime":{"type":["integer","null"]}}}},"required":["success","code","message","error","data"]}}}}
1,"400":{"description":"`request.invalid_pagination` - `limit` or `offset` is not a whole number, or `limit` falls outside 1-100.","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","const":false},"code":{"type":"integer","example":400},"message":{"type":"string","example":"Something went wrong."},"error":{"$ref":"#/components/schemas/ApiError"},"data":{"type":"null"},"_req":{"type":"object","properties":{"reqId":{"type":"string"},"resTime":{"type":["integer","null"]}}}},"required":["success","code","message","error","data"]}}}},"401":{"description":"Missing, malformed, revoked or non-member API key (`auth.api_key_*`).","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","const":false},"code":{"type":"integer","example":400},"message":{"type":"string","example":"Something went wrong."},"error":{"$ref":"#/components/schemas/ApiError"},"data":{"type":"null"},"_req":{"type":"object","properties":{"reqId":{"type":"string"},"resTime":{"type":["integer","null"]}}}},"required":["success","code","message","error","data"]}}}},"403":{"description":"`auth.scope_missing` - the key lacks product_access:read.","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","const":false},"code":{"type":"integer","example":400},"message":{"type":"string","example":"Something went wrong."},"error":{"$ref":"#/components/schemas/ApiError"},"data":{"type":"null"},"_req":{"type":"object","properties":{"reqId":{"type":"string"},"resTime":{"type":["integer","null"]}}}},"required":["success","code","message","error","data"]}}}},"404":{"description":"`product.not_found` - no product matches, or it is private and the key owner has no grant.","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","const":false},"code":{"type":"integer","example":400},"message":{"type":"string","example":"Something went wrong."},"error":{"$ref":"#/components/schemas/ApiError"},"data":{"type":"null"},"_req":{"type":"object","properties":{"reqId":{"type":"string"},"resTime":{"type":["integer","null"]}}}},"required":["success","code","message","error","data"]}}}},"500":{"description":"Unexpected server error (`server.error`).","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","const":false},"code":{"type":"integer","example":400},"message":{"type":"string","example":"Something went wrong."},"error":{"$ref":"#/components/schemas/ApiError"},"data":{"type":"null"},"_req":{"type":"object","properties":{"reqId":{"type":"string"},"resTime":{"type":["integer","null"]}}}},"required":["success","code","message","error","data"]}}}}},"x-envless-scopes":["product-access:read"],"parameters":[{"name":"slug","in":"path","required":true,"schema":{"type":"string"},"description":"Product slug, or the product\'s uniqueId. A UUID-shaped value is resolved as an id only."},{"name":"limit","in":"query","schema":{"type":"integer","minimum":1,"maximum":100,"default":25},"description":"Rows per page."},{"name":"offset","in":"query","schema":{"type":"integer","minimum":0,"default":0},"description":"Rows to skip."}]}},"/products/{slug}/access/{memberId}":{"put":{"operationId":"grantProductAccess","tags":["Product access"],"summary":"Grant product access","description":"Grants one workspace member access to a product. Idempotent: re-granting an existing grant succeeds and still returns `granted: true`. Takes no request body - the two path segments are the whole input. `{memberId}` is a workspace member id (the `id` on GET /members and on GET /products/{slug}/access), not a user id; passing a user id returns 404 `member.not_found`. Granting on a public product is allowed and simply records the grant, which only starts mattering if the product is later switched to private. Returns 200, not 201, because the grant is upserted rather than created.","responses":{"200":{"description":"Grant product access succeeded.","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","const":true},"code":{"type":"integer","example":200},"message":{"type":"string","example":"OK"},"error":{"type":"null"},"data":{"type":"object","properties":{"id":{"type":"string","description":"Workspace member id that was granted."},"user":{"type":["object","null"],"properties":{"id":{"type":"string"},"name":{"type":"string"},"email":{"type":"string"},"avatar":{"type":["string","null"]}},"required":["id","name","email","avatar"]},"granted":{"type":"boolean","description":"Always true on success, including when the grant already existed."}},"required":["id","user","granted"]},"_req":{"type":"object","properties":{"reqId":{"type":"string"},"resTime":{"type":["integer","null"]}}}},"required":["success","code","message","error","data"]}}}},"401":{"description":"Missing, malformed, revoked or non-member API key (`auth.api_key_*`).","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","const":false},"code":{"type":"integer","example":400},"message":{"type":"string","example":"Something went wrong."},"error":{"$ref":"#/components/schemas/ApiError"},"data":{"type":"null"},"_req":{"type":"object","properties":{"reqId":{"type":"string"},"resTime":{"type":["integer","null"]}}}},"required":["success","code","message","error","data"]}}}},"402":{"description":"`product.locked` - the product sits beyond the plan\'s product allowance.","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","const":false},"code":{"type":"integer","example":400},"message":{"type":"string","example":"Something went wrong."},"error":{"$ref":"#/components/schemas/ApiError"},"data":{"type":"null"},"_req":{"type":"object","properties":{"reqId":{"type":"string"},"resTime":{"type":["integer","null"]}}}},"required":["success","code","message","error","data"]}}}},"403":{"description":"`auth.scope_missing` - the key lacks product_access:write.","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","const":false},"code":{"type":"integer","example":400},"message":{"type":"string","example":"Something went wrong."},"error":{"$ref":"#/components/schemas/ApiError"},"data":{"type":"null"},"_req":{"type":"object","properties":{"reqId":{"type":"string"},"resTime":{"type":["integer","null"]}}}},"required":["success","code","message","error","data"]}}}}
1,"404":{"description":"`member.not_found` - no live member of this workspace has that member id - most often because a user id was passed instead.","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","const":false},"code":{"type":"integer","example":400},"message":{"type":"string","example":"Something went wrong."},"error":{"$ref":"#/components/schemas/ApiError"},"data":{"type":"null"},"_req":{"type":"object","properties":{"reqId":{"type":"string"},"resTime":{"type":["integer","null"]}}}},"required":["success","code","message","error","data"]}}}},"409":{"description":"`product.not_found` - the product was deleted while the grant was being created.","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","const":false},"code":{"type":"integer","example":400},"message":{"type":"string","example":"Something went wrong."},"error":{"$ref":"#/components/schemas/ApiError"},"data":{"type":"null"},"_req":{"type":"object","properties":{"reqId":{"type":"string"},"resTime":{"type":["integer","null"]}}}},"required":["success","code","message","error","data"]}}}},"500":{"description":"Unexpected server error (`server.error`).","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","const":false},"code":{"type":"integer","example":400},"message":{"type":"string","example":"Something went wrong."},"error":{"$ref":"#/components/schemas/ApiError"},"data":{"type":"null"},"_req":{"type":"object","properties":{"reqId":{"type":"string"},"resTime":{"type":["integer","null"]}}}},"required":["success","code","message","error","data"]}}}}},"x-envless-scopes":["product-access:write"],"parameters":[{"name":"slug","in":"path","required":true,"schema":{"type":"string"},"description":"Product slug, or the product\'s uniqueId. A UUID-shaped value is resolved as an id only."},{"name":"memberId","in":"path","required":true,"schema":{"type":"string"},"description":"Workspace member id, the same id space as PATCH /members/{id}. Not a user id."}]},"delete":{"operationId":"revokeProductAccess","tags":["Product access"],"summary":"Revoke product access","description":"Removes a member\'s grant on a product. Idempotent and never 404s on a missing grant: if the member had no grant the call still returns 200 with `revoked: false` and the message \'That member did not have access to this product.\' Use `revoked` to tell the two apart. You cannot revoke your own key owner\'s access - that returns 403 `auth.self_mutation_forbidden`, which is what stops an integrator locking themselves out of a private product. Revoking on a public product removes the stored grant but changes nothing about who can read it.","responses":{"200":{"description":"Revoke product access succeeded.","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","const":true},"code":{"type":"integer","example":200},"message":{"type":"string","example":"OK"},"error":{"type":"null"},"data":{"type":"object","properties":{"id":{"type":"string","description":"Workspace member id that was targeted."},"revoked":{"type":"boolean","description":"True when a grant actually existed and was removed; false when the member already had no grant."}},"required":["id","revoked"]},"_req":{"type":"object","properties":{"reqId":{"type":"string"},"resTime":{"type":["integer","null"]}}}},"required":["success","code","message","error","data"]}}}},"401":{"description":"Missing, malformed, revoked or non-member API key (`auth.api_key_*`).","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","const":false},"code":{"type":"integer","example":400},"message":{"type":"string","example":"Something went wrong."},"error":{"$ref":"#/components/schemas/ApiError"},"data":{"type":"null"},"_req":{"type":"object","properties":{"reqId":{"type":"string"},"resTime":{"type":["integer","null"]}}}},"required":["success","code","message","error","data"]}}}},"402":{"description":"`product.locked` - the product sits beyond the plan\'s product allowance.","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","const":false},"code":{"type":"integer","example":400},"message":{"type":"string","example":"Something went wrong."},"error":{"$ref":"#/components/schemas/ApiError"},"data":{"type":"null"},"_req":{"type":"object","properties":{"reqId":{"type":"string"},"resTime":{"type":["integer","null"]}}}},"required":["success","code","message","error","data"]}}}},"403":{"description":"`auth.self_mutation_forbidden` - the member id resolves to the key owner\'s own membership.","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","const":false},"code":{"type":"integer","example":400},"message":{"type":"string","example":"Something went wrong."},"error":{"$ref":"#/components/schemas/ApiError"},"data":{"type":"null"},"_req":{"type":"object","properties":{"reqId":{"type":"string"},"resTime":{"type":["integer","null"]}}}},"required":["success","code","message","error","data"]}}}}
1,"404":{"description":"`member.not_found` - no live member of this workspace has that member id.","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","const":false},"code":{"type":"integer","example":400},"message":{"type":"string","example":"Something went wrong."},"error":{"$ref":"#/components/schemas/ApiError"},"data":{"type":"null"},"_req":{"type":"object","properties":{"reqId":{"type":"string"},"resTime":{"type":["integer","null"]}}}},"required":["success","code","message","error","data"]}}}},"500":{"description":"Unexpected server error (`server.error`).","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","const":false},"code":{"type":"integer","example":400},"message":{"type":"string","example":"Something went wrong."},"error":{"$ref":"#/components/schemas/ApiError"},"data":{"type":"null"},"_req":{"type":"object","properties":{"reqId":{"type":"string"},"resTime":{"type":["integer","null"]}}}},"required":["success","code","message","error","data"]}}}}},"x-envless-scopes":["product-access:write"],"parameters":[{"name":"slug","in":"path","required":true,"schema":{"type":"string"},"description":"Product slug, or the product\'s uniqueId. A UUID-shaped value is resolved as an id only."},{"name":"memberId","in":"path","required":true,"schema":{"type":"string"},"description":"Workspace member id, the same id space as PATCH /members/{id}. Not a user id."}]}},"/products/{slug}/duplicate":{"post":{"operationId":"duplicateProduct","tags":["Products"],"summary":"Duplicate a product","description":"Copies a product together with every project, environment and variable inside it. Ciphertext is copied verbatim, so the clone decrypts with the same workspace key. Names and slugs are derived from the source and are not predictable, so read them from the response. Refused for project-restricted keys, since the clone\'s projects are new ids outside the key\'s allowlist. Both the product cap and the project cap are enforced.","responses":{"201":{"description":"Duplicate a product succeeded.","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","const":true},"code":{"type":"integer","example":200},"message":{"type":"string","example":"OK"},"error":{"type":"null"},"data":{"$ref":"#/components/schemas/Product"},"_req":{"type":"object","properties":{"reqId":{"type":"string"},"resTime":{"type":["integer","null"]}}}},"required":["success","code","message","error","data"]}}}},"401":{"description":"Missing, malformed, revoked or non-member API key (`auth.api_key_*`).","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","const":false},"code":{"type":"integer","example":400},"message":{"type":"string","example":"Something went wrong."},"error":{"$ref":"#/components/schemas/ApiError"},"data":{"type":"null"},"_req":{"type":"object","properties":{"reqId":{"type":"string"},"resTime":{"type":["integer","null"]}}}},"required":["success","code","message","error","data"]}}}},"402":{"description":"`plan.upgrade_required` - duplicating would exceed the product or project allowance on your tier (Free 1/1, Dev 3/3, Team 15/15; Enterprise is unlimited).","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","const":false},"code":{"type":"integer","example":400},"message":{"type":"string","example":"Something went wrong."},"error":{"$ref":"#/components/schemas/ApiError"},"data":{"type":"null"},"_req":{"type":"object","properties":{"reqId":{"type":"string"},"resTime":{"type":["integer","null"]}}}},"required":["success","code","message","error","data"]}}}},"403":{"description":"`auth.key_project_restricted` - the key is limited to specific projects.","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","const":false},"code":{"type":"integer","example":400},"message":{"type":"string","example":"Something went wrong."},"error":{"$ref":"#/components/schemas/ApiError"},"data":{"type":"null"},"_req":{"type":"object","properties":{"reqId":{"type":"string"},"resTime":{"type":["integer","null"]}}}},"required":["success","code","message","error","data"]}}}}
1,"404":{"description":"`product.not_found` - no product matches the slug, or the key owner cannot see it.","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","const":false},"code":{"type":"integer","example":400},"message":{"type":"string","example":"Something went wrong."},"error":{"$ref":"#/components/schemas/ApiError"},"data":{"type":"null"},"_req":{"type":"object","properties":{"reqId":{"type":"string"},"resTime":{"type":["integer","null"]}}}},"required":["success","code","message","error","data"]}}}},"409":{"description":"`product.not_found` - the product was deleted while it was being duplicated.","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","const":false},"code":{"type":"integer","example":400},"message":{"type":"string","example":"Something went wrong."},"error":{"$ref":"#/components/schemas/ApiError"},"data":{"type":"null"},"_req":{"type":"object","properties":{"reqId":{"type":"string"},"resTime":{"type":["integer","null"]}}}},"required":["success","code","message","error","data"]}}}},"500":{"description":"Unexpected server error (`server.error`).","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","const":false},"code":{"type":"integer","example":400},"message":{"type":"string","example":"Something went wrong."},"error":{"$ref":"#/components/schemas/ApiError"},"data":{"type":"null"},"_req":{"type":"object","properties":{"reqId":{"type":"string"},"resTime":{"type":["integer","null"]}}}},"required":["success","code","message","error","data"]}}}}},"x-envless-scopes":["products:write","projects:write","variables:write"],"parameters":[{"name":"slug","in":"path","required":true,"schema":{"type":"string"}}]}},"/products/{slug}/projects":{"get":{"operationId":"listProductProjects","tags":["Products"],"summary":"List a product\'s projects","description":"Lists the projects inside one product. Equivalent to GET /projects?product={slug} but scoped by path, and it needs both products:read and projects:read. Project-restricted keys see only their allowed project ids within the product; a key restricted to projects in another product returns an empty page rather than 403. `pagination.totalCount` counts the rows the caller can see. Use this rather than GET /projects when you care about a single product, because project slugs are unique per product and the flat list can contain the same slug more than once.","responses":{"200":{"description":"List a product\'s projects succeeded.","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","const":true},"code":{"type":"integer","example":200},"message":{"type":"string","example":"OK"},"error":{"type":"null"},"data":{"type":"object","properties":{"projects":{"type":"array","items":{"$ref":"#/components/schemas/Project"}},"pagination":{"$ref":"#/components/schemas/Pagination"}},"required":["projects","pagination"]},"_req":{"type":"object","properties":{"reqId":{"type":"string"},"resTime":{"type":["integer","null"]}}}},"required":["success","code","message","error","data"]}}}},"400":{"description":"`request.invalid_pagination` - `limit` or `offset` is not a whole number, or `limit` falls outside 1-100.","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","const":false},"code":{"type":"integer","example":400},"message":{"type":"string","example":"Something went wrong."},"error":{"$ref":"#/components/schemas/ApiError"},"data":{"type":"null"},"_req":{"type":"object","properties":{"reqId":{"type":"string"},"resTime":{"type":["integer","null"]}}}},"required":["success","code","message","error","data"]}}}},"401":{"description":"Missing, malformed, revoked or non-member API key (`auth.api_key_*`).","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","const":false},"code":{"type":"integer","example":400},"message":{"type":"string","example":"Something went wrong."},"error":{"$ref":"#/components/schemas/ApiError"},"data":{"type":"null"},"_req":{"type":"object","properties":{"reqId":{"type":"string"},"resTime":{"type":["integer","null"]}}}},"required":["success","code","message","error","data"]}}}},"403":{"description":"`auth.scope_missing` - the key lacks products:read or projects:read.","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","const":false},"code":{"type":"integer","example":400},"message":{"type":"string","example":"Something went wrong."},"error":{"$ref":"#/components/schemas/ApiError"},"data":{"type":"null"},"_req":{"type":"object","properties":{"reqId":{"type":"string"},"resTime":{"type":["integer","null"]}}}},"required":["success","code","message","error","data"]}}}}
1,"404":{"description":"`product.not_found` - no product matches, or it is private and the key owner has no grant.","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","const":false},"code":{"type":"integer","example":400},"message":{"type":"string","example":"Something went wrong."},"error":{"$ref":"#/components/schemas/ApiError"},"data":{"type":"null"},"_req":{"type":"object","properties":{"reqId":{"type":"string"},"resTime":{"type":["integer","null"]}}}},"required":["success","code","message","error","data"]}}}},"500":{"description":"Unexpected server error (`server.error`).","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","const":false},"code":{"type":"integer","example":400},"message":{"type":"string","example":"Something went wrong."},"error":{"$ref":"#/components/schemas/ApiError"},"data":{"type":"null"},"_req":{"type":"object","properties":{"reqId":{"type":"string"},"resTime":{"type":["integer","null"]}}}},"required":["success","code","message","error","data"]}}}}},"x-envless-scopes":["products:read","projects:read"],"parameters":[{"name":"slug","in":"path","required":true,"schema":{"type":"string"},"description":"Product slug, or the product\'s uniqueId. A UUID-shaped value is resolved as an id only."},{"name":"limit","in":"query","schema":{"type":"integer","minimum":1,"maximum":100,"default":25},"description":"Rows per page."},{"name":"offset","in":"query","schema":{"type":"integer","minimum":0,"default":0},"description":"Rows to skip."},{"name":"search","in":"query","schema":{"type":"string"},"description":"Case-insensitive substring match against project name and slug."},{"name":"order","in":"query","schema":{"type":"string","enum":["name","asc","desc"],"default":"name"},"description":"`name` sorts A to Z, `asc` and `desc` sort oldest and newest first on createdAt. Any other value, including omitting it, sorts by name."}]}},"/projects":{"get":{"operationId":"listProjects","tags":["Projects"],"summary":"List projects","description":"Lists projects across every product the key owner can reach. **Project slugs are unique per product, not per workspace**, so this flat list can legitimately contain two projects with the same `slug` in different products - always key off `id`, or off the `product.slug` + `slug` pair. Pass `?product=<productSlug>` to narrow to one product. Project-restricted keys see only their allowed project ids; owners without `products.manage_private` see only public products plus products they hold a grant on. Every row carries its `product` object so you can disambiguate without a second call.","responses":{"200":{"description":"List projects succeeded.","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","const":true},"code":{"type":"integer","example":200},"message":{"type":"string","example":"OK"},"error":{"type":"null"},"data":{"type":"object","properties":{"projects":{"type":"array","items":{"$ref":"#/components/schemas/Project"}},"pagination":{"$ref":"#/components/schemas/Pagination"}},"required":["projects","pagination"]},"_req":{"type":"object","properties":{"reqId":{"type":"string"},"resTime":{"type":["integer","null"]}}}},"required":["success","code","message","error","data"]}}}},"400":{"description":"`request.invalid_pagination` - `limit` or `offset` is not a whole number, or `limit` falls outside 1-100.","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","const":false},"code":{"type":"integer","example":400},"message":{"type":"string","example":"Something went wrong."},"error":{"$ref":"#/components/schemas/ApiError"},"data":{"type":"null"},"_req":{"type":"object","properties":{"reqId":{"type":"string"},"resTime":{"type":["integer","null"]}}}},"required":["success","code","message","error","data"]}}}},"401":{"description":"Missing, malformed, revoked or non-member API key (`auth.api_key_*`).","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","const":false},"code":{"type":"integer","example":400},"message":{"type":"string","example":"Something went wrong."},"error":{"$ref":"#/components/schemas/ApiError"},"data":{"type":"null"},"_req":{"type":"object","properties":{"reqId":{"type":"string"},"resTime":{"type":["integer","null"]}}}},"required":["success","code","message","error","data"]}}}},"403":{"description":"`auth.scope_missing` - the key lacks projects:read.","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","const":false},"code":{"type":"integer","example":400},"message":{"type":"string","example":"Something went wrong."},"error":{"$ref":"#/components/schemas/ApiError"},"data":{"type":"null"},"_req":{"type":"object","properties":{"reqId":{"type":"string"},"resTime":{"type":["integer","null"]}}}},"required":["success","code","message","error","data"]}}}},"404":{"description":"`product.not_found` - `?product=` names a product that does not exist or that the key owner cannot reach. The error carries field `product`.","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","const":false},"code":{"type":"integer","example":400},"message":{"type":"string","example":"Something went wrong."},"error":{"$ref":"#/components/schemas/ApiError"},"data":{"type":"null"},"_req":{"type":"object","properties":{"reqId":{"type":"string"},"resTime":{"type":["integer","null"]}}}},"required":["success","code","message","error","data"]}}}},"500":{"description":"Unexpected server error (`server.error`).","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","const":false},"code":{"type":"integer","example":400},"message":{"type":"string","example":"Something went wrong."},"error":{"$ref":"#/components/schemas/ApiError"},"data":{"type":"null"},"_req":{"type":"object","properties":{"reqId":{"type":"string"},"resTime":{"type":["integer","null"]}}}},"required":["success","code","message","error","data"]}}}}},"x-envless-scopes":["projects:read"],"parameters":[{"name":"product","in":"query","schema":{"type":"string"},"description":"Filter to a single product. Accepts a product slug or a product uniqueId. An unknown or inaccessible value returns 404 `product.not_found` with field `product` - it does not silently return an empty page."},{"name":"limit","in":"query","schema":{"type":"integer","minimum":1,"maximum":100,"default":25},"description":"Rows per page."},{"name":"offset","in":"query","schema":{"type":"integer","minimum":0,"default":0},"description":"Rows to skip."},{"name":"search","in":"query","schema":{"type":"string"},"description":"Case-insensitive substring match against project name and slug."},{"name":"order","in":"query","schema":{"type":"string","enum":["name","asc","desc"],"default":"name"},"description":"`name` sorts A to Z, `asc` and `desc` sort oldest and newest first on createdAt. Any other value, including omitting it, sorts by name."}]},"post":{"operationId":"createProject","tags":["Projects"],"summary":"Create a project","description":"Creates a project inside a product. Both `name` and `slug` are required here (unlike POST /products, which derives the slug); the supplied slug is still slugified before validation. The target product is chosen by the `product` field **in the body**, which accepts a product **slug only** - a product uniqueId is not resolved and returns 404. Omit `product` and the workspace\'s `default` product is used, being created on the fly if it does not exist yet. Because slugs are unique per product, the same project slug
1can exist in several products; the 409 `project.slug_conflict` is scoped to the chosen product. The plan allowance is counted across the whole workspace, not per product, and is checked before the slug conflict.","responses":{"201":{"description":"Create a project succeeded.","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","const":true},"code":{"type":"integer","example":200},"message":{"type":"string","example":"OK"},"error":{"type":"null"},"data":{"$ref":"#/components/schemas/Project"},"_req":{"type":"object","properties":{"reqId":{"type":"string"},"resTime":{"type":["integer","null"]}}}},"required":["success","code","message","error","data"]}}}},"400":{"description":"`request.body_invalid` - `name` or `slug` is missing or not a string, or either fails length or slug-pattern validation.","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","const":false},"code":{"type":"integer","example":400},"message":{"type":"string","example":"Something went wrong."},"error":{"$ref":"#/components/schemas/ApiError"},"data":{"type":"null"},"_req":{"type":"object","properties":{"reqId":{"type":"string"},"resTime":{"type":["integer","null"]}}}},"required":["success","code","message","error","data"]}}}},"401":{"description":"Missing, malformed, revoked or non-member API key (`auth.api_key_*`).","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","const":false},"code":{"type":"integer","example":400},"message":{"type":"string","example":"Something went wrong."},"error":{"$ref":"#/components/schemas/ApiError"},"data":{"type":"null"},"_req":{"type":"object","properties":{"reqId":{"type":"string"},"resTime":{"type":["integer","null"]}}}},"required":["success","code","message","error","data"]}}}},"402":{"description":"`plan.upgrade_required` - the workspace already holds its plan\'s project allowance (Free 1, Dev 3, Team 15; Enterprise is unlimited and never hits this). `data` carries `{ limit, current }`.","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","const":false},"code":{"type":"integer","example":400},"message":{"type":"string","example":"Something went wrong."},"error":{"$ref":"#/components/schemas/ApiError"},"data":{"type":"null"},"_req":{"type":"object","properties":{"reqId":{"type":"string"},"resTime":{"type":["integer","null"]}}}},"required":["success","code","message","error","data"]}}}},"403":{"description":"`auth.scope_missing` - the key lacks projects:write.","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","const":false},"code":{"type":"integer","example":400},"message":{"type":"string","example":"Something went wrong."},"error":{"$ref":"#/components/schemas/ApiError"},"data":{"type":"null"},"_req":{"type":"object","properties":{"reqId":{"type":"string"},"resTime":{"type":["integer","null"]}}}},"required":["success","code","message","error","data"]}}}},"404":{"description":"`product.not_found` - `product` names a slug that does not exist in the workspace, or one the key owner has no grant on.","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","const":false},"code":{"type":"integer","example":400},"message":{"type":"string","example":"Something went wrong."},"error":{"$ref":"#/components/schemas/ApiError"},"data":{"type":"null"},"_req":{"type":"object","properties":{"reqId":{"type":"string"},"resTime":{"type":["integer","null"]}}}},"required":["success","code","message","error","data"]}}}},"409":{"description":"`product.not_found` - the product was deleted while the project was being created.","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","const":false},"code":{"type":"integer","example":400},"message":{"type":"string","example":"Something went wrong."},"error":{"$ref":"#/components/schemas/ApiError"},"data":{"type":"null"},"_req":{"type":"object","properties":{"reqId":{"type":"string"},"resTime":{"type":["integer","null"]}}}},"required":["success","code","message","error","data"]}}}},"500":{"description":"Unexpected server error (`server.error`).","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","const":false},"code":{"type":"integer","example":400},"message":{"type":"string","example":"Something went wrong."},"error":{"$ref":"#/components/schemas/ApiError"},"data":{"type":"null"},"_req":{"type":"object","properties":{"reqId":{"type":"string"},"resTime":{"type":["integer","null"]}}}},"required":["success","code","message","error","data"]}}}}},"x-envless-scopes":["projects:write"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"name":{"type":"string","minLength":3,"maxLength":50,"description":"Display name. Required.","example":"Billing"},"slug":{"type":"string","minLength":3,"maxLength":50,"pattern":"^[a-z0-9]+(?:-[a-z0-9]+)*$","description":"Required. Unique within the chosen product only. Slugified server-side before validation.","example":"billing"},"product":{"type":"string","description":"Product slug to create the project under. Slug only - ids are not accepted. Defaults to the workspace\'s `default` product, created on demand.","example":"internal-tools"}},"required":["name","slug"]}}}}}},"/projects/{slug}":{"get":{"operationId":"getProject","tags":["Projects"],"summary":"Get a project","description":"Fetches a project by slug or id. **Project slugs are unique per product, not per workspace.** If the slug exists in more than one product this returns 409 `project.ambiguous_product`; add `?product=<productSlug>` to pick one. A UUID-shaped path segment is tried as an id first and then falls back to a slug lookup, so ids never need the `product` hint. `?product=` is matched against product slugs only. Projects outside a restricted key\'s allowlist, and projects inside private products the key owner has no grant on, return 404 rather than 403.","responses":{"200":{"description":"Get a project succeeded.","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","const":true},"code":{"type":"integer","example":200},"message":{"type":"string","example":"OK"},"error":{"type":"null"},"data":{"$ref":"#/components/schemas/Project"},"_req":{"type":"object","properties":{"reqId":{"type":"string"},"resTime":{"type":["integer","null"]}}}},"required":["success","code","message","error","data"]}}}},"401":{"description":"Missing, malformed, revoked or non-member API key (`auth.api_key_*`).","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","const":false},"code":{"type":"integer","example":400},"message":{"type":"string","example":"Something went wrong."},"error":{"$ref":"#/components/schemas/ApiError"},"data":{"type":"null"},"_req":{"type":"object","properties":{"reqId":{"type":"string"},"resTime":{"type":["integer","null"]}}}},"required":["success","code","message","error","data"]}}}},"402":{"description":"`plan.upgrade_required` - the project sits beyond the plan\'s project allowance and is locked until you upgrade.","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","const":false},"code":{"type":"integer","example":400},"message":{"type":"string","example":"Something went wrong."},"error":{"$ref":"#/components/schemas/ApiError"},"data":{"type":"null"},"_req":{"type":"object","properties":{"reqId":{"type":"string"},"resTime":{"type":["integer","null"]}}}},"required":["success","code","message","error","data"]}}}},"403":{"description":"`auth.product_restricted` - the project\'s product is private and the key owner holds no grant on it.","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","const":false},"code":{"type":"integer","example":400},"message":{"type":"string","example":"Something went wrong."},"error":{"$ref":"#/components/schemas/ApiError"},"data":{"type":"null"},"_req":{"type":"object","properties":{"reqId":{"type":"string"},"resTime":{"type":["integer","null"]}}}},"required":["success","code","message","error","data"]}}}}
1,"404":{"description":"`project.not_found` - no project matches the slug or id in scope for this key. The controller omits the error code on this branch, so `error` is null and only the 404 status and message identify it.","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","const":false},"code":{"type":"integer","example":400},"message":{"type":"string","example":"Something went wrong."},"error":{"$ref":"#/components/schemas/ApiError"},"data":{"type":"null"},"_req":{"type":"object","properties":{"reqId":{"type":"string"},"resTime":{"type":["integer","null"]}}}},"required":["success","code","message","error","data"]}}}},"409":{"description":"`project.ambiguous_product` - the slug resolves to projects in more than one product; retry with `?product=<productSlug>`. The controller omits the error code on this branch, so `error` is null.","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","const":false},"code":{"type":"integer","example":400},"message":{"type":"string","example":"Something went wrong."},"error":{"$ref":"#/components/schemas/ApiError"},"data":{"type":"null"},"_req":{"type":"object","properties":{"reqId":{"type":"string"},"resTime":{"type":["integer","null"]}}}},"required":["success","code","message","error","data"]}}}},"500":{"description":"Unexpected server error (`server.error`).","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","const":false},"code":{"type":"integer","example":400},"message":{"type":"string","example":"Something went wrong."},"error":{"$ref":"#/components/schemas/ApiError"},"data":{"type":"null"},"_req":{"type":"object","properties":{"reqId":{"type":"string"},"resTime":{"type":["integer","null"]}}}},"required":["success","code","message","error","data"]}}}}},"x-envless-scopes":["projects:read"],"parameters":[{"name":"slug","in":"path","required":true,"schema":{"type":"string"},"description":"Project slug, or the project\'s uniqueId. A UUID-shaped value is resolved as an id first, then as a slug."},{"name":"product","in":"query","schema":{"type":"string"},"description":"Product slug used to disambiguate the project slug. Required whenever the same project slug exists in more than one product. Slug only - a product id is not resolved and yields 404."}]},"patch":{"operationId":"updateProject","tags":["Projects"],"summary":"Update a project","description":"Partial update of `name` and/or `slug`. **Project slugs are unique per product**, so the uniqueness check for a new slug runs inside the project\'s own product and `?product=<productSlug>` may be needed to resolve the project in the first place. Unlike the product route, the new slug is validated as-is rather than slugified, so send a slug that already matches `^[a-z0-9]+(?:-[a-z0-9]+)*$`. Projects cannot be moved between products over the API - there is no `product` field in the body. Icons are not settable here.","responses":{"200":{"description":"Update a project succeeded.","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","const":true},"code":{"type":"integer","example":200},"message":{"type":"string","example":"OK"},"error":{"type":"null"},"data":{"$ref":"#/components/schemas/Project"},"_req":{"type":"object","properties":{"reqId":{"type":"string"},"resTime":{"type":["integer","null"]}}}},"required":["success","code","message","error","data"]}}}}
1,"400":{"description":"`request.body_invalid` - `name` or `slug` fails length or slug-pattern validation. `error` is null on this branch.","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","const":false},"code":{"type":"integer","example":400},"message":{"type":"string","example":"Something went wrong."},"error":{"$ref":"#/components/schemas/ApiError"},"data":{"type":"null"},"_req":{"type":"object","properties":{"reqId":{"type":"string"},"resTime":{"type":["integer","null"]}}}},"required":["success","code","message","error","data"]}}}},"401":{"description":"Missing, malformed, revoked or non-member API key (`auth.api_key_*`).","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","const":false},"code":{"type":"integer","example":400},"message":{"type":"string","example":"Something went wrong."},"error":{"$ref":"#/components/schemas/ApiError"},"data":{"type":"null"},"_req":{"type":"object","properties":{"reqId":{"type":"string"},"resTime":{"type":["integer","null"]}}}},"required":["success","code","message","error","data"]}}}},"402":{"description":"`plan.upgrade_required` - the project is locked because it exceeds the plan\'s project allowance.","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","const":false},"code":{"type":"integer","example":400},"message":{"type":"string","example":"Something went wrong."},"error":{"$ref":"#/components/schemas/ApiError"},"data":{"type":"null"},"_req":{"type":"object","properties":{"reqId":{"type":"string"},"resTime":{"type":["integer","null"]}}}},"required":["success","code","message","error","data"]}}}},"403":{"description":"`auth.product_restricted` - the project\'s product is private and the key owner holds no grant on it.","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","const":false},"code":{"type":"integer","example":400},"message":{"type":"string","example":"Something went wrong."},"error":{"$ref":"#/components/schemas/ApiError"},"data":{"type":"null"},"_req":{"type":"object","properties":{"reqId":{"type":"string"},"resTime":{"type":["integer","null"]}}}},"required":["success","code","message","error","data"]}}}},"404":{"description":"`project.not_found` - no project matches in scope for this key. `error` is null on this branch.","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","const":false},"code":{"type":"integer","example":400},"message":{"type":"string","example":"Something went wrong."},"error":{"$ref":"#/components/schemas/ApiError"},"data":{"type":"null"},"_req":{"type":"object","properties":{"reqId":{"type":"string"},"resTime":{"type":["integer","null"]}}}},"required":["success","code","message","error","data"]}}}},"409":{"description":"`project.slug_conflict` - another project in the same product already owns the new slug. `error` is null on this branch.","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","const":false},"code":{"type":"integer","example":400},"message":{"type":"string","example":"Something went wrong."},"error":{"$ref":"#/components/schemas/ApiError"},"data":{"type":"null"},"_req":{"type":"object","properties":{"reqId":{"type":"string"},"resTime":{"type":["integer","null"]}}}},"required":["success","code","message","error","data"]}}}},"500":{"description":"Unexpected server error (`server.error`).","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","const":false},"code":{"type":"integer","example":400},"message":{"type":"string","example":"Something went wrong."},"error":{"$ref":"#/components/schemas/ApiError"},"data":{"type":"null"},"_req":{"type":"object","properties":{"reqId":{"type":"string"},"resTime":{"type":["integer","null"]}}}},"required":["success","code","message","error","data"]}}}}},"x-envless-scopes":["projects:write"],"parameters":[{"name":"slug","in":"path","required":true,"schema":{"type":"string"},"description":"Project slug, or the project\'s uniqueId. A UUID-shaped value is resolved as an id first, then as a
1slug."},{"name":"product","in":"query","schema":{"type":"string"},"description":"Product slug used to disambiguate the project slug. Required whenever the same project slug exists in more than one product."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"name":{"type":"string","minLength":3,"maxLength":50,"example":"Billing"},"slug":{"type":"string","minLength":3,"maxLength":50,"pattern":"^[a-z0-9]+(?:-[a-z0-9]+)*$","description":"Unique within the project\'s product only. Validated as-is, not slugified.","example":"billing"}}}}}}},"delete":{"operationId":"deleteProject","tags":["Projects"],"summary":"Delete a project","description":"Soft-deletes a project along with everything under it, in one transaction: its environments and every variable in them. **Project slugs are unique per product**, so pass `?product=<productSlug>` when the slug is ambiguous; a 409 here means the delete did not happen, not that it half-happened. There is no has-children guard and no undo over the API: a project with environments and variables is deleted without complaint. The payload is a tombstone plus a count of what the cascade removed, not the full Project schema.","responses":{"200":{"description":"Delete a project succeeded.","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","const":true},"code":{"type":"integer","example":200},"message":{"type":"string","example":"OK"},"error":{"type":"null"},"data":{"type":"object","properties":{"id":{"type":"string"},"name":{"type":"string"},"slug":{"type":"string"},"deletedEnvironments":{"type":"integer"},"deletedVariables":{"type":"integer"}},"required":["id","name","slug","deletedEnvironments","deletedVariables"]},"_req":{"type":"object","properties":{"reqId":{"type":"string"},"resTime":{"type":["integer","null"]}}}},"required":["success","code","message","error","data"]}}}},"401":{"description":"Missing, malformed, revoked or non-member API key (`auth.api_key_*`).","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","const":false},"code":{"type":"integer","example":400},"message":{"type":"string","example":"Something went wrong."},"error":{"$ref":"#/components/schemas/ApiError"},"data":{"type":"null"},"_req":{"type":"object","properties":{"reqId":{"type":"string"},"resTime":{"type":["integer","null"]}}}},"required":["success","code","message","error","data"]}}}},"402":{"description":"`plan.upgrade_required` - the project is locked because it exceeds the plan\'s project allowance.","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","const":false},"code":{"type":"integer","example":400},"message":{"type":"string","example":"Something went wrong."},"error":{"$ref":"#/components/schemas/ApiError"},"data":{"type":"null"},"_req":{"type":"object","properties":{"reqId":{"type":"string"},"resTime":{"type":["integer","null"]}}}},"required":["success","code","message","error","data"]}}}},"403":{"description":"`auth.product_restricted` - the project\'s product is private and the key owner holds no grant on it.","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","const":false},"code":{"type":"integer","example":400},"message":{"type":"string","example":"Something went wrong."},"error":{"$ref":"#/components/schemas/ApiError"},"data":{"type":"null"},"_req":{"type":"object","properties":{"reqId":{"type":"string"},"resTime":{"type":["integer","null"]}}}},"required":["success","code","message","error","data"]}}}},"404":{"description":"`project.not_found` - no project matches in scope for this key. `error` is null on this branch.","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","const":false},"code":{"type":"integer","example":400},"message":{"type":"string","example":"Something went wrong."},"error":{"$ref":"#/components/schemas/ApiError"},"data":{"type":"null"},"_req":{"type":"object","properties":{"reqId":{"type":"string"},"resTime":{"type":["integer","null"]}}}},"required":["success","code","message","error","data"]}}}},"409":{"description":"`project.ambiguous_product` - the slug resolves to projects in more than one product; retry with `?product=<productSlug>`. `error` is null on this branch.","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","const":false},"code":{"type":"integer","example":400},"message":{"type":"string","example":"Something went wrong."},"error":{"$ref":"#/components/schemas/ApiError"},"data":{"type":"null"},"_req":{"type":"object","properties":{"reqId":{"type":"string"},"resTime":{"type":["integer","null"]}}}},"required":["success","code","message","error","data"]}}}},"500":{"description":"Unexpected server error (`server.error`).","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","const":false},"code":{"type":"integer","example":400},"message":{"type":"string","example":"Something went wrong."},"error":{"$ref":"#/components/schemas/ApiError"},"data":{"type":"null"},"_req":{"type":"object","properties":{"reqId":{"type":"string"},"resTime":{"type":["integer","null"]}}}},"required":["success","code","message","error","data"]}}}}},"x-envless-scopes":["projects:write"],"parameters":[{"name":"slug","in":"path","required":true,"schema":{"type":"string"},"description":"Project slug, or the project\'s uniqueId. A UUID-shaped value is resolved as an id first, then as a
1slug."},{"name":"product","in":"query","schema":{"type":"string"},"description":"Product slug used to disambiguate the project slug. Required whenever the same project slug exists in more than one product."}]}},"/projects/{slug}/duplicate":{"post":{"operationId":"duplicateProject","tags":["Projects"],"summary":"Duplicate a project","description":"Deep-copies a project into the same product: every environment and every variable, ciphertext included, in one transaction. Takes no request body. The copy is named `<name> (Copy)` (truncated to 50 characters) with a slug derived from that name and suffixed `-2`, `-3`, ... until it is free inside the product; after enough collisions a random 6-character suffix is used instead. **Refused outright for project-restricted keys** with 403 `auth.key_project_restricted`, because the new project could not be covered by the key\'s allowlist. Needs both projects:write and variables:write. The workspace project allowance is checked before any copying happens, so a 402/409 leaves nothing behind. **Project slugs are unique per product**, so pass `?product=<productSlug>` when the source slug is ambiguous.","responses":{"201":{"description":"Duplicate a project succeeded.","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","const":true},"code":{"type":"integer","example":200},"message":{"type":"string","example":"OK"},"error":{"type":"null"},"data":{"$ref":"#/components/schemas/Project"},"_req":{"type":"object","properties":{"reqId":{"type":"string"},"resTime":{"type":["integer","null"]}}}},"required":["success","code","message","error","data"]}}}},"401":{"description":"Missing, malformed, revoked or non-member API key (`auth.api_key_*`).","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","const":false},"code":{"type":"integer","example":400},"message":{"type":"string","example":"Something went wrong."},"error":{"$ref":"#/components/schemas/ApiError"},"data":{"type":"null"},"_req":{"type":"object","properties":{"reqId":{"type":"string"},"resTime":{"type":["integer","null"]}}}},"required":["success","code","message","error","data"]}}}},"402":{"description":"`plan.upgrade_required` - the workspace already holds its plan\'s project allowance. `data` carries `{ limit, current }`.","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","const":false},"code":{"type":"integer","example":400},"message":{"type":"string","example":"Something went wrong."},"error":{"$ref":"#/components/schemas/ApiError"},"data":{"type":"null"},"_req":{"type":"object","properties":{"reqId":{"type":"string"},"resTime":{"type":["integer","null"]}}}},"required":["success","code","message","error","data"]}}}},"403":{"description":"`auth.scope_missing` - the key lacks projects:write or variables:write.","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","const":false},"code":{"type":"integer","example":400},"message":{"type":"string","example":"Something went wrong."},"error":{"$ref":"#/components/schemas/ApiError"},"data":{"type":"null"},"_req":{"type":"object","properties":{"reqId":{"type":"string"},"resTime":{"type":["integer","null"]}}}},"required":["success","code","message","error","data"]}}}},"404":{"description":"`project.not_found` - no project matches in scope for this key.","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","const":false},"code":{"type":"integer","example":400},"message":{"type":"string","example":"Something went wrong."},"error":{"$ref":"#/components/schemas/ApiError"},"data":{"type":"null"},"_req":{"type":"object","properties":{"reqId":{"type":"string"},"resTime":{"type":["integer","null"]}}}},"required":["success","code","message","error","data"]}}}},"409":{"description":"`product.not_found` - the product was deleted while the project was being duplicated.","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","const":false},"code":{"type":"integer","example":400},"message":{"type":"string","example":"Something went wrong."},"error":{"$ref":"#/components/schemas/ApiError"},"data":{"type":"null"},"_req":{"type":"object","properties":{"reqId":{"type":"string"},"resTime":{"type":["integer","null"]}}}},"required":["success","code","message","error","data"]}}}},"500":{"description":"Unexpected server error (`server.error`).","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","const":false},"code":{"type":"integer","example":400},"message":{"type":"string","example":"Something went wrong."},"error":{"$ref":"#/components/schemas/ApiError"},"data":{"type":"null"},"_req":{"type":"object","properties":{"reqId":{"type":"string"},"resTime":{"type":["integer","null"]}}}},"required":["success","code","message","error","data"]}}}}},"x-envless-scopes":["projects:write","variables:write"],"parameters":[{"name":"slug","in":"path","required":true,"schema":{"type":"string"},"description":"Slug or uniqueId of the project to copy. A UUID-shaped value is resolved as an id first, then as a
1slug."},{"name":"product","in":"query","schema":{"type":"string"},"description":"Product slug used to disambiguate the project slug. Required whenever the same project slug exists in more than one product."}]}},"/projects/{slug}/environments":{"get":{"operationId":"listEnvironments","tags":["Environments"],"summary":"List a project\'s environments","description":"Lists the environments in one project, sorted by `name` A to Z. **Project slugs are unique per product**, so pass `?product=<productSlug>` whenever the project slug exists in more than one product, otherwise the call fails with 409 before it ever looks at environments. The rows here are trimmed: they carry `id`, `name`, `slug`, `projectId` and `createdAt` only, with no `exposed` and no `updatedAt`. Read `exposed` from a PATCH response, or from the dashboard.","responses":{"200":{"description":"List a project\'s environments succeeded.","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","const":true},"code":{"type":"integer","example":200},"message":{"type":"string","example":"OK"},"error":{"type":"null"},"data":{"type":"object","properties":{"environments":{"type":"array","items":{"$ref":"#/components/schemas/Environment"}},"pagination":{"$ref":"#/components/schemas/Pagination"}},"required":["environments","pagination"]},"_req":{"type":"object","properties":{"reqId":{"type":"string"},"resTime":{"type":["integer","null"]}}}},"required":["success","code","message","error","data"]}}}},"400":{"description":"`request.invalid_pagination` - `limit` or `offset` is not a whole number, or `limit` falls outside 1-100.","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","const":false},"code":{"type":"integer","example":400},"message":{"type":"string","example":"Something went wrong."},"error":{"$ref":"#/components/schemas/ApiError"},"data":{"type":"null"},"_req":{"type":"object","properties":{"reqId":{"type":"string"},"resTime":{"type":["integer","null"]}}}},"required":["success","code","message","error","data"]}}}},"401":{"description":"Missing, malformed, revoked or non-member API key (`auth.api_key_*`).","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","const":false},"code":{"type":"integer","example":400},"message":{"type":"string","example":"Something went wrong."},"error":{"$ref":"#/components/schemas/ApiError"},"data":{"type":"null"},"_req":{"type":"object","properties":{"reqId":{"type":"string"},"resTime":{"type":["integer","null"]}}}},"required":["success","code","message","error","data"]}}}},"402":{"description":"`plan.upgrade_required` - the project is locked because it exceeds the plan\'s project allowance.","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","const":false},"code":{"type":"integer","example":400},"message":{"type":"string","example":"Something went wrong."},"error":{"$ref":"#/components/schemas/ApiError"},"data":{"type":"null"},"_req":{"type":"object","properties":{"reqId":{"type":"string"},"resTime":{"type":["integer","null"]}}}},"required":["success","code","message","error","data"]}}}},"403":{"description":"`auth.product_restricted` - the project\'s product is private and the key owner holds no grant on it.","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","const":false},"code":{"type":"integer","example":400},"message":{"type":"string","example":"Something went wrong."},"error":{"$ref":"#/components/schemas/ApiError"},"data":{"type":"null"},"_req":{"type":"object","properties":{"reqId":{"type":"string"},"resTime":{"type":["integer","null"]}}}},"required":["success","code","message","error","data"]}}}},"404":{"description":"`project.not_found` - no project matches in scope for this key. `error` is null on this branch.","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","const":false},"code":{"type":"integer","example":400},"message":{"type":"string","example":"Something went wrong."},"error":{"$ref":"#/components/schemas/ApiError"},"data":{"type":"null"},"_req":{"type":"object","properties":{"reqId":{"type":"string"},"resTime":{"type":["integer","null"]}}}},"required":["success","code","message","error","data"]}}}},"409":{"description":"`project.ambiguous_product` - the project slug resolves to projects in more than one product; retry with `?product=<productSlug>`. `error` is null on this branch.","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","const":false},"code":{"type":"integer","example":400},"message":{"type":"string","example":"Something went wrong."},"error":{"$ref":"#/components/schemas/ApiError"},"data":{"type":"null"},"_req":{"type":"object","properties":{"reqId":{"type":"string"},"resTime":{"type":["integer","null"]}}}},"required":["success","code","message","error","data"]}}}},"500":{"description":"Unexpected server error (`server.error`).","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","const":false},"code":{"type":"integer","example":400},"message":{"type":"string","example":"Something went wrong."},"error":{"$ref":"#/components/schemas/ApiError"},"data":{"type":"null"},"_req":{"type":"object","properties":{"reqId":{"type":"string"},"resTime":{"type":["integer","null"]}}}},"required":["success","code","message","error","data"]}}}}},"x-envless-scopes":["environments:read"],"parameters":[{"name":"slug","in":"path","required":true,"schema":{"type":"string"},"description":"Project slug, or the project\'s uniqueId. A UUID-shaped value is resolved as an id first, then as a
1slug."},{"name":"product","in":"query","schema":{"type":"string"},"description":"Product slug used to disambiguate the project slug. Required whenever the same project slug exists in more than one product."},{"name":"limit","in":"query","schema":{"type":"integer","minimum":1,"maximum":100,"default":25},"description":"Rows per page."},{"name":"offset","in":"query","schema":{"type":"integer","minimum":0,"default":0},"description":"Rows to skip."},{"name":"search","in":"query","schema":{"type":"string"},"description":"Case-insensitive substring match against environment name and slug."},{"name":"order","in":"query","schema":{"type":"string","enum":["name","asc","desc"],"default":"name"},"description":"`name` sorts A to Z, `asc` and `desc` sort oldest and newest first on createdAt. Any other value, including omitting it, sorts by name."}]},"post":{"operationId":"createEnvironment","tags":["Environments"],"summary":"Create an environment","description":"Creates an environment in a project. Both `name` and `slug` are required; the slug is slugified server-side before validation and must be unique within the project. **Project slugs are unique per product**, so pass `?product=<productSlug>` when the project slug is ambiguous - note the body is parsed and validated *before* the project is resolved, so a malformed body returns 400 even when the project reference is also wrong. The environment allowance is counted **per project** (Free 2, Dev 3, Team 15, Enterprise unlimited), not per workspace like products and projects, and is checked before the slug conflict. `exposed` cannot be set over the API and always comes back `false` on this response even though the stored value may differ later.","responses":{"201":{"description":"Create an environment succeeded.","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","const":true},"code":{"type":"integer","example":200},"message":{"type":"string","example":"OK"},"error":{"type":"null"},"data":{"$ref":"#/components/schemas/Environment"},"_req":{"type":"object","properties":{"reqId":{"type":"string"},"resTime":{"type":["integer","null"]}}}},"required":["success","code","message","error","data"]}}}}
1,"400":{"description":"`request.body_invalid` - `name` or `slug` is missing or not a string, or either fails length or slug-pattern validation.","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","const":false},"code":{"type":"integer","example":400},"message":{"type":"string","example":"Something went wrong."},"error":{"$ref":"#/components/schemas/ApiError"},"data":{"type":"null"},"_req":{"type":"object","properties":{"reqId":{"type":"string"},"resTime":{"type":["integer","null"]}}}},"required":["success","code","message","error","data"]}}}},"401":{"description":"Missing, malformed, revoked or non-member API key (`auth.api_key_*`).","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","const":false},"code":{"type":"integer","example":400},"message":{"type":"string","example":"Something went wrong."},"error":{"$ref":"#/components/schemas/ApiError"},"data":{"type":"null"},"_req":{"type":"object","properties":{"reqId":{"type":"string"},"resTime":{"type":["integer","null"]}}}},"required":["success","code","message","error","data"]}}}},"402":{"description":"`plan.upgrade_required` - the project already holds its plan\'s environment allowance (Free 2, Dev 3, Team 15 per project; Enterprise is unlimited and never hits this). `data` carries `{ limit, current }`.","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","const":false},"code":{"type":"integer","example":400},"message":{"type":"string","example":"Something went wrong."},"error":{"$ref":"#/components/schemas/ApiError"},"data":{"type":"null"},"_req":{"type":"object","properties":{"reqId":{"type":"string"},"resTime":{"type":["integer","null"]}}}},"required":["success","code","message","error","data"]}}}},"403":{"description":"`auth.product_restricted` - the project\'s product is private and the key owner holds no grant on it.","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","const":false},"code":{"type":"integer","example":400},"message":{"type":"string","example":"Something went wrong."},"error":{"$ref":"#/components/schemas/ApiError"},"data":{"type":"null"},"_req":{"type":"object","properties":{"reqId":{"type":"string"},"resTime":{"type":["integer","null"]}}}},"required":["success","code","message","error","data"]}}}},"404":{"description":"`project.not_found` - no project matches in scope for this key.","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","const":false},"code":{"type":"integer","example":400},"message":{"type":"string","example":"Something went wrong."},"error":{"$ref":"#/components/schemas/ApiError"},"data":{"type":"null"},"_req":{"type":"object","properties":{"reqId":{"type":"string"},"resTime":{"type":["integer","null"]}}}},"required":["success","code","message","error","data"]}}}},"409":{"description":"`project.not_found` - the project was deleted while the environment was being created.","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","const":false},"code":{"type":"integer","example":400},"message":{"type":"string","example":"Something went wrong."},"error":{"$ref":"#/components/schemas/ApiError"},"data":{"type":"null"},"_req":{"type":"object","properties":{"reqId":{"type":"string"},"resTime":{"type":["integer","null"]}}}},"required":["success","code","message","error","data"]}}}},"500":{"description":"Unexpected server error (`server.error`).","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","const":false},"code":{"type":"integer","example":400},"message":{"type":"string","example":"Something went wrong."},"error":{"$ref":"#/components/schemas/ApiError"},"data":{"type":"null"},"_req":{"type":"object","properties":{"reqId":{"type":"string"},"resTime":{"type":["integer","null"]}}}},"required":["success","code","message","error","data"]}}}}},"x-envless-scopes":["environments:write"],"parameters":[{"name":"slug","in":"path","required":true,"schema":{"type":"string"},"description":"Project slug, or the project\'s uniqueId. A UUID-shaped value is resolved as an id first, then as a
1slug."},{"name":"product","in":"query","schema":{"type":"string"},"description":"Product slug used to disambiguate the project slug. Required whenever the same project slug exists in more than one product."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"name":{"type":"string","minLength":2,"maxLength":50,"description":"Display name. Required.","example":"Billing"},"slug":{"type":"string","minLength":2,"maxLength":50,"pattern":"^[a-z0-9]+(?:-[a-z0-9]+)*$","description":"Required. Unique within the project. Slugified server-side before validation.","example":"billing"}},"required":["name","slug"]}}}}}},"/projects/{slug}/environments/{environmentSlug}":{"get":{"operationId":"getEnvironment","tags":["Environments"],"summary":"Get an environment","description":"Fetches one environment inside a project. `{environmentSlug}` is a **slug only** - environment uniqueIds are not resolved on any of these routes and will 404. **Project slugs are unique per product**, so pass `?product=<productSlug>` when the project slug is ambiguous. Like the list route, the payload is trimmed: `id`, `name`, `slug`, `projectId`, `createdAt`, with no `exposed` and no `updatedAt`.","responses":{"200":{"description":"Get an environment succeeded.","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","const":true},"code":{"type":"integer","example":200},"message":{"type":"string","example":"OK"},"error":{"type":"null"},"data":{"$ref":"#/components/schemas/Environment"},"_req":{"type":"object","properties":{"reqId":{"type":"string"},"resTime":{"type":["integer","null"]}}}},"required":["success","code","message","error","data"]}}}},"401":{"description":"Missing, malformed, revoked or non-member API key (`auth.api_key_*`).","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","const":false},"code":{"type":"integer","example":400},"message":{"type":"string","example":"Something went wrong."},"error":{"$ref":"#/components/schemas/ApiError"},"data":{"type":"null"},"_req":{"type":"object","properties":{"reqId":{"type":"string"},"resTime":{"type":["integer","null"]}}}},"required":["success","code","message","error","data"]}}}},"402":{"description":"`plan.upgrade_required` - the project is locked because it exceeds the plan\'s project allowance.","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","const":false},"code":{"type":"integer","example":400},"message":{"type":"string","example":"Something went wrong."},"error":{"$ref":"#/components/schemas/ApiError"},"data":{"type":"null"},"_req":{"type":"object","properties":{"reqId":{"type":"string"},"resTime":{"type":["integer","null"]}}}},"required":["success","code","message","error","data"]}}}},"403":{"description":"`auth.product_restricted` - the project\'s product is private and the key owner holds no grant on it.","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","const":false},"code":{"type":"integer","example":400},"message":{"type":"string","example":"Something went wrong."},"error":{"$ref":"#/components/schemas/ApiError"},"data":{"type":"null"},"_req":{"type":"object","properties":{"reqId":{"type":"string"},"resTime":{"type":["integer","null"]}}}},"required":["success","code","message","error","data"]}}}},"404":{"description":"`environment.not_found` - no environment with that slug lives in the project. `error` is null on this branch.","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","const":false},"code":{"type":"integer","example":400},"message":{"type":"string","example":"Something went wrong."},"error":{"$ref":"#/components/schemas/ApiError"},"data":{"type":"null"},"_req":{"type":"object","properties":{"reqId":{"type":"string"},"resTime":{"type":["integer","null"]}}}},"required":["success","code","message","error","data"]}}}},"409":{"description":"`project.ambiguous_product` - the project slug resolves to projects in more than one product; retry with `?product=<productSlug>`. `error` is null on this branch.","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","const":false},"code":{"type":"integer","example":400},"message":{"type":"string","example":"Something went wrong."},"error":{"$ref":"#/components/schemas/ApiError"},"data":{"type":"null"},"_req":{"type":"object","properties":{"reqId":{"type":"string"},"resTime":{"type":["integer","null"]}}}},"required":["success","code","message","error","data"]}}}},"500":{"description":"Unexpected server error (`server.error`).","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","const":false},"code":{"type":"integer","example":400},"message":{"type":"string","example":"Something went wrong."},"error":{"$ref":"#/components/schemas/ApiError"},"data":{"type":"null"},"_req":{"type":"object","properties":{"reqId":{"type":"string"},"resTime":{"type":["integer","null"]}}}},"required":["success","code","message","error","data"]}}}}},"x-envless-scopes":["environments:read"],"parameters":[{"name":"slug","in":"path","required":true,"schema":{"type":"string"},"description":"Project slug, or the project\'s uniqueId. A UUID-shaped value is resolved as an id first, then as a
1slug."},{"name":"environmentSlug","in":"path","required":true,"schema":{"type":"string"},"description":"Environment slug, unique within the project. Ids are not accepted here."},{"name":"product","in":"query","schema":{"type":"string"},"description":"Product slug used to disambiguate the project slug. Required whenever the same project slug exists in more than one product."}]},"patch":{"operationId":"updateEnvironment","tags":["Environments"],"summary":"Update an environment","description":"Partial update of an environment\'s `name` and/or `slug`, addressed by its current slug. The new slug is validated as-is rather than slugified and must be free within the project. `exposed` is read-only over the API: sending it is silently ignored, and the value you get back is whatever is stored - this is the one environment route that returns the real `exposed` and `updatedAt`. **Project slugs are unique per product**, so pass `?product=<productSlug>` when the project slug is ambiguous.","responses":{"200":{"description":"Update an environment succeeded.","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","const":true},"code":{"type":"integer","example":200},"message":{"type":"string","example":"OK"},"error":{"type":"null"},"data":{"$ref":"#/components/schemas/Environment"},"_req":{"type":"object","properties":{"reqId":{"type":"string"},"resTime":{"type":["integer","null"]}}}},"required":["success","code","message","error","data"]}}}}
1,"400":{"description":"`request.body_invalid` - `name` or `slug` fails length or slug-pattern validation. `error` is null on this branch.","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","const":false},"code":{"type":"integer","example":400},"message":{"type":"string","example":"Something went wrong."},"error":{"$ref":"#/components/schemas/ApiError"},"data":{"type":"null"},"_req":{"type":"object","properties":{"reqId":{"type":"string"},"resTime":{"type":["integer","null"]}}}},"required":["success","code","message","error","data"]}}}},"401":{"description":"Missing, malformed, revoked or non-member API key (`auth.api_key_*`).","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","const":false},"code":{"type":"integer","example":400},"message":{"type":"string","example":"Something went wrong."},"error":{"$ref":"#/components/schemas/ApiError"},"data":{"type":"null"},"_req":{"type":"object","properties":{"reqId":{"type":"string"},"resTime":{"type":["integer","null"]}}}},"required":["success","code","message","error","data"]}}}},"402":{"description":"`plan.upgrade_required` - the project is locked because it exceeds the plan\'s project allowance.","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","const":false},"code":{"type":"integer","example":400},"message":{"type":"string","example":"Something went wrong."},"error":{"$ref":"#/components/schemas/ApiError"},"data":{"type":"null"},"_req":{"type":"object","properties":{"reqId":{"type":"string"},"resTime":{"type":["integer","null"]}}}},"required":["success","code","message","error","data"]}}}},"403":{"description":"`auth.product_restricted` - the project\'s product is private and the key owner holds no grant on it.","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","const":false},"code":{"type":"integer","example":400},"message":{"type":"string","example":"Something went wrong."},"error":{"$ref":"#/components/schemas/ApiError"},"data":{"type":"null"},"_req":{"type":"object","properties":{"reqId":{"type":"string"},"resTime":{"type":["integer","null"]}}}},"required":["success","code","message","error","data"]}}}},"404":{"description":"`environment.not_found` - no environment with that slug lives in the project. `error` is null on this branch.","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","const":false},"code":{"type":"integer","example":400},"message":{"type":"string","example":"Something went wrong."},"error":{"$ref":"#/components/schemas/ApiError"},"data":{"type":"null"},"_req":{"type":"object","properties":{"reqId":{"type":"string"},"resTime":{"type":["integer","null"]}}}},"required":["success","code","message","error","data"]}}}},"409":{"description":"`environment.slug_conflict` - another environment in the project already owns the new slug. `error` is null on this branch.","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","const":false},"code":{"type":"integer","example":400},"message":{"type":"string","example":"Something went wrong."},"error":{"$ref":"#/components/schemas/ApiError"},"data":{"type":"null"},"_req":{"type":"object","properties":{"reqId":{"type":"string"},"resTime":{"type":["integer","null"]}}}},"required":["success","code","message","error","data"]}}}},"500":{"description":"Unexpected server error (`server.error`).","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","const":false},"code":{"type":"integer","example":400},"message":{"type":"string","example":"Something went wrong."},"error":{"$ref":"#/components/schemas/ApiError"},"data":{"type":"null"},"_req":{"type":"object","properties":{"reqId":{"type":"string"},"resTime":{"type":["integer","null"]}}}},"required":["success","code","message","error","data"]}}}}},"x-envless-scopes":["environments:write"],"parameters":[{"name":"slug","in":"path","required":true,"schema":{"type":"string"},"description":"Project slug, or the project\'s uniqueId. A UUID-shaped value is resolved as an id first, then as a
1slug."},{"name":"environmentSlug","in":"path","required":true,"schema":{"type":"string"},"description":"Current environment slug. Ids are not accepted here."},{"name":"product","in":"query","schema":{"type":"string"},"description":"Product slug used to disambiguate the project slug. Required whenever the same project slug exists in more than one product."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"name":{"type":"string","minLength":2,"maxLength":50,"example":"Billing"},"slug":{"type":"string","minLength":2,"maxLength":50,"pattern":"^[a-z0-9]+(?:-[a-z0-9]+)*$","description":"Unique within the project. Validated as-is, not slugified.","example":"billing"}}}}}}},"delete":{"operationId":"deleteEnvironment","tags":["Environments"],"summary":"Delete an environment","description":"Soft-deletes an environment and everything under it in one transaction, including its variables, and takes its published versions out of reach with it. There is no guard on a non-empty environment and no undo over the API. Deleting frees a slot against the project\'s per-project environment allowance. **Project slugs are unique per product**, so pass `?product=<productSlug>` when the project slug is ambiguous. The payload is a tombstone, not the Environment schema.","responses":{"200":{"description":"Delete an environment succeeded.","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","const":true},"code":{"type":"integer","example":200},"message":{"type":"string","example":"OK"},"error":{"type":"null"},"data":{"type":"object","properties":{"id":{"type":"string"},"name":{"type":"string"},"slug":{"type":"string"},"projectId":{"type":"string"},"deletedVariables":{"type":"integer"}},"required":["id","name","slug","projectId","deletedVariables"]},"_req":{"type":"object","properties":{"reqId":{"type":"string"},"resTime":{"type":["integer","null"]}}}},"required":["success","code","message","error","data"]}}}},"401":{"description":"Missing, malformed, revoked or non-member API key (`auth.api_key_*`).","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","const":false},"code":{"type":"integer","example":400},"message":{"type":"string","example":"Something went wrong."},"error":{"$ref":"#/components/schemas/ApiError"},"data":{"type":"null"},"_req":{"type":"object","properties":{"reqId":{"type":"string"},"resTime":{"type":["integer","null"]}}}},"required":["success","code","message","error","data"]}}}},"402":{"description":"`plan.upgrade_required` - the project is locked because it exceeds the plan\'s project allowance.","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","const":false},"code":{"type":"integer","example":400},"message":{"type":"string","example":"Something went wrong."},"error":{"$ref":"#/components/schemas/ApiError"},"data":{"type":"null"},"_req":{"type":"object","properties":{"reqId":{"type":"string"},"resTime":{"type":["integer","null"]}}}},"required":["success","code","message","error","data"]}}}},"403":{"description":"`auth.product_restricted` - the project\'s product is private and the key owner holds no grant on it.","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","const":false},"code":{"type":"integer","example":400},"message":{"type":"string","example":"Something went wrong."},"error":{"$ref":"#/components/schemas/ApiError"},"data":{"type":"null"},"_req":{"type":"object","properties":{"reqId":{"type":"string"},"resTime":{"type":["integer","null"]}}}},"required":["success","code","message","error","data"]}}}},"404":{"description":"`environment.not_found` - no environment with that slug lives in the project. `error` is null on this branch.","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","const":false},"code":{"type":"integer","example":400},"message":{"type":"string","example":"Something went wrong."},"error":{"$ref":"#/components/schemas/ApiError"},"data":{"type":"null"},"_req":{"type":"object","properties":{"reqId":{"type":"string"},"resTime":{"type":["integer","null"]}}}},"required":["success","code","message","error","data"]}}}},"409":{"description":"`project.ambiguous_product` - the project slug resolves to projects in more than one product; retry with `?product=<productSlug>`. `error` is null on this branch.","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","const":false},"code":{"type":"integer","example":400},"message":{"type":"string","example":"Something went wrong."},"error":{"$ref":"#/components/schemas/ApiError"},"data":{"type":"null"},"_req":{"type":"object","properties":{"reqId":{"type":"string"},"resTime":{"type":["integer","null"]}}}},"required":["success","code","message","error","data"]}}}},"500":{"description":"Unexpected server error (`server.error`).","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","const":false},"code":{"type":"integer","example":400},"message":{"type":"string","example":"Something went wrong."},"error":{"$ref":"#/components/schemas/ApiError"},"data":{"type":"null"},"_req":{"type":"object","properties":{"reqId":{"type":"string"},"resTime":{"type":["integer","null"]}}}},"required":["success","code","message","error","data"]}}}}},"x-envless-scopes":["environments:write"],"parameters":[{"name":"slug","in":"path","required":true,"schema":{"type":"string"},"description":"Project slug, or the project\'s uniqueId. A UUID-shaped value is resolved as an id first, then as a
1slug."},{"name":"environmentSlug","in":"path","required":true,"schema":{"type":"string"},"description":"Environment slug. Ids are not accepted here."},{"name":"product","in":"query","schema":{"type":"string"},"description":"Product slug used to disambiguate the project slug. Required whenever the same project slug exists in more than one product."}]}},"/projects/{slug}/environments/{environmentSlug}/duplicate":{"post":{"operationId":"duplicateEnvironment","tags":["Environments"],"summary":"Duplicate an environment","description":"Copies an environment and all its variables, ciphertext included, into the same project in one transaction. Takes no request body. The copy is named `<name> (Copy)` (truncated to 50 characters) with a slug derived from that name and suffixed `-2`, `-3`, ... until free within the project, falling back to a random 6-character suffix after enough collisions. Needs both environments:write and variables:write. The per-project environment allowance is checked before any copying, so a 402/409 leaves nothing behind. Unlike the project duplicate route this is *not* blocked for project-restricted keys, because the copy stays inside a project the key already covers. `exposed` always comes back `false` on this response regardless of the source environment.","responses":{"201":{"description":"Duplicate an environment succeeded.","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","const":true},"code":{"type":"integer","example":200},"message":{"type":"string","example":"OK"},"error":{"type":"null"},"data":{"$ref":"#/components/schemas/Environment"},"_req":{"type":"object","properties":{"reqId":{"type":"string"},"resTime":{"type":["integer","null"]}}}},"required":["success","code","message","error","data"]}}}},"401":{"description":"Missing, malformed, revoked or non-member API key (`auth.api_key_*`).","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","const":false},"code":{"type":"integer","example":400},"message":{"type":"string","example":"Something went wrong."},"error":{"$ref":"#/components/schemas/ApiError"},"data":{"type":"null"},"_req":{"type":"object","properties":{"reqId":{"type":"string"},"resTime":{"type":["integer","null"]}}}},"required":["success","code","message","error","data"]}}}},"402":{"description":"`plan.upgrade_required` - the project already holds its plan\'s environment allowance, or the project itself is locked. `data` carries `{ limit, current }` in the allowance case.","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","const":false},"code":{"type":"integer","example":400},"message":{"type":"string","example":"Something went wrong."},"error":{"$ref":"#/components/schemas/ApiError"},"data":{"type":"null"},"_req":{"type":"object","properties":{"reqId":{"type":"string"},"resTime":{"type":["integer","null"]}}}},"required":["success","code","message","error","data"]}}}},"403":{"description":"`auth.product_restricted` - the project\'s product is private and the key owner holds no grant on it.","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","const":false},"code":{"type":"integer","example":400},"message":{"type":"string","example":"Something went wrong."},"error":{"$ref":"#/components/schemas/ApiError"},"data":{"type":"null"},"_req":{"type":"object","properties":{"reqId":{"type":"string"},"resTime":{"type":["integer","null"]}}}},"required":["success","code","message","error","data"]}}}},"404":{"description":"`environment.not_found` - no environment with that slug lives in the project.","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","const":false},"code":{"type":"integer","example":400},"message":{"type":"string","example":"Something went wrong."},"error":{"$ref":"#/components/schemas/ApiError"},"data":{"type":"null"},"_req":{"type":"object","properties":{"reqId":{"type":"string"},"resTime":{"type":["integer","null"]}}}},"required":["success","code","message","error","data"]}}}},"409":{"description":"`project.not_found` - the project was deleted while the environment was being duplicated.","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","const":false},"code":{"type":"integer","example":400},"message":{"type":"string","example":"Something went wrong."},"error":{"$ref":"#/components/schemas/ApiError"},"data":{"type":"null"},"_req":{"type":"object","properties":{"reqId":{"type":"string"},"resTime":{"type":["integer","null"]}}}},"required":["success","code","message","error","data"]}}}},"500":{"description":"Unexpected server error (`server.error`).","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","const":false},"code":{"type":"integer","example":400},"message":{"type":"string","example":"Something went wrong."},"error":{"$ref":"#/components/schemas/ApiError"},"data":{"type":"null"},"_req":{"type":"object","properties":{"reqId":{"type":"string"},"resTime":{"type":["integer","null"]}}}},"required":["success","code","message","error","data"]}}}}},"x-envless-scopes":["environments:write","variables:write"],"parameters":[{"name":"slug","in":"path","required":true,"schema":{"type":"string"},"description":"Project slug, or the project\'s uniqueId. A UUID-shaped value is resolved as an id first, then as a
1slug."},{"name":"environmentSlug","in":"path","required":true,"schema":{"type":"string"},"description":"Slug of the environment to copy. Ids are not accepted here."},{"name":"product","in":"query","schema":{"type":"string"},"description":"Product slug used to disambiguate the project slug. Required whenever the same project slug exists in more than one product."}]}},"/projects/{slug}/environments/{environmentSlug}/expose":{"post":{"operationId":"exposeEnvironment","tags":["Environments"],"summary":"Expose or unexpose an environment","description":"Toggles public exposure for one environment. An exposed environment serves its **encrypted** variables over a branded public URL, so anyone with the link gets ciphertext and still needs the workspace passphrase or key to read a value. Nothing is decrypted server-side.\\n\\nExposing is refused unless two independent flags line up: the workspace must have `virtualEnvsEnabled` on, set with `PATCH /workspace`, and the environment\'s product must not be private. Both are deliberate, so that a single accidental toggle cannot publish a feed.\\n\\nUnexposing with `{ \\"exposed\\": false }` needs neither flag and always succeeds, which makes it a safe kill switch. The public URL 404s uniformly the moment it lands, with no hint that the environment exists.\\n\\nThe project is resolved by slug or id. Pass `product` when the same project slug exists in more than one product.","responses":{"200":{"description":"Expose or unex
1pose an environment succeeded.","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","const":true},"code":{"type":"integer","example":200},"message":{"type":"string","example":"OK"},"error":{"type":"null"},"data":{"$ref":"#/components/schemas/Environment"},"_req":{"type":"object","properties":{"reqId":{"type":"string"},"resTime":{"type":["integer","null"]}}}},"required":["success","code","message","error","data"]}}}},"400":{"description":"`request.body_invalid` - `exposed` is missing or not a boolean.","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","const":false},"code":{"type":"integer","example":400},"message":{"type":"string","example":"Something went wrong."},"error":{"$ref":"#/components/schemas/ApiError"},"data":{"type":"null"},"_req":{"type":"object","properties":{"reqId":{"type":"string"},"resTime":{"type":["integer","null"]}}}},"required":["success","code","message","error","data"]}}}},"401":{"description":"Missing, malformed, revoked or non-member API key (`auth.api_key_*`).","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","const":false},"code":{"type":"integer","example":400},"message":{"type":"string","example":"Something went wrong."},"error":{"$ref":"#/components/schemas/ApiError"},"data":{"type":"null"},"_req":{"type":"object","properties":{"reqId":{"type":"string"},"resTime":{"type":["integer","null"]}}}},"required":["success","code","message","error","data"]}}}},"403":{"description":"`auth.product_restricted` - the key owner has no grant on the private product that owns the project.","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","const":false},"code":{"type":"integer","example":400},"message":{"type":"string","example":"Something went wrong."},"error":{"$ref":"#/components/schemas/ApiError"},"data":{"type":"null"},"_req":{"type":"object","properties":{"reqId":{"type":"string"},"resTime":{"type":["integer","null"]}}}},"required":["success","code","message","error","data"]}}}},"404":{"description":"`environment.not_found` - the project has no environment with that slug.","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","const":false},"code":{"type":"integer","example":400},"message":{"type":"string","example":"Something went wrong."},"error":{"$ref":"#/components/schemas/ApiError"},"data":{"type":"null"},"_req":{"type":"object","properties":{"reqId":{"type":"string"},"resTime":{"type":["integer","null"]}}}},"required":["success","code","message","error","data"]}}}},"409":{"description":"`environment.expose_private_product` - the owning product is private, which can never be exposed.","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","const":false},"code":{"type":"integer","example":400},"message":{"type":"string","example":"Something went wrong."},"error":{"$ref":"#/components/schemas/ApiError"},"data":{"type":"null"},"_req":{"type":"object","properties":{"reqId":{"type":"string"},"resTime":{"type":["integer","null"]}}}},"required":["success","code","message","error","data"]}}}},"500":{"description":"Unexpected server error (`server.error`).","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","const":false},"code":{"type":"integer","example":400},"message":{"type":"string","example":"Something went wrong."},"error":{"$ref":"#/components/schemas/ApiError"},"data":{"type":"null"},"_req":{"type":"object","properties":{"reqId":{"type":"string"},"resTime":{"type":["integer","null"]}}}},"required":["success","code","message","error","data"]}}}}},"x-envless-scopes":["environments:write"],"parameters":[{"name":"slug","in":"path","required":true,"schema":{"type":"string"},"description":"The project slug or id that owns the environment."},{"name":"environmentSlug","in":"path","required":true,"schema":{"type":"string"}
1,"description":"The environment slug to expose or unexpose."},{"name":"product","in":"query","schema":{"type":"string"},"description":"Disambiguates the project when the same slug exists in more than one product."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"exposed":{"type":"boolean","example":true,"description":"True to serve the environment\'s encrypted variables publicly, false to stop."}},"additionalProperties":false,"required":["exposed"]}}}}}},"/projects/{slug}/environments/{environmentSlug}/variables":{"get":{"operationId":"listVariables","tags":["Variables"],"summary":"List variables","description":"Lists the variables in one environment, sorted by `name` A to Z. Soft-deleted variables are excluded. Names come back with the casing they were stored with, and no two live variables in one environment can differ only in case.\\n\\n`value` and `defaultValue` come back exactly as they were stored, which means **ciphertext**. The server holds no key material and cannot decrypt or encrypt anything. Decrypt client-side with the workspace key. Rows written before the ciphertext rule was enforced may still be plaintext, so treat any value that does not start with `v1:` or `v2:` as legacy plaintext rather than assuming decryption failed.\\n\\nThe public list takes no search or sort parameters. Paginate with `limit` and `offset`.","responses":{"200":{"description":"List variables succeeded.","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","const":true},"code":{"type":"integer","example":200},"message":{"type":"string","example":"OK"},"error":{"type":"null"},"data":{"type":"object","properties":{"variables":{"type":"array","items":{"$ref":"#/components/schemas/Variable"}},"pagination":{"$ref":"#/components/schemas/Pagination"}},"required":["variables","pagination"]},"_req":{"type":"object","properties":{"reqId":{"type":"string"},"resTime":{"type":["integer","null"]}}}},"required":["success","code","message","error","data"]}}}},"400":{"description":"`request.invalid_pagination` - `limit` is not a whole number between 1 and 100, or `offset` is not a whole number of 0 or greater.","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","const":false},"code":{"type":"integer","example":400},"message":{"type":"string","example":"Something went wrong."},"error":{"$ref":"#/components/schemas/ApiError"},"data":{"type":"null"},"_req":{"type":"object","properties":{"reqId":{"type":"string"},"resTime":{"type":["integer","null"]}}}},"required":["success","code","message","error","data"]}}}},"401":{"description":"Missing, malformed, revoked or non-member API key (`auth.api_key_*`).","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","const":false},"code":{"type":"integer","example":400},"message":{"type":"string","example":"Something went wrong."},"error":{"$ref":"#/components/schemas/ApiError"},"data":{"type":"null"},"_req":{"type":"object","properties":{"reqId":{"type":"string"},"resTime":{"type":["integer","null"]}}}},"required":["success","code","message","error","data"]}}}},"402":{"description":"`plan.upgrade_required` - the project is locked because the workspace holds more projects than its plan allows. Locked projects refuse reads as well as writes until the plan is upgraded.","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","const":false},"code":{"type":"integer","example":400},"message":{"type":"string","example":"Something went wrong."},"error":{"$ref":"#/components/schemas/ApiError"},"data":{"type":"null"},"_req":{"type":"object","properties":{"reqId":{"type":"string"},"resTime":{"type":["integer","null"]}}}},"required":["success","code","message","error","data"]}}}},"403":{"description":"`auth.key_project_restricted` - the key is pinned to a project allowlist that does not contain this project, or `auth.product_restricted` when the key owner has no access to the private product the project sits in.","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","const":false},"code":{"type":"integer","example":400},"message":{"type":"string","example":"Something went wrong."},"error":{"$ref":"#/components/schemas/ApiError"},"data":{"type":"null"},"_req":{"type":"object","properties":{"reqId":{"type":"string"},"resTime":{"type":["integer","null"]}}}},"required":["success","code","message","error","data"]}}}}
1,"404":{"description":"`project.not_found` - no such project in the workspace, or `environment.not_found` when the environment slug does not exist in it. Both are returned with `error: null`, so branch on the status.","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","const":false},"code":{"type":"integer","example":400},"message":{"type":"string","example":"Something went wrong."},"error":{"$ref":"#/components/schemas/ApiError"},"data":{"type":"null"},"_req":{"type":"object","properties":{"reqId":{"type":"string"},"resTime":{"type":["integer","null"]}}}},"required":["success","code","message","error","data"]}}}},"409":{"description":"`project.ambiguous_product` - the project slug is not unique in the workspace. Retry with `?product=<productSlug>`.","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","const":false},"code":{"type":"integer","example":400},"message":{"type":"string","example":"Something went wrong."},"error":{"$ref":"#/components/schemas/ApiError"},"data":{"type":"null"},"_req":{"type":"object","properties":{"reqId":{"type":"string"},"resTime":{"type":["integer","null"]}}}},"required":["success","code","message","error","data"]}}}},"500":{"description":"Unexpected server error (`server.error`).","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","const":false},"code":{"type":"integer","example":400},"message":{"type":"string","example":"Something went wrong."},"error":{"$ref":"#/components/schemas/ApiError"},"data":{"type":"null"},"_req":{"type":"object","properties":{"reqId":{"type":"string"},"resTime":{"type":["integer","null"]}}}},"required":["success","code","message","error","data"]}}}}},"x-envless-scopes":["variables:read"],"parameters":[{"name":"slug","in":"path","required":true,"schema":{"type":"string"},"description":"Project slug, or the project\'s uniqueId (uuid v7). An id is tried first and falls back to a slug lookup."},{"name":"environmentSlug","in":"path","required":true,"schema":{"type":"string"},"description":"Environment slug. Only the slug is accepted here, an environment uniqueId will not resolve."},{"name":"product","in":"query","required":false,"schema":{"type":"string"},"description":"Product slug. Required only when the same project slug exists under more than one product, otherwise the request fails with 409 `project.ambiguous_product`."},{"name":"limit","in":"query","schema":{"type":"integer","minimum":1,"maximum":100,"default":25},"description":"Page size, 1 to 100."},{"name":"offset","in":"query","schema":{"type":"integer","minimum":0,"default":0},"description":"Rows to skip."}]},"post":{"operationId":"createVariable","tags":["Variables"],"summary":"Create a variable","description":"Creates one variable in an environment.\\n\\n**`value` must be ciphertext.** The server never sees plaintext, holds no key, and will not encrypt for you. Encrypt with the workspace key first, then send the result. Anything that does not start with `v1:` or `v2:` is rejected with 400 `variable.ciphertext_invalid` and `error.field: \\"value\\"`.\\n\\n**`defaultValue` is also ciphertext**, encrypted with the same workspace key and carrying the same `v1:`/`v2:` prefix. It is validated identically when present. Sending a plaintext `defaultValue` past any weaker path stores permanent plaintext that then propagates into every version snapshot taken afterwards, and into every rollback made from those snapshots.\\n\\nCiphertext is validated before the project and environment are resolved, so a malformed value against a project that does not exist returns 400, not 404.\\n\\n`isSecret` is accepted and stored but is not part of the response body.","responses":{"201":{"description":"Create a variable succeeded.","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","const":true},"code":{"type":"integer","example":200},"message":{"type":"string","example":"OK"},"error":{"type":"null"},"data":{"$ref":"#/components/schemas/Variable"},"_req":{"type":"object","properties":{"reqId":{"type":"string"},"resTime":{"type":["integer","null"]}}}},"required":["success","code","message","error","data"]}}}},"400":{"description":"`variable.ciphertext_invalid` - `value` or `defaultValue` does not start with `v1:` or `v2:`, with `error.field` naming the offender. Also 400 for `request.body_must_be_json`, `request.body_invali
1d` when `name` or `value` is missing or not a string, and `request.body_invalid` when the service rejects the name, value length (1 to 20000), type, visibility, required flag or an oversized defaultValue.","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","const":false},"code":{"type":"integer","example":400},"message":{"type":"string","example":"Something went wrong."},"error":{"$ref":"#/components/schemas/ApiError"},"data":{"type":"null"},"_req":{"type":"object","properties":{"reqId":{"type":"string"},"resTime":{"type":["integer","null"]}}}},"required":["success","code","message","error","data"]}}}},"401":{"description":"Missing, malformed, revoked or non-member API key (`auth.api_key_*`).","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","const":false},"code":{"type":"integer","example":400},"message":{"type":"string","example":"Something went wrong."},"error":{"$ref":"#/components/schemas/ApiError"},"data":{"type":"null"},"_req":{"type":"object","properties":{"reqId":{"type":"string"},"resTime":{"type":["integer","null"]}}}},"required":["success","code","message","error","data"]}}}},"402":{"description":"`plan.upgrade_required` - the project is locked because the workspace exceeds its plan\'s project limit.","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","const":false},"code":{"type":"integer","example":400},"message":{"type":"string","example":"Something went wrong."},"error":{"$ref":"#/components/schemas/ApiError"},"data":{"type":"null"},"_req":{"type":"object","properties":{"reqId":{"type":"string"},"resTime":{"type":["integer","null"]}}}},"required":["success","code","message","error","data"]}}}},"403":{"description":"`auth.key_project_restricted` - the key\'s project allowlist excludes this project, or `auth.product_restricted` for a private product the key owner cannot see.","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","const":false},"code":{"type":"integer","example":400},"message":{"type":"string","example":"Something went wrong."},"error":{"$ref":"#/components/schemas/ApiError"},"data":{"type":"null"},"_req":{"type":"object","properties":{"reqId":{"type":"string"},"resTime":{"type":["integer","null"]}}}},"required":["success","code","message","error","data"]}}}},"404":{"description":"`project.not_found` - the project does not exist, or `environment.not_found` for an unknown environment slug.","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","const":false},"code":{"type":"integer","example":400},"message":{"type":"string","example":"Something went wrong."},"error":{"$ref":"#/components/schemas/ApiError"},"data":{"type":"null"},"_req":{"type":"object","properties":{"reqId":{"type":"string"},"resTime":{"type":["integer","null"]}}}},"required":["success","code","message","error","data"]}}}},"409":{"description":"`environment.not_found` - the environment was deleted while the variable was being created, which a cascading product or project delete can do mid-request.","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","const":false},"code":{"type":"integer","example":400},"message":{"type":"string","example":"Something went wrong."},"error":{"$ref":"#/components/schemas/ApiError"},"data":{"type":"null"},"_req":{"type":"object","properties":{"reqId":{"type":"string"},"resTime":{"type":["integer","null"]}}}},"required":["success","code","message","error","data"]}}}},"500":{"description":"Unexpected server error (`server.error`).","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","const":false},"code":{"type":"integer","example":400},"message":{"type":"string","example":"Something went wrong."},"error":{"$ref":"#/components/schemas/ApiError"},"data":{"type":"null"},"_req":{"type":"object","properties":{"reqId":{"type":"string"},"resTime":{"type":["integer","null"]}}}},"required":["success","code","message","error","data"]}}}}},"x-envless-scopes":["variables:write"],"parameters":[{"name":"slug","in":"path","required":true,"schema":{"type":"string"},"description":"Project slug or project uniqueId."},{"name":"environmentSlug","in":"path","required":true,"schema":{"type":"string"}
1,"description":"Environment slug. A uniqueId will not resolve."},{"name":"product","in":"query","required":false,"schema":{"type":"string"},"description":"Product slug, to disambiguate a project slug shared across products."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"name":{"type":"string","minLength":1,"maxLength":100,"pattern":"^[A-Za-z_][A-Za-z0-9_]*$","example":"STRIPE_SECRET_KEY","description":"Variable name. Must match `^[A-Za-z_][A-Za-z0-9_]*$` and be 1 to 100 characters, the same rule the bulk and apply endpoints enforce. Lowercase is legal, and the name is stored and returned with exactly the casing you send, nothing upper-cases it. Uniqueness among the live variables of the environment is judged without regard to case, so `api_key` conflicts with an existing `API_KEY`."},"value":{"type":"string","minLength":1,"maxLength":20000,"pattern":"^v[12]:","description":"CIPHERTEXT. Must start with `v1:` or `v2:`. Encrypt client-side with the workspace key.","example":"v1:8Wm3kQ...ciphertext"},"type":{"type":"string","enum":["string","number","boolean"],"default":"string","example":"string"},"isSecret":{"type":"boolean","default":true,"description":"Stored, but never returned by any public read."},"visibility":{"type":"string","enum":["server","client"],"default":"server","example":"server"},"required":{"type":"boolean","default":false,"example":false},"defaultValue":{"type":["string","null"],"maxLength":20000,"pattern":"^v[12]:","description":"CIPHERTEXT, same workspace key and same `v1:`/`v2:` prefix as `value`. Send null or omit for none."}},"required":["name","value"]}}}}},"delete":{"operationId":"deleteVariables","tags":["Variables"],"summary":"Delete variables by name","description":"Bulk soft-deletes variables by name, matched without regard to case, so `api_key` deletes a live `API_KEY`. Takes a JSON body on DELETE, which some HTTP clients suppress by default.\\n\\nUnknown names are not an error. They come back in `notFound` and the rest are still deleted, so the call is idempotent enough to retry. If none of the names match, the response is still 200 with `count: 0` and every name in `notFound`.\\n\\nAt most 200 names per request. Deletes are soft, so the rows stay available to version snapshots taken earlier and to rollback.","responses":{"200":{"description":"Delete variables by name succeeded.","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","const":true},"code":{"type":"integer","example":200},"message":{"type":"string","example":"OK"},"error":{"type":"null"},"data":{"type":"object","properties":{"deleted":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string"},"name":{"type":"string","example":"STRIPE_SECRET_KEY"}},"required":["id","name"]}},"count":{"type":"integer","description":"Rows actually soft-deleted."},"notFound":{"type":"array","items":{"type":"string"},"description":"Names from the request that matched no live variable."}},"required":["deleted","count","notFound"]},"_req":{"type":"object","properties":{"reqId":{"type":"string"},"resTime":{"type":["integer","null"]}}}},"required":["success","code","message","error","data"]}}}}
1,"400":{"description":"`request.body_invalid` - the body is not JSON, `names` is missing, empty, contains a non-string or empty string, or holds more than 200 entries. These 400s are returned with `error: null`, only `message` explains them.","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","const":false},"code":{"type":"integer","example":400},"message":{"type":"string","example":"Something went wrong."},"error":{"$ref":"#/components/schemas/ApiError"},"data":{"type":"null"},"_req":{"type":"object","properties":{"reqId":{"type":"string"},"resTime":{"type":["integer","null"]}}}},"required":["success","code","message","error","data"]}}}},"401":{"description":"Missing, malformed, revoked or non-member API key (`auth.api_key_*`).","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","const":false},"code":{"type":"integer","example":400},"message":{"type":"string","example":"Something went wrong."},"error":{"$ref":"#/components/schemas/ApiError"},"data":{"type":"null"},"_req":{"type":"object","properties":{"reqId":{"type":"string"},"resTime":{"type":["integer","null"]}}}},"required":["success","code","message","error","data"]}}}},"402":{"description":"`plan.upgrade_required` - the project is locked by the plan\'s project limit.","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","const":false},"code":{"type":"integer","example":400},"message":{"type":"string","example":"Something went wrong."},"error":{"$ref":"#/components/schemas/ApiError"},"data":{"type":"null"},"_req":{"type":"object","properties":{"reqId":{"type":"string"},"resTime":{"type":["integer","null"]}}}},"required":["success","code","message","error","data"]}}}},"403":{"description":"`auth.key_project_restricted` - the key\'s project allowlist excludes this project, or `auth.product_restricted` for an inaccessible private product.","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","const":false},"code":{"type":"integer","example":400},"message":{"type":"string","example":"Something went wrong."},"error":{"$ref":"#/components/schemas/ApiError"},"data":{"type":"null"},"_req":{"type":"object","properties":{"reqId":{"type":"string"},"resTime":{"type":["integer","null"]}}}},"required":["success","code","message","error","data"]}}}},"404":{"description":"`project.not_found` - unknown project, or `environment.not_found` for an unknown environment slug. Returned with `error: null`.","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","const":false},"code":{"type":"integer","example":400},"message":{"type":"string","example":"Something went wrong."},"error":{"$ref":"#/components/schemas/ApiError"},"data":{"type":"null"},"_req":{"type":"object","properties":{"reqId":{"type":"string"},"resTime":{"type":["integer","null"]}}}},"required":["success","code","message","error","data"]}}}},"409":{"description":"`project.ambiguous_product` - the project slug exists under more than one product.","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","const":false},"code":{"type":"integer","example":400},"message":{"type":"string","example":"Something went wrong."},"error":{"$ref":"#/components/schemas/ApiError"},"data":{"type":"null"},"_req":{"type":"object","properties":{"reqId":{"type":"string"},"resTime":{"type":["integer","null"]}}}},"required":["success","code","message","error","data"]}}}},"500":{"description":"Unexpected server error (`server.error`).","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","const":false},"code":{"type":"integer","example":400},"message":{"type":"string","example":"Something went wrong."},"error":{"$ref":"#/components/schemas/ApiError"},"data":{"type":"null"},"_req":{"type":"object","properties":{"reqId":{"type":"string"},"resTime":{"type":["integer","null"]}}}},"required":["success","code","message","error","data"]}}}}},"x-envless-scopes":["variables:write"],"parameters":[{"name":"slug","in":"path","required":true,"schema":{"type":"string"},"description":"Project slug or project uniqueId."},{"name":"environmentSlug","in":"path","required":true,"schema":{"type":"string"}
1,"description":"Environment slug."},{"name":"product","in":"query","required":false,"schema":{"type":"string"},"description":"Product slug, to disambiguate a project slug shared across products."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"names":{"type":"array","minItems":1,"maxItems":200,"items":{"type":"string","minLength":1},"description":"Variable names to delete. Matching ignores case, so `api_key` deletes a live `API_KEY`. Names that match nothing come back in `notFound`.","example":["STRIPE_SECRET_KEY","SENTRY_DSN"]}},"required":["names"]}}}}}},"/projects/{slug}/environments/{environmentSlug}/variables/apply":{"post":{"operationId":"applyVariables","tags":["Variables"],"summary":"Apply a set of variable changes atomically","description":"The transactional way to sync an environment. **A sync client should use this instead of N separate create, update and delete calls.** Everything runs inside one database transaction behind a per-environment advisory lock, so the environment is never left half-written and two concurrent applies cannot interleave.\\n\\n**`baseline` is required and is how drift is detected.** Send the full set of variables you last read, as `{ uniqueId, name, updatedAt }` for every live variable in the environment, using the `id` and `updatedAt` you received from the list endpoint. Before touching anything, the server compares the baseline against the live rows and rejects the whole request with 409 `variable.baseline_drifted` if any live variable is missing from your baseline, any baseline entry no longer exists, or any `updatedAt` differs by even a millisecond. The drifted names are listed in `message`, sorted, and nowhere else. On a 409, re-read the environment and rebuild the change set. A partial baseline is not a partial check, it is guaranteed drift, because every live variable you omitted counts as drifted.\\n\\n`value` in `creates` and `updates` is **ciphertext** encrypted client-side with the workspace key. Gotcha: this endpoint does not run the `v1:`/`v2:` prefix check that `POST .../variables` runs, it only enforces a length of 1 to 20000. Plaintext sent here is stored as plaintext and then propagates into every later version snapshot. Validate the prefix in your client.\\n\\nApply is value-only and name-only. `creates` insert `name` and `value` and take the column defaults for type, isSecret, visibility, required and defaultValue. `updates` set `value` alone. There is no rename and no defaultValue path here, use `PATCH .../variables/{name}` or `PATCH /variables/{id}` for those. Names are compared without regard to case throughout apply, so a `creates` entry for `api_key` conflicts with a live `API_KEY` unless the same request deletes it.\\n\\nCaps: at most 1000 baseline entries, and at most 1000 items across `creates` plus `updates` plus `deletes` combined. At least one of the three must be non-empty.","responses":{"200":{"description":"Apply a set of variable changes atomically succeeded.","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","const":true},"code":{"type":"integer","example":200},"message":{"type":"string","example":"OK"},"error":{"type":"null"},"data":{"type":"object","properties":{"added":{"type":"integer"},"updated":{"type":"integer"},"removed":{"type":"integer"}},"required":["added","updated","removed"]},"_req":{"type":"object","properties":{"reqId":{"type":"string"},"resTime":{"type":["integer","null"]}}}},"required":["success","code","message","error","data"]}}}}
1,"400":{"description":"`request.body_invalid` - `baseline` is missing or not an array (`error.field: \\"baseline\\"`), all three change arrays are empty, the 1000 item cap is exceeded, an item has the wrong shape, or the body is not JSON (`request.body_must_be_json`). Also 400 `request.body_invalid` for a rejected name, a value outside 1 to 20000 characters, and, counterintuitively, for exceeding the plan\'s variable cap, whose message reads like a plan error but arrives as 400 rather than 402.","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","const":false},"code":{"type":"integer","example":400},"message":{"type":"string","example":"Something went wrong."},"error":{"$ref":"#/components/schemas/ApiError"},"data":{"type":"null"},"_req":{"type":"object","properties":{"reqId":{"type":"string"},"resTime":{"type":["integer","null"]}}}},"required":["success","code","message","error","data"]}}}},"401":{"description":"Missing, malformed, revoked or non-member API key (`auth.api_key_*`).","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","const":false},"code":{"type":"integer","example":400},"message":{"type":"string","example":"Something went wrong."},"error":{"$ref":"#/components/schemas/ApiError"},"data":{"type":"null"},"_req":{"type":"object","properties":{"reqId":{"type":"string"},"resTime":{"type":["integer","null"]}}}},"required":["success","code","message","error","data"]}}}},"402":{"description":"`plan.upgrade_required` - the project is locked because the workspace exceeds its plan\'s project limit.","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","const":false},"code":{"type":"integer","example":400},"message":{"type":"string","example":"Something went wrong."},"error":{"$ref":"#/components/schemas/ApiError"},"data":{"type":"null"},"_req":{"type":"object","properties":{"reqId":{"type":"string"},"resTime":{"type":["integer","null"]}}}},"required":["success","code","message","error","data"]}}}},"403":{"description":"`auth.key_project_restricted` - the key\'s project allowlist excludes this project, or `auth.product_restricted` for an inaccessible private product.","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","const":false},"code":{"type":"integer","example":400},"message":{"type":"string","example":"Something went wrong."},"error":{"$ref":"#/components/schemas/ApiError"},"data":{"type":"null"},"_req":{"type":"object","properties":{"reqId":{"type":"string"},"resTime":{"type":["integer","null"]}}}},"required":["success","code","message","error","data"]}}}},"404":{"description":"`project.not_found` - unknown project, or `environment.not_found` for an unknown environment slug.","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","const":false},"code":{"type":"integer","example":400},"message":{"type":"string","example":"Something went wrong."},"error":{"$ref":"#/components/schemas/ApiError"},"data":{"type":"null"},"_req":{"type":"object","properties":{"reqId":{"type":"string"},"resTime":{"type":["integer","null"]}}}},"required":["success","code","message","error","data"]}}}},"409":{"description":"`variable.baseline_drifted` - the environment changed under you. The drifted names are only in `message`. The same code is reused for two neighbouring conflicts, a `creates` name already taken by a variable you are not deleting, and an `updates` or `deletes` id that is no longer live, so read `message` to tell them apart. 409 `project.ambiguous_product` also lands on this status when the project slug is not unique.","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","const":false},"code":{"type":"integer","example":400},"message":{"type":"string","example":"Something went wrong."},"error":{"$ref":"#/components/schemas/ApiError"},"data":{"type":"null"},"_req":{"type":"object","properties":{"reqId":{"type":"string"},"resTime":{"type":["integer","null"]}}}},"required":["success","code","message","error","data"]}}}},"500":{"description":"Unexpected server error (`server.error`).","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","const":false},"code":{"type":"integer","example":400},"message":{"type":"string","example":"Something went wrong."},"error":{"$ref":"#/components/schemas/ApiError"},"data":{"type":"null"},"_req":{"type":"object","properties":{"reqId":{"type":"string"},"resTime":{"type":["integer","null"]}}}},"required":["success","code","message","error","data"]}}}}},"x-envless-scopes":["variables:write"],"parameters":[{"name":"slug","in":"path","required":true,"schema":{"type":"string"},"description":"Project slug or project uniqueId."},{"name":"environmentSlug","in":"path","required":true,"schema":{"type":"string"}
1,"description":"Environment slug."},{"name":"product","in":"query","required":false,"schema":{"type":"string"},"description":"Product slug, to disambiguate a project slug shared across products."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"baseline":{"type":"array","maxItems":1000,"description":"Every live variable as you last read it. May be empty only when the environment is genuinely empty. Omitting a live variable is drift.","items":{"type":"object","properties":{"uniqueId":{"type":"string","description":"The variable `id` from a read."},"name":{"type":"string","example":"STRIPE_SECRET_KEY","description":"Used only to name the variable in the drift message. Send it back exactly as you read it, no pattern is enforced here so a legacy name still round-trips."},"updatedAt":{"type":"string","format":"date-time","description":"Compared for exact millisecond equality against the live row."}},"required":["uniqueId","name","updatedAt"]}},"creates":{"type":"array","description":"New variables. Name must match `^[A-Za-z_][A-Za-z0-9_]*$` and be 1 to 100 characters, is stored with the casing you send, and must not repeat within the request. Repeats inside the request and collisions with live variables are judged without regard to case, so `api_key` collides with an existing `API_KEY` you are not deleting in the same request.","items":{"type":"object","properties":{"name":{"type":"string","minLength":1,"maxLength":100,"pattern":"^[A-Za-z_][A-Za-z0-9_]*$","example":"SENTRY_DSN","description":"Variable name. Stored as typed, compared without regard to case."},"value":{"type":"string","minLength":1,"maxLength":20000,"pattern":"^v[12]:","description":"CIPHERTEXT. Prefix not enforced server-side on this endpoint.","example":"v1:8Wm3kQ...ciphertext"}},"required":["name","value"]}},"updates":{"type":"array","description":"Value replacements. Nothing but `value` is written.","items":{"type":"object","properties":{"uniqueId":{"type":"string"},"value":{"type":"string","minLength":1,"maxLength":20000,"pattern":"^v[12]:","description":"CIPHERTEXT. Prefix not enforced server-side on this endpoint.","example":"v1:8Wm3kQ...ciphertext"}},"required":["uniqueId","value"]}},"deletes":{"type":"array","description":"Soft deletes by id. A name freed by a delete in the same request can be reused by a create in that request, including under a different casing.","items":{"type":"object","properties":{"uniqueId":{"type":"string"}},"required":["uniqueId"]}}},"required":["baseline"]}}}}}},"/projects/{slug}/environments/{environmentSlug}/variables/bulk":{"post":{"operationId":"createVariables","tags":["Variables"],"summary":"Create variables in bulk","description":"Creates up to 200 variables in one call. This endpoint is **partial success by design**: an item the server refuses is reported in `skipped` and the rest are still created, so always read `skipped` and `count` rather than trusting the status. A batch in which every single item is refused does not come back as a 201, it fails with a 4xx and the per-item reasons.\\n\\nAn item is skipped, never fatal, when the name repeats inside the request, fails validation, collides with an existing live variable, or would push the environment past the 1,000 variables per environment fair-use cap that applies on every plan (`reason: \\"plan limit reached\\"`). A name that fails the `^[A-Za-z_][A-Za-z0-9_]*$` shape or the 1 to 100 character bound is reported the same way, with the validation message as its `reason`. Names are compared without regard to case throughout, so two items differing only in case collide with each other and `api_key` collides with a live `API_KEY`. Items are created in request order, so plan overflow drops the tail.\\n\\n`value` and `defaultValue` are **ciphertext**, encrypted client-side with the workspace key, prefixed `v1:` or `v2:`. Note the gotcha: unlike `POST .../variables` and `PATCH .../variables/{name}`, this endpoint does not run the ciphertext prefix check, it only checks that `value` is a string of 1 to 20000 characters. Sending plaintext here succeeds and stores permanent plaintext, which then propagates into every later version snapshot and every rollback from one. Validate the prefix in your client.","responses":{"201":{"description":"Create variables in bulk succeeded.","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","const":true},"code":{"type":"integer","example":200},"message":{"type":"string","example":"OK"},"error":{"type":"null"},"data":{"type":"object","properties":{"created":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string"},"name":{"type":"string","example":"STRIPE_SECRET_KEY"}},"required":["id","name"]},"description":"Only id and name. Re-read the variable if you need the full record."},"skipped":{"type":"array","items":{"type":"object","properties":{"name":{"type":"string","example":"STRIPE_SECRET_KEY"},"reason":{"type":"string","description":"One of: duplicate in request, already exists, plan limit reached, or a validation message such as the one for a name that fails `^[A-Za-z_][A-Za-z0-9_]*$`."}},"required":["name","reason"]}},"count":{"type":"integer","description":"Length of `created`. A 201 always created at least one variable, everything the server refused is in `skipped`."}},"required":["created","skipped","count"]},"_req":{"type":"object","properties":{"reqId":{"type":"string"},"resTime":{"type":["integer","null"]}}}},"required":["success","code","message","error","data"]}}}}
1,"400":{"description":"`request.body_invalid` - the body is not JSON, `variables` is missing, empty or longer than 200, or an item lacks a string `name` or string `value`. Returned with `error: null`.","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","const":false},"code":{"type":"integer","example":400},"message":{"type":"string","example":"Something went wrong."},"error":{"$ref":"#/components/schemas/ApiError"},"data":{"type":"null"},"_req":{"type":"object","properties":{"reqId":{"type":"string"},"resTime":{"type":["integer","null"]}}}},"required":["success","code","message","error","data"]}}}},"401":{"description":"Missing, malformed, revoked or non-member API key (`auth.api_key_*`).","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","const":false},"code":{"type":"integer","example":400},"message":{"type":"string","example":"Something went wrong."},"error":{"$ref":"#/components/schemas/ApiError"},"data":{"type":"null"},"_req":{"type":"object","properties":{"reqId":{"type":"string"},"resTime":{"type":["integer","null"]}}}},"required":["success","code","message","error","data"]}}}},"402":{"description":"`plan.upgrade_required` - the project is locked by the plan\'s project limit. The variable cap itself never surfaces here, it appears per item in `skipped`.","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","const":false},"code":{"type":"integer","example":400},"message":{"type":"string","example":"Something went wrong."},"error":{"$ref":"#/components/schemas/ApiError"},"data":{"type":"null"},"_req":{"type":"object","properties":{"reqId":{"type":"string"},"resTime":{"type":["integer","null"]}}}},"required":["success","code","message","error","data"]}}}},"403":{"description":"`auth.key_project_restricted` - the key\'s project allowlist excludes this project, or `auth.product_restricted` for an inaccessible private product.","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","const":false},"code":{"type":"integer","example":400},"message":{"type":"string","example":"Something went wrong."},"error":{"$ref":"#/components/schemas/ApiError"},"data":{"type":"null"},"_req":{"type":"object","properties":{"reqId":{"type":"string"},"resTime":{"type":["integer","null"]}}}},"required":["success","code","message","error","data"]}}}},"404":{"description":"`project.not_found` - unknown project, or `environment.not_found` for an unknown environment slug.","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","const":false},"code":{"type":"integer","example":400},"message":{"type":"string","example":"Something went wrong."},"error":{"$ref":"#/components/schemas/ApiError"},"data":{"type":"null"},"_req":{"type":"object","properties":{"reqId":{"type":"string"},"resTime":{"type":["integer","null"]}}}},"required":["success","code","message","error","data"]}}}},"409":{"description":"`environment.not_found` - the environment was deleted while the variables were being created, which a cascading product or project delete can do mid-request.","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","const":false},"code":{"type":"integer","example":400},"message":{"type":"string","example":"Something went wrong."},"error":{"$ref":"#/components/schemas/ApiError"},"data":{"type":"null"},"_req":{"type":"object","properties":{"reqId":{"type":"string"},"resTime":{"type":["integer","null"]}}}},"required":["success","code","message","error","data"]}}}},"500":{"description":"`server.error` - every candidate row failed to insert. Note the asymmetry: items filtered out before the insert are reported as `skipped` with a 201, but a database insert that lands zero rows is a 500.","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","const":false},"code":{"type":"integer","example":400},"message":{"type":"string","example":"Something went wrong."},"error":{"$ref":"#/components/schemas/ApiError"},"data":{"type":"null"},"_req":{"type":"object","properties":{"reqId":{"type":"string"},"resTime":{"type":["integer","null"]}}}},"required":["success","code","message","error","data"]}}}}},"x-envless-scopes":["variables:write"],"parameters":[{"name":"slug","in":"path","required":true,"schema":{"type":"string"},"description":"Project slug or project uniqueId."},{"name":"environmentSlug","in":"path","required":true,"schema":{"type":"string"}
1,"description":"Environment slug."},{"name":"product","in":"query","required":false,"schema":{"type":"string"},"description":"Product slug, to disambiguate a project slug shared across products."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"variables":{"type":"array","minItems":1,"maxItems":200,"items":{"type":"object","properties":{"name":{"type":"string","minLength":1,"maxLength":100,"pattern":"^[A-Za-z_][A-Za-z0-9_]*$","example":"SENTRY_DSN","description":"Variable name. Same rule as the single create: `^[A-Za-z_][A-Za-z0-9_]*$`, 1 to 100 characters, stored with the casing you send, unique in the environment without regard to case. A name that fails lands in `skipped` with the reason, it does not fail the whole batch."},"value":{"type":"string","minLength":1,"maxLength":20000,"pattern":"^v[12]:","description":"CIPHERTEXT. The prefix is NOT enforced server-side on this endpoint. Enforce it yourself.","example":"v1:8Wm3kQ...ciphertext"},"type":{"type":"string","enum":["string","number","boolean"],"default":"string","example":"string"},"isSecret":{"type":"boolean","default":true},"visibility":{"type":"string","enum":["server","client"],"default":"server","example":"server"},"required":{"type":"boolean","default":false,"example":false},"defaultValue":{"type":["string","null"],"maxLength":20000,"pattern":"^v[12]:","description":"CIPHERTEXT, same key and prefix as `value`. Not prefix-checked here either."}},"required":["name","value"]}}},"required":["variables"]}}}}}},"/projects/{slug}/environments/{environmentSlug}/variables/{name}":{"get":{"operationId":"getVariableByName","tags":["Variables"],"summary":"Get a variable by name","description":"Fetches one live variable by name within an environment. Matching ignores case, so `API_KEY`, `api_key` and `Api_Key` all resolve to the same variable and the response carries the name with its stored casing. There is no fallback to id on this route, use `GET /variables/{id}` for id addressing.\\n\\n`value` and `defaultValue` are **ciphertext** and are returned untouched. The server cannot decrypt them. Legacy rows written before ciphertext was enforced still return their plaintext unchanged, so detect the `v1:`/`v2:` prefix rather than assuming.\\n\\nEvery write path enforces `^[A-Za-z_][A-Za-z0-9_]*$`, so a name created through the API is letters, digits and underscores only and never needs escaping in a path segment. Only legacy rows written before that rule was enforced can hold a character that does, so URL-encode the segment when you are addressing one of those.","responses":{"200":{"description":"Get a variable by name succeeded.","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","const":true},"code":{"type":"integer","example":200},"message":{"type":"string","example":"OK"},"error":{"type":"null"},"data":{"$ref":"#/components/schemas/Variable"},"_req":{"type":"object","properties":{"reqId":{"type":"string"},"resTime":{"type":["integer","null"]}}}},"required":["success","code","message","error","data"]}}}},"401":{"description":"Missing, malformed, revoked or non-member API key (`auth.api_key_*`).","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","const":false},"code":{"type":"integer","example":400},"message":{"type":"string","example":"Something went wrong."},"error":{"$ref":"#/components/schemas/ApiError"},"data":{"type":"null"},"_req":{"type":"object","properties":{"reqId":{"type":"string"},"resTime":{"type":["integer","null"]}}}},"required":["success","code","message","error","data"]}}}},"402":{"description":"`plan.upgrade_required` - the project is locked by the plan\'s project limit.","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","const":false},"code":{"type":"integer","example":400},"message":{"type":"string","example":"Something went wrong."},"error":{"$ref":"#/components/schemas/ApiError"},"data":{"type":"null"},"_req":{"type":"object","properties":{"reqId":{"type":"string"},"resTime":{"type":["integer","null"]}}}},"required":["success","code","message","error","data"]}}}},"403":{"description":"`auth.key_project_restricted` - the key\'s project allowlist excludes this project, or `auth.product_restricted` for an inaccessible private product.","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","const":false},"code":{"type":"integer","example":400},"message":{"type":"string","example":"Something went wrong."},"error":{"$ref":"#/components/schemas/ApiError"},"data":{"type":"null"},"_req":{"type":"object","properties":{"reqId":{"type":"string"},"resTime":{"type":["integer","null"]}}}},"required":["success","code","message","error","data"]}}}}
1,"404":{"description":"`variable.not_found` - no live variable of that name in the environment. The same status covers `project.not_found` and `environment.not_found`. All three are sent with `error: null`, so read `message` or treat 404 as one case.","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","const":false},"code":{"type":"integer","example":400},"message":{"type":"string","example":"Something went wrong."},"error":{"$ref":"#/components/schemas/ApiError"},"data":{"type":"null"},"_req":{"type":"object","properties":{"reqId":{"type":"string"},"resTime":{"type":["integer","null"]}}}},"required":["success","code","message","error","data"]}}}},"409":{"description":"`project.ambiguous_product` - the project slug exists under more than one product.","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","const":false},"code":{"type":"integer","example":400},"message":{"type":"string","example":"Something went wrong."},"error":{"$ref":"#/components/schemas/ApiError"},"data":{"type":"null"},"_req":{"type":"object","properties":{"reqId":{"type":"string"},"resTime":{"type":["integer","null"]}}}},"required":["success","code","message","error","data"]}}}},"500":{"description":"Unexpected server error (`server.error`).","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","const":false},"code":{"type":"integer","example":400},"message":{"type":"string","example":"Something went wrong."},"error":{"$ref":"#/components/schemas/ApiError"},"data":{"type":"null"},"_req":{"type":"object","properties":{"reqId":{"type":"string"},"resTime":{"type":["integer","null"]}}}},"required":["success","code","message","error","data"]}}}}},"x-envless-scopes":["variables:read"],"parameters":[{"name":"slug","in":"path","required":true,"schema":{"type":"string"},"description":"Project slug or project uniqueId."},{"name":"environmentSlug","in":"path","required":true,"schema":{"type":"string"},"description":"Environment slug. A uniqueId will not resolve."},{"name":"name","in":"path","required":true,"schema":{"type":"string"},"description":"Variable name, matched without regard to case. URL-encode it only for a legacy name holding characters outside `[A-Za-z0-9_]`."},{"name":"product","in":"query","required":false,"schema":{"type":"string"},"description":"Product slug, to disambiguate a project slug shared across products."}]},"patch":{"operationId":"updateVariableByName","tags":["Variables"],"summary":"Update a variable by name","description":"Partial update of one variable, addressed by its current name and matched without regard to case. Every field is optional and omitted fields keep their current value.\\n\\n**`value` is ciphertext.** If present it must start with `v1:` or `v2:`, otherwise 400 `variable.ciphertext_invalid` with `error.field: \\"value\\"`. The server cannot encrypt for you, so encrypt with the workspace key before sending.\\n\\n**`defaultValue` is ciphertext too**, same workspace key, same prefix, validated the same way when it is a string. Send `null` to clear it. Omit it to leave it alone. A plaintext `defaultValue` that slips through another path is permanent plaintext and is copied into every version snapshot taken afterwards.\\n\\nPassing `name` renames the variable, which changes the URL you address it by. The new name must match `^[A-Za-z_][A-Za-z0-9_]*$` and be 1 to 100 characters, and the rename is rejected if another live variable already holds that name, compared without regard to case.","responses":{"200":{"description":"Update a variable by name succeeded.","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","const":true},"code":{"type":"integer","example":200},"message":{"type":"string","example":"OK"},"error":{"type":"null"},"data":{"$ref":"#/components/schemas/Variable"},"_req":{"type":"object","properties":{"reqId":{"type":"string"},"resTime":{"type":["integer","null"]}}}},"required":["success","code","message","error","data"]}}}},"400":{"description":"`variable.ciphertext_invalid` - `value` or `defaultValue` is not `v1:`/`v2:` ciphertext, with `error.field` naming it. The same status, but with `error: null`, covers a non-JSON body and a value, name, type, visibility, required flag or defaultValue the service rejects.","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","const":false},"code":{"type":"integer","example":400},"message":{"type":"string","example":"Something went wrong."},"error":{"$ref":"#/components/schemas/ApiError"},"data":{"type":"null"},"_req":{"type":"object","properties":{"reqId":{"type":"string"},"resTime":{"type":["integer","null"]}}}},"required":["success","code","message","error","data"]}}}},"401":{"description":"Missing, malformed, revoked or non-member API key (`auth.api_key_*`).","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","const":false},"code":{"type":"integer","example":400},"message":{"type":"string","example":"Something went wrong."},"error":{"$ref":"#/components/schemas/ApiError"},"data":{"type":"null"},"_req":{"type":"object","properties":{"reqId":{"type":"string"},"resTime":{"type":["integer","null"]}}}},"required":["success","code","message","error","data"]}}}},"402":{"description":"`plan.upgrade_required` - the project is locked by the plan\'s project limit.","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","const":false},"code":{"type":"integer","example":400},"message":{"type":"string","example":"Something went wrong."},"error":{"$ref":"#/components/schemas/ApiError"},"data":{"type":"null"},"_req":{"type":"object","properties":{"reqId":{"type":"string"},"resTime":{"type":["integer","null"]}}}},"required":["success","code","message","error","data"]}}}},"403":{"description":"`auth.key_project_restricted` - the key\'s project allowlist excludes this project, or `auth.product_restricted` for an inaccessible private product.","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","const":false},"code":{"type":"integer","example":400},"message":{"type":"string","example":"Something went wrong."},"error":{"$ref":"#/components/schemas/ApiError"},"data":{"type":"null"},"_req":{"type":"object","properties":{"reqId":{"type":"string"},"resTime":{"type":["integer","null"]}}}},"required":["success","code","message","error","data"]}}}}
1,"404":{"description":"`variable.not_found` - no live variable of that name, or the project or environment does not exist. Sent with `error: null`.","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","const":false},"code":{"type":"integer","example":400},"message":{"type":"string","example":"Something went wrong."},"error":{"$ref":"#/components/schemas/ApiError"},"data":{"type":"null"},"_req":{"type":"object","properties":{"reqId":{"type":"string"},"resTime":{"type":["integer","null"]}}}},"required":["success","code","message","error","data"]}}}},"409":{"description":"`variable.name_conflict` - a rename collides with another live variable in the same environment, compared without regard to case. Sent with `error: null`. 409 `project.ambiguous_product` shares this status when the project slug is not unique.","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","const":false},"code":{"type":"integer","example":400},"message":{"type":"string","example":"Something went wrong."},"error":{"$ref":"#/components/schemas/ApiError"},"data":{"type":"null"},"_req":{"type":"object","properties":{"reqId":{"type":"string"},"resTime":{"type":["integer","null"]}}}},"required":["success","code","message","error","data"]}}}},"500":{"description":"Unexpected server error (`server.error`).","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","const":false},"code":{"type":"integer","example":400},"message":{"type":"string","example":"Something went wrong."},"error":{"$ref":"#/components/schemas/ApiError"},"data":{"type":"null"},"_req":{"type":"object","properties":{"reqId":{"type":"string"},"resTime":{"type":["integer","null"]}}}},"required":["success","code","message","error","data"]}}}}},"x-envless-scopes":["variables:write"],"parameters":[{"name":"slug","in":"path","required":true,"schema":{"type":"string"},"description":"Project slug or project uniqueId."},{"name":"environmentSlug","in":"path","required":true,"schema":{"type":"string"},"description":"Environment slug."},{"name":"name","in":"path","required":true,"schema":{"type":"string"},"description":"Current variable name, matched without regard to case. URL-encode it only for a legacy name holding characters outside `[A-Za-z0-9_]`."},{"name":"product","in":"query","required":false,"schema":{"type":"string"},"description":"Product slug, to disambiguate a project slug shared across products."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","minProperties":1,"properties":{"name":{"type":"string","minLength":1,"maxLength":100,"pattern":"^[A-Za-z_][A-Za-z0-9_]*$","example":"STRIPE_SECRET_KEY","description":"New name. Must match `^[A-Za-z_][A-Za-z0-9_]*$` and be 1 to 100 characters, and is stored with the casing you send. Renaming changes the URL of this variable."},"value":{"type":"string","minLength":1,"maxLength":20000,"pattern":"^v[12]:","description":"CIPHERTEXT. Must start with `v1:` or `v2:`.","example":"v1:8Wm3kQ...ciphertext"},"type":{"type":"string","enum":["string","number","boolean"],"example":"string"},"isSecret":{"type":"boolean"},"visibility":{"type":"string","enum":["server","client"],"example":"server"},"required":{"type":"boolean","example":false},"defaultValue":{"type":["string","null"],"maxLength":20000,"pattern":"^v[12]:","description":"CIPHERTEXT, same key and prefix as `value`. `null` clears it, omitting keeps it."}}}}}}},"delete":{"operationId":"deleteVariableByName","tags":["Variables"],"summary":"Delete a variable by name","description":"Soft-deletes one live variable by name, matched without regard to case. The row stops appearing in reads immediately, and version snapshots taken before the delete keep their copy, so a rollback can bring the variable back.\\n\\nDeleting a name that does not exist is a 404, not a no-op. Use the bulk `DELETE .../variables` route if you want unknown names tolerated.","responses":{"200":{"description":"Delete a variable by name succeeded.","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","const":true},"code":{"type":"integer","example":200},"message":{"type":"string","example":"OK"},"error":{"type":"null"},"data":{"type":"object","properties":{"id":{"type":"string"},"name":{"type":"string","example":"STRIPE_SECRET_KEY"},"environmentId":{"type":"string"}},"required":["id","name","environmentId"]},"_req":{"type":"object","properties":{"reqId":{"type":"string"},"resTime":{"type":["integer","null"]}}}},"required":["success","code","message","error","data"]}}}},"401":{"description":"Missing, malformed, revoked or non-member API key (`auth.api_key_*`).","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","const":false},"code":{"type":"integer","example":400},"message":{"type":"string","example":"Something went wrong."},"error":{"$ref":"#/components/schemas/ApiError"},"data":{"type":"null"},"_req":{"type":"object","properties":{"reqId":{"type":"string"},"resTime":{"type":["integer","null"]}}}},"required":["success","code","message","error","data"]}}}},"402":{"description":"`plan.upgrade_required` - the project is locked by the plan\'s project limit.","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","const":false},"code":{"type":"integer","example":400},"message":{"type":"string","example":"Something went wrong."},"error":{"$ref":"#/components/schemas/ApiError"},"data":{"type":"null"},"_req":{"type":"object","properties":{"reqId":{"type":"string"},"resTime":{"type":["integer","null"]}}}},"required":["success","code","message","error","data"]}}}},"403":{"description":"`auth.key_project_restricted` - the key\'s project allowlist excludes this project, or `auth.product_restricted` for an inaccessible private product.","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","const":false},"code":{"type":"integer","example":400},"message":{"type":"string","example":"Something went wrong."},"error":{"$ref":"#/components/schemas/ApiError"},"data":{"type":"null"},"_req":{"type":"object","properties":{"reqId":{"type":"string"},"resTime":{"type":["integer","null"]}}}},"required":["success","code","message","error","data"]}}}}
1,"404":{"description":"`variable.not_found` - no live variable of that name, or the project or environment does not exist. Sent with `error: null`.","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","const":false},"code":{"type":"integer","example":400},"message":{"type":"string","example":"Something went wrong."},"error":{"$ref":"#/components/schemas/ApiError"},"data":{"type":"null"},"_req":{"type":"object","properties":{"reqId":{"type":"string"},"resTime":{"type":["integer","null"]}}}},"required":["success","code","message","error","data"]}}}},"409":{"description":"`project.ambiguous_product` - the project slug exists under more than one product.","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","const":false},"code":{"type":"integer","example":400},"message":{"type":"string","example":"Something went wrong."},"error":{"$ref":"#/components/schemas/ApiError"},"data":{"type":"null"},"_req":{"type":"object","properties":{"reqId":{"type":"string"},"resTime":{"type":["integer","null"]}}}},"required":["success","code","message","error","data"]}}}},"500":{"description":"Unexpected server error (`server.error`).","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","const":false},"code":{"type":"integer","example":400},"message":{"type":"string","example":"Something went wrong."},"error":{"$ref":"#/components/schemas/ApiError"},"data":{"type":"null"},"_req":{"type":"object","properties":{"reqId":{"type":"string"},"resTime":{"type":["integer","null"]}}}},"required":["success","code","message","error","data"]}}}}},"x-envless-scopes":["variables:write"],"parameters":[{"name":"slug","in":"path","required":true,"schema":{"type":"string"},"description":"Project slug or project uniqueId."},{"name":"environmentSlug","in":"path","required":true,"schema":{"type":"string"},"description":"Environment slug."},{"name":"name","in":"path","required":true,"schema":{"type":"string"},"description":"Variable name, matched without regard to case. URL-encode it only for a legacy name holding characters outside `[A-Za-z0-9_]`."},{"name":"product","in":"query","required":false,"schema":{"type":"string"},"description":"Product slug, to disambiguate a project slug shared across products."}]}},"/projects/{slug}/environments/{environmentSlug}/variables/{name}/history":{"get":{"operationId":"getVariableHistory","tags":["Variables"],"summary":"List a variable\'s history","de
1scription":"Audit trail for one variable, newest first. Events are recorded per variable id, so history follows the row through renames but does not follow a name that was deleted and re-created, that name starts a fresh id with a fresh history.\\n\\nNo values, ciphertext or otherwise, are ever included. `metadata` carries small change hints such as `nameChanged`, `valueChanged`, `previousName`, `rolledBackFromVersion` or `source`, and its keys vary by event type.\\n\\n`actor` is null for changes made by an API key whose owner record is gone, or by internal processes.\\n\\n**Plan gate.** Free workspaces see only the latest event and the response carries `historyLimited: true` with `hiddenCount` telling you how many older events exist. Dev, Team and Enterprise see the full history. Nothing is deleted on a downgrade, the older events come back on upgrade.","responses":{"200":{"description":"List a variable\'s history succeeded.","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","const":true},"code":{"type":"integer","example":200},"message":{"type":"string","example":"OK"},"error":{"type":"null"},"data":{"type":"object","properties":{"events":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string"},"type":{"type":"string","enum":["created","updated","deleted","restored"]},"metadata":{"type":["object","null"],"additionalProperties":true,"description":"Free-form change hints. Never contains values."},"actor":{"type":["object","null"],"properties":{"id":{"type":"string"},"name":{"type":["string","null"]},"email":{"type":["string","null"]}},"required":["id"]},"createdAt":{"type":"string","format":"date-time"}},"required":["id","type","createdAt"]}},"pagination":{"$ref":"#/components/schemas/Pagination"},"historyLimited":{"type":"boolean","description":"True when the plan hides part of the history. Free workspaces see only the latest event; Dev, Team and Enterprise see everything."},"historyLimit":{"type":"integer","description":"How many entries the plan makes visible. 1 on Free, a very large sentinel on unlimited plans."},"hiddenCount":{"type":"integer","description":"How many older events exist but are hidden by the plan. 0 when nothing is hidden."}},"required":["events","pagination","historyLimited","historyLimit","hiddenCount"]},"_req":{"type":"object","properties":{"reqId":{"type":"string"},"resTime":{"type":["integer","null"]}}}},"required":["success","code","message","error","data"]}}}},"400":{"description":"`request.invalid_pagination` - `limit` is outside 1 to 100 or either pagination value is not a whole number.","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","const":false},"code":{"type":"integer","example":400},"message":{"type":"string","example":"Something went wrong."},"error":{"$ref":"#/components/schemas/ApiError"},"data":{"type":"null"},"_req":{"type":"object","properties":{"reqId":{"type":"string"},"resTime":{"type":["integer","null"]}}}},"required":["success","code","message","error","data"]}}}},"401":{"description":"Missing, malformed, revoked or non-member API key (`auth.api_key_*`).","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","const":false},"code":{"type":"integer","example":400},"message":{"type":"string","example":"Something went wrong."},"error":{"$ref":"#/components/schemas/ApiError"},"data":{"type":"null"},"_req":{"type":"object","properties":{"reqId":{"type":"string"},"resTime":{"type":["integer","null"]}}}},"required":["success","code","message","error","data"]}}}},"402":{"description":"`plan.upgrade_required` - the project is locked by the plan\'s project limit. Free workspaces are not refused here, they simply receive only the latest event with `historyLimited: true`.","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","const":false},"code":{"type":"integer","example":400},"message":{"type":"string","example":"Something went wrong."},"error":{"$ref":"#/components/schemas/ApiError"},"data":{"type":"null"},"_req":{"type":"object","properties":{"reqId":{"type":"string"},"resTime":{"type":["integer","null"]}}}},"required":["success","code","message","error","data"]}}}},"403":{"description":"`auth.key_project_restricted` - the key\'s project allowlist excludes this project, or `auth.product_restricted` for an inaccessible private product.","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","const":false},"code":{"type":"integer","example":400},"message":{"type":"string","example":"Something went wrong."},"error":{"$ref":"#/components/schemas/ApiError"},"data":{"type":"null"},"_req":{"type":"object","properties":{"reqId":{"type":"string"},"resTime":{"type":["integer","null"]}}}},"required":["success","code","message","error","data"]}}}}
1,"404":{"description":"`variable.not_found` - no live variable of that name, or the project or environment does not exist. Sent with `error: null`.","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","const":false},"code":{"type":"integer","example":400},"message":{"type":"string","example":"Something went wrong."},"error":{"$ref":"#/components/schemas/ApiError"},"data":{"type":"null"},"_req":{"type":"object","properties":{"reqId":{"type":"string"},"resTime":{"type":["integer","null"]}}}},"required":["success","code","message","error","data"]}}}},"409":{"description":"`project.ambiguous_product` - the project slug exists under more than one product.","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","const":false},"code":{"type":"integer","example":400},"message":{"type":"string","example":"Something went wrong."},"error":{"$ref":"#/components/schemas/ApiError"},"data":{"type":"null"},"_req":{"type":"object","properties":{"reqId":{"type":"string"},"resTime":{"type":["integer","null"]}}}},"required":["success","code","message","error","data"]}}}},"500":{"description":"Unexpected server error (`server.error`).","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","const":false},"code":{"type":"integer","example":400},"message":{"type":"string","example":"Something went wrong."},"error":{"$ref":"#/components/schemas/ApiError"},"data":{"type":"null"},"_req":{"type":"object","properties":{"reqId":{"type":"string"},"resTime":{"type":["integer","null"]}}}},"required":["success","code","message","error","data"]}}}}},"x-envless-scopes":["variables:read"],"parameters":[{"name":"slug","in":"path","required":true,"schema":{"type":"string"},"description":"Project slug or project uniqueId."},{"name":"environmentSlug","in":"path","required":true,"schema":{"type":"string"},"description":"Environment slug."},{"name":"name","in":"path","required":true,"schema":{"type":"string"},"description":"Current variable name, matched without regard to case. The variable must still be live, history for a deleted variable is not reachable by name."},{"name":"product","in":"query","required":false,"schema":{"type":"string"},"description":"Product slug, to disambiguate a project slug shared across products."},{"name":"limit","in":"query","schema":{"type":"integer","minimum":1,"maximum":100,"default":25},"description":"Page size, 1 to 100."},{"name":"offset","in":"query","schema":{"type":"integer","minimum":0,"default":0},"description":"Rows to skip."}]}},"/projects/{slug}/environments/{environmentSlug}/versions":{"get":{"operationId":"listVersions","tags":["Versions"],"summary":"List versions","description":"Lists the snapshots taken for an environment, newest first. Each row is metadata only, no variables and no ciphertext. Fetch `GET /versions/{id}` for the contents of one snapshot.\\n\\n`label` is assigned server-side as `v1`, `v2` and so on, derived from how many versions the environment already has. It is not guaranteed unique forever, since the counter is based on a count, so treat `id` as the identity.\\n\\n`createdBy` falls back to the name and email captured at snapshot time when the user record has since been removed, and is null when neither is known.\\n\\n**Plan gate.** Free workspaces see only the latest version: the list holds one row, `historyLimited` is `true` and `hiddenCount` tells you how many older versions exist. Reading, comparing or rolling back to any older version returns 402 `plan.upgrade_required` with `error.resource: \\"version\\"`. Dev, Team and Enterprise see the full history. Publishing keeps working on every plan and nothing is deleted on a downgrade, the hidden versions come back on upgrade.","responses":{"200":{"description":"List versions succeeded.","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","const":true},"code":{"type":"integer","example":200},"message":{"type":"string","example":"OK"},"error":{"type":"null"},"data":{"type":"object","properties":{"versions":{"type":"array","items":{"allOf":[{"$ref":"#/components/schemas/Version"},{"type":"object","properties":{"environmentId":{"type":"string"}},"required":["environmentId"]}]}},"pagination":{"$ref":"#/components/schemas/Pagination"},"historyLimited":{"type":"boolean","description":"True when the plan hides part of the history. Free workspaces see only the latest version; Dev, Team and Enterprise see every version."},"historyLimit":{"type":"integer","description":"How many versions the plan makes visible. 1 on Free, a very large sentinel on unlimited plans."},"hiddenCount":{"type":"integer","description":"How many older versions exist but are hidden by the plan. 0 when nothing is hidden. Nothing is deleted on a downgrade, the hidden versions come back on upgrade."}},"required":["versions","pagination","historyLimited","historyLimit","hiddenCount"]},"_req":{"type":"object","properties":{"reqId":{"type":"string"},"resTime":{"type":["integer","null"]}}}},"required":["success","code","message","error","data"]}}}}
1,"400":{"description":"`request.invalid_pagination` - `limit` is outside 1 to 100 or either pagination value is not a whole number.","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","const":false},"code":{"type":"integer","example":400},"message":{"type":"string","example":"Something went wrong."},"error":{"$ref":"#/components/schemas/ApiError"},"data":{"type":"null"},"_req":{"type":"object","properties":{"reqId":{"type":"string"},"resTime":{"type":["integer","null"]}}}},"required":["success","code","message","error","data"]}}}},"401":{"description":"Missing, malformed, revoked or non-member API key (`auth.api_key_*`).","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","const":false},"code":{"type":"integer","example":400},"message":{"type":"string","example":"Something went wrong."},"error":{"$ref":"#/components/schemas/ApiError"},"data":{"type":"null"},"_req":{"type":"object","properties":{"reqId":{"type":"string"},"resTime":{"type":["integer","null"]}}}},"required":["success","code","message","error","data"]}}}},"402":{"description":"`plan.upgrade_required` - the project is locked by the plan\'s project limit. Free workspaces are not refused here, they simply receive only the latest version with `historyLimited: true`.","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","const":false},"code":{"type":"integer","example":400},"message":{"type":"string","example":"Something went wrong."},"error":{"$ref":"#/components/schemas/ApiError"},"data":{"type":"null"},"_req":{"type":"object","properties":{"reqId":{"type":"string"},"resTime":{"type":["integer","null"]}}}},"required":["success","code","message","error","data"]}}}},"403":{"description":"`auth.scope_missing` - the key lacks `versions:read`. This route also fails with `auth.key_project_restricted` when the key\'s project allowlist excludes this project, and `auth.product_restricted` for an inaccessible private product.","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","const":false},"code":{"type":"integer","example":400},"message":{"type":"string","example":"Something went wrong."},"error":{"$ref":"#/components/schemas/ApiError"},"data":{"type":"null"},"_req":{"type":"object","properties":{"reqId":{"type":"string"},"resTime":{"type":["integer","null"]}}}},"required":["success","code","message","error","data"]}}}},"404":{"description":"`project.not_found` - unknown project, or `environment.not_found` for an unknown environment slug. Sent with `error: null`.","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","const":false},"code":{"type":"integer","example":400},"message":{"type":"string","example":"Something went wrong."},"error":{"$ref":"#/components/schemas/ApiError"},"data":{"type":"null"},"_req":{"type":"object","properties":{"reqId":{"type":"string"},"resTime":{"type":["integer","null"]}}}},"required":["success","code","message","error","data"]}}}},"409":{"description":"`project.ambiguous_product` - the project slug exists under more than one product.","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","const":false},"code":{"type":"integer","example":400},"message":{"type":"string","example":"Something went wrong."},"error":{"$ref":"#/components/schemas/ApiError"},"data":{"type":"null"},"_req":{"type":"object","properties":{"reqId":{"type":"string"},"resTime":{"type":["integer","null"]}}}},"required":["success","code","message","error","data"]}}}},"500":{"description":"Unexpected server error (`server.error`).","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","const":false},"code":{"type":"integer","example":400},"message":{"type":"string","example":"Something went wrong."},"error":{"$ref":"#/components/schemas/ApiError"},"data":{"type":"null"},"_req":{"type":"object","properties":{"reqId":{"type":"string"},"resTime":{"type":["integer","null"]}}}},"required":["success","code","message","error","data"]}}}}},"x-envless-scopes":["versions:read"],"parameters":[{"name":"slug","in":"path","required":true,"schema":{"type":"string"},"description":"Project slug or project uniqueId."},{"name":"environmentSlug","in":"path","required":true,"schema":{"type":"string"}
1,"description":"Environment slug. A uniqueId will not resolve."},{"name":"product","in":"query","required":false,"schema":{"type":"string"},"description":"Product slug, to disambiguate a project slug shared across products."},{"name":"limit","in":"query","schema":{"type":"integer","minimum":1,"maximum":100,"default":25},"description":"Page size, 1 to 100."},{"name":"offset","in":"query","schema":{"type":"integer","minimum":0,"default":0},"description":"Rows to skip."}]},"post":{"operationId":"createVersion","tags":["Versions"],"summary":"Create a version","description":"Snapshots every live variable in the environment into a new immutable version. The snapshot copies `name`, `value`, `type`, `isSecret`, `visibility`, `required` and `defaultValue` as stored, which means the **ciphertext is copied verbatim**. The server cannot decrypt or re-encrypt it, so whatever key the values were encrypted with is the key needed to read this version later.\\n\\nThis is the durability step. Take a version before any risky bulk change, and take one before a rollback, because rollback does not snapshot the current state for you.\\n\\nThe body is optional. A missing or unparseable body is treated as no note rather than an error. `label` is assigned server-side.\\n\\nAn environment holds at most 1000 versions. Past that, creation fails.\\n\\nPublishing works on every plan, including Free. The plan only decides how much of the resulting history is visible: Free workspaces can read the latest version they just published, older versions, their entries and rollback return 402 `plan.upgrade_required` until the workspace upgrades.","responses":{"201":{"description":"Create a version succeeded.","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","const":true},"code":{"type":"integer","example":200},"message":{"type":"string","example":"OK"},"error":{"type":"null"},"data":{"type":"object","properties":{"id":{"type":"string"},"label":{"type":"string","description":"Server-assigned, `v1`, `v2` and so on."},"note":{"type":["string","null"]},"variableCount":{"type":"integer","description":"Live variables captured in the snapshot. 0 is allowed."},"environmentId":{"type":"string"},"createdAt":{"type":"string","format":"date-time"}},"required":["id","label","variableCount","environmentId","createdAt"]},"_req":{"type":"object","properties":{"reqId":{"type":"string"},"resTime":{"type":["integer","null"]}}}},"required":["success","code","message","error","data"]}}}}
1,"400":{"description":"`request.body_invalid` - `note` is longer than 200 characters, or the environment already holds 1000 versions. Both come back as 400 with `error: null`, so read `message`.","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","const":false},"code":{"type":"integer","example":400},"message":{"type":"string","example":"Something went wrong."},"error":{"$ref":"#/components/schemas/ApiError"},"data":{"type":"null"},"_req":{"type":"object","properties":{"reqId":{"type":"string"},"resTime":{"type":["integer","null"]}}}},"required":["success","code","message","error","data"]}}}},"401":{"description":"Missing, malformed, revoked or non-member API key (`auth.api_key_*`).","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","const":false},"code":{"type":"integer","example":400},"message":{"type":"string","example":"Something went wrong."},"error":{"$ref":"#/components/schemas/ApiError"},"data":{"type":"null"},"_req":{"type":"object","properties":{"reqId":{"type":"string"},"resTime":{"type":["integer","null"]}}}},"required":["success","code","message","error","data"]}}}},"402":{"description":"`plan.upgrade_required` - the project is locked by the plan\'s project limit. Publishing itself works on every plan, including Free.","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","const":false},"code":{"type":"integer","example":400},"message":{"type":"string","example":"Something went wrong."},"error":{"$ref":"#/components/schemas/ApiError"},"data":{"type":"null"},"_req":{"type":"object","properties":{"reqId":{"type":"string"},"resTime":{"type":["integer","null"]}}}},"required":["success","code","message","error","data"]}}}},"403":{"description":"`auth.scope_missing` - the key lacks `versions:write`, or `auth.key_project_restricted` / `auth.product_restricted` for a project or product the key cannot reach.","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","const":false},"code":{"type":"integer","example":400},"message":{"type":"string","example":"Something went wrong."},"error":{"$ref":"#/components/schemas/ApiError"},"data":{"type":"null"},"_req":{"type":"object","properties":{"reqId":{"type":"string"},"resTime":{"type":["integer","null"]}}}},"required":["success","code","message","error","data"]}}}},"404":{"description":"`project.not_found` - unknown project, or `environment.not_found` for an unknown environment slug.","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","const":false},"code":{"type":"integer","example":400},"message":{"type":"string","example":"Something went wrong."},"error":{"$ref":"#/components/schemas/ApiError"},"data":{"type":"null"},"_req":{"type":"object","properties":{"reqId":{"type":"string"},"resTime":{"type":["integer","null"]}}}},"required":["success","code","message","error","data"]}}}},"409":{"description":"`project.ambiguous_product` - the project slug exists under more than one product.","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","const":false},"code":{"type":"integer","example":400},"message":{"type":"string","example":"Something went wrong."},"error":{"$ref":"#/components/schemas/ApiError"},"data":{"type":"null"},"_req":{"type":"object","properties":{"reqId":{"type":"string"},"resTime":{"type":["integer","null"]}}}},"required":["success","code","message","error","data"]}}}},"500":{"description":"Unexpected server error (`server.error`).","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","const":false},"code":{"type":"integer","example":400},"message":{"type":"string","example":"Something went wrong."},"error":{"$ref":"#/components/schemas/ApiError"},"data":{"type":"null"},"_req":{"type":"object","properties":{"reqId":{"type":"string"},"resTime":{"type":["integer","null"]}}}},"required":["success","code","message","error","data"]}}}}},"x-envless-scopes":["versions:write"],"parameters":[{"name":"slug","in":"path","required":true,"schema":{"type":"string"},"description":"Project slug or project uniqueId."},{"name":"environmentSlug","in":"path","required":true,"schema":{"type":"string"}
1,"description":"Environment slug."},{"name":"product","in":"query","required":false,"schema":{"type":"string"},"description":"Product slug, to disambiguate a project slug shared across products."}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"note":{"type":["string","null"],"maxLength":200,"description":"Optional note. Trimmed, and an empty result is stored as null."}}}}}}}},"/projects/{slug}/environments/{environmentSlug}/versions/entries":{"get":{"operationId":"listVersionEntries","tags":["Versions"],"summary":"List version entry ciphertext","description":"Reads the raw ciphertext of **every version entry in the environment, across all versions**, so it can be re-encrypted client-side. Together with `POST .../versions/entries/reencrypt` this is the passphrase rotation pair.\\n\\nRotation flow: page through this endpoint, decrypt each `value` and `defaultValue` with the old workspace key, re-encrypt with the new one, and post the results back to the reencrypt endpoint keyed by the same `id`.\\n\\n**Rotating the live variables without also rotating the version entries silently breaks every later rollback.** Nothing errors at rotation time. The live variables decrypt fine under the new key, the snapshots still decrypt only under the old one, and the breakage only shows up when someone rolls back and the restored values become undecryptable garbage. Rotate both, in the same run.\\n\\nThe payload is deliberately thin. There is no name and no version id on an entry, because rotation is blind, you decrypt and re-encrypt by `id` alone. Pagination is applied in memory after loading the environment\'s entries, so it is stable within a run but not cheap on very large environments. Requires both `versions:read` and `variables:read`.\\n\\nThis feed is deliberately not limited by the plan\'s version history: a Free workspace can rotate the entries of every stored version, so the history it keeps for a later upgrade stays decryptable.","responses":{"200":{"description":"List version entry ciphertext succeeded.","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","const":true},"code":{"type":"integer","example":200},"message":{"type":"string","example":"OK"},"error":{"type":"null"},"data":{"type":"object","properties":{"entries":{"type":"array","items":{"$ref":"#/components/schemas/VersionEntry"}},"pagination":{"$ref":"#/components/schemas/Pagination"}},"required":["entries","pagination"]},"_req":{"type":"object","properties":{"reqId":{"type":"string"},"resTime":{"type":["integer","null"]}}}},"required":["success","code","message","error","data"]}}}},"400":{"description":"`request.invalid_pagination` - `limit` is outside 1 to 100 or either pagination value is not a whole number.","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","const":false},"code":{"type":"integer","example":400},"message":{"type":"string","example":"Something went wrong."},"error":{"$ref":"#/components/schemas/ApiError"},"data":{"type":"null"},"_req":{"type":"object","properties":{"reqId":{"type":"string"},"resTime":{"type":["integer","null"]}}}},"required":["success","code","message","error","data"]}}}},"401":{"description":"Missing, malformed, revoked or non-member API key (`auth.api_key_*`).","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","const":false},"code":{"type":"integer","example":400},"message":{"type":"string","example":"Something went wrong."},"error":{"$ref":"#/components/schemas/ApiError"},"data":{"type":"null"},"_req":{"type":"object","properties":{"reqId":{"type":"string"},"resTime":{"type":["integer","null"]}}}},"required":["success","code","message","error","data"]}}}},"402":{"description":"`plan.upgrade_required` - the project is locked by the plan\'s project limit. This rotation feed is not history-gated, Free workspaces can rotate the entries of every version.","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","const":false},"code":{"type":"integer","example":400},"message":{"type":"string","example":"Something went wrong."},"error":{"$ref":"#/components/schemas/ApiError"},"data":{"type":"null"},"_req":{"type":"object","properties":{"reqId":{"type":"string"},"resTime":{"type":["integer","null"]}}}},"required":["success","code","message","error","data"]}}}},"403":{"description":"`auth.scope_missing` - the key lacks `versions:read` or `variables:read`, both are required. Also `auth.key_project_restricted` and `auth.product_restricted` for projects and products the key cannot reach.","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","const":false},"code":{"type":"integer","example":400},"message":{"type":"string","example":"Something went wrong."},"error":{"$ref":"#/components/schemas/ApiError"},"data":{"type":"null"},"_req":{"type":"object","properties":{"reqId":{"type":"string"},"resTime":{"type":["integer","null"]}}}},"required":["success","code","message","error","data"]}}}},"404":{"description":"`project.not_found` - unknown project, or `environment.not_found` for an unknown environment slug.","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","const":false},"code":{"type":"integer","example":400},"message":{"type":"string","example":"Something went wrong."},"error":{"$ref":"#/components/schemas/ApiError"},"data":{"type":"null"},"_req":{"type":"object","properties":{"reqId":{"type":"string"},"resTime":{"type":["integer","null"]}}}},"required":["success","code","message","error","data"]}}}},"409":{"description":"`project.ambiguous_product` - the project slug exists under more than one product.","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","const":false},"code":{"type":"integer","example":400},"message":{"type":"string","example":"Something went wrong."},"error":{"$ref":"#/components/schemas/ApiError"},"data":{"type":"null"},"_req":{"type":"object","properties":{"reqId":{"type":"string"},"resTime":{"type":["integer","null"]}}}},"required":["success","code","message","error","data"]}}}},"500":{"description":"Unexpected server error (`server.error`).","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","const":false},"code":{"type":"integer","example":400},"message":{"type":"string","example":"Something went wrong."},"error":{"$ref":"#/components/schemas/ApiError"},"data":{"type":"null"},"_req":{"type":"object","properties":{"reqId":{"type":"string"},"resTime":{"type":["integer","null"]}}}},"required":["success","code","message","error","data"]}}}}},"x-envless-scopes":["versions:read","variables:read"],"parameters":[{"name":"slug","in":"path","required":true,"schema":{"type":"string"},"description":"Project slug or project uniqueId."},{"name":"environmentSlug","in":"path","required":true,"schema":{"type":"string"}
1,"description":"Environment slug. A uniqueId will not resolve."},{"name":"product","in":"query","required":false,"schema":{"type":"string"},"description":"Product slug, to disambiguate a project slug shared across products."},{"name":"limit","in":"query","schema":{"type":"integer","minimum":1,"maximum":100,"default":25},"description":"Page size, 1 to 100. The reencrypt endpoint accepts up to 200 entries per call, so pages of 100 are the practical maximum round trip."},{"name":"offset","in":"query","schema":{"type":"integer","minimum":0,"default":0},"description":"Rows to skip."}]}},"/projects/{slug}/environments/{environmentSlug}/versions/entries/reencrypt":{"post":{"operationId":"reencryptVersionEntries","tags":["Versions"],"summary":"Write re-encrypted version entry ciphertext","description":"Writes back version entry ciphertext that you re-encrypted client-side. The other half of the passphrase rotation pair, paired with `GET .../versions/entries`.\\n\\nOnly `value` and `defaultValue` are touched, and only for entries that belong to a version of this environment, so an id from another environment cannot be written through this route. Names, types and version metadata are untouched.\\n\\n**Rotate the version entries in the same run as the live variables.** Rotating live values alone leaves the snapshots encrypted under the old key, which silently breaks any later rollback with no error at rotation time.\\n\\nTwo behaviours to code around. First, the endpoint is lenient rather than strict: entries whose `id` is not a valid uuid v7, or whose `value` is empty or longer than 20000 characters, are skipped without any error, and if every entry is skipped the response is still 200 with `updated: 0`. Always compare `updated` against the number of entries you sent and re-drive the difference. Second, `defaultValue` is written with a coalesce, so `null` or an omitted `defaultValue` keeps whatever is already stored. There is no way to clear a stored defaultValue through this route.\\n\\nAt most 200 entries per request. Requires both `versions:write` and `variables:write`.","responses":{"200":{"description":"Write re-encrypted version entry ciphertext succeeded.","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","const":true},"code":{"type":"integer","example":200},"message":{"type":"string","example":"OK"},"error":{"type":"null"},"data":{"type":"object","properties":{"updated":{"type":"integer","description":"Rows actually written. Lower than the number sent means some entries were skipped as invalid or did not belong to this environment."}},"required":["updated"]},"_req":{"type":"object","properties":{"reqId":{"type":"string"},"resTime":{"type":["integer","null"]}}}},"required":["success","code","message","error","data"]}}}}
1,"400":{"description":"`request.body_invalid` - `entries` is missing, empty or longer than 200, with `error.field: \\"entries\\"`. `request.body_must_be_json` for an unparseable body.","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","const":false},"code":{"type":"integer","example":400},"message":{"type":"string","example":"Something went wrong."},"error":{"$ref":"#/components/schemas/ApiError"},"data":{"type":"null"},"_req":{"type":"object","properties":{"reqId":{"type":"string"},"resTime":{"type":["integer","null"]}}}},"required":["success","code","message","error","data"]}}}},"401":{"description":"Missing, malformed, revoked or non-member API key (`auth.api_key_*`).","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","const":false},"code":{"type":"integer","example":400},"message":{"type":"string","example":"Something went wrong."},"error":{"$ref":"#/components/schemas/ApiError"},"data":{"type":"null"},"_req":{"type":"object","properties":{"reqId":{"type":"string"},"resTime":{"type":["integer","null"]}}}},"required":["success","code","message","error","data"]}}}},"402":{"description":"`plan.upgrade_required` - the project is locked by the plan\'s project limit.","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","const":false},"code":{"type":"integer","example":400},"message":{"type":"string","example":"Something went wrong."},"error":{"$ref":"#/components/schemas/ApiError"},"data":{"type":"null"},"_req":{"type":"object","properties":{"reqId":{"type":"string"},"resTime":{"type":["integer","null"]}}}},"required":["success","code","message","error","data"]}}}},"403":{"description":"`auth.scope_missing` - the key lacks `versions:write` or `variables:write`, both are required. Also `auth.key_project_restricted` and `auth.product_restricted` for projects and products the key cannot reach.","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","const":false},"code":{"type":"integer","example":400},"message":{"type":"string","example":"Something went wrong."},"error":{"$ref":"#/components/schemas/ApiError"},"data":{"type":"null"},"_req":{"type":"object","properties":{"reqId":{"type":"string"},"resTime":{"type":["integer","null"]}}}},"required":["success","code","message","error","data"]}}}},"404":{"description":"`project.not_found` - unknown project, or `environment.not_found` for an unknown environment slug.","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","const":false},"code":{"type":"integer","example":400},"message":{"type":"string","example":"Something went wrong."},"error":{"$ref":"#/components/schemas/ApiError"},"data":{"type":"null"},"_req":{"type":"object","properties":{"reqId":{"type":"string"},"resTime":{"type":["integer","null"]}}}},"required":["success","code","message","error","data"]}}}},"409":{"description":"`project.ambiguous_product` - the project slug exists under more than one product.","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","const":false},"code":{"type":"integer","example":400},"message":{"type":"string","example":"Something went wrong."},"error":{"$ref":"#/components/schemas/ApiError"},"data":{"type":"null"},"_req":{"type":"object","properties":{"reqId":{"type":"string"},"resTime":{"type":["integer","null"]}}}},"required":["success","code","message","error","data"]}}}},"500":{"description":"Unexpected server error (`server.error`).","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","const":false},"code":{"type":"integer","example":400},"message":{"type":"string","example":"Something went wrong."},"error":{"$ref":"#/components/schemas/ApiError"},"data":{"type":"null"},"_req":{"type":"object","properties":{"reqId":{"type":"string"},"resTime":{"type":["integer","null"]}}}},"required":["success","code","message","error","data"]}}}}},"x-envless-scopes":["versions:write","variables:write"],"parameters":[{"name":"slug","in":"path","required":true,"schema":{"type":"string"},"description":"Project slug or project uniqueId."},{"name":"environmentSlug","in":"path","required":true,"schema":{"type":"string"}
1,"description":"Environment slug."},{"name":"product","in":"query","required":false,"schema":{"type":"string"},"description":"Product slug, to disambiguate a project slug shared across products."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"entries":{"type":"array","minItems":1,"maxItems":200,"items":{"type":"object","properties":{"id":{"type":"string","format":"uuid","description":"Entry id from `GET .../versions/entries`. `uniqueId` is accepted as an alias and wins when both are sent."},"uniqueId":{"type":"string","format":"uuid","description":"Alias for `id`."},"value":{"type":"string","minLength":1,"maxLength":20000,"pattern":"^v[12]:","description":"CIPHERTEXT re-encrypted with the new workspace key. The `v1:`/`v2:` prefix is NOT enforced on this endpoint, so a plaintext write here would succeed and corrupt the snapshot. Enforce it in your client.","example":"v1:8Wm3kQ...ciphertext"},"defaultValue":{"type":["string","null"],"maxLength":20000,"pattern":"^v[12]:","description":"CIPHERTEXT re-encrypted with the new key. null or omitted keeps the stored value, it does not clear it."}},"required":["value"]}}},"required":["entries"]}}}}}},"/roles":{"get":{"operationId":"listRoles","tags":["Roles"],"summary":"List roles","description":"Lists every role in the workspace: the three system roles (owner, admin, viewer) plus any custom roles. Use this to get the `roleId` values that POST /members and PATCH /members/{id} require.\\n\\nSystem roles always sort ahead of custom roles regardless of `sortBy`; `sortBy` orders within each group. For system roles, `permissions` is the canonical list computed from the platform catalogue rather than whatever is stored on the row, so it always reflects the current definition of owner/admin/viewer.\\n\\nThe list is read in full and paginated in memory, so `pagination.totalCount` is exact. `search` matches role name and description.","responses":{"200":{"description":"List roles succeeded.","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","const":true},"code":{"type":"integer","example":200},"message":{"type":"string","example":"OK"},"error":{"type":"null"},"data":{"type":"object","properties":{"roles":{"type":"array","items":{"$ref":"#/components/schemas/Role"}},"pagination":{"$ref":"#/components/schemas/Pagination"}},"required":["roles","pagination"]},"_req":{"type":"object","properties":{"reqId":{"type":"string"},"resTime":{"type":["integer","null"]}}}},"required":["success","code","message","error","data"]}}}},"400":{"description":"`request.invalid_pagination` - `limit` or `offset` is not a whole number, or `limit` is outside 1 to 100; `error.field` names the offending parameter.","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","const":false},"code":{"type":"integer","example":400},"message":{"type":"string","example":"Something went wrong."},"error":{"$ref":"#/components/schemas/ApiError"},"data":{"type":"null"},"_req":{"type":"object","properties":{"reqId":{"type":"string"},"resTime":{"type":["integer","null"]}}}},"required":["success","code","message","error","data"]}}}},"401":{"description":"Missing, malformed, revoked or non-member API key (`auth.api_key_*`).","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","const":false},"code":{"type":"integer","example":400},"message":{"type":"string","example":"Something went wrong."},"error":{"$ref":"#/components/schemas/ApiError"},"data":{"type":"null"},"_req":{"type":"object","properties":{"reqId":{"type":"string"},"resTime":{"type":["integer","null"]}}}},"required":["success","code","message","error","data"]}}}},"500":{"description":"Unexpected server error (`server.error`).","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","const":false},"code":{"type":"integer","example":400},"message":{"type":"string","example":"Something went wrong."},"error":{"$ref":"#/components/schemas/ApiError"},"data":{"type":"null"},"_req":{"type":"object","properties":{"reqId":{"type":"string"},"resTime":{"type":["integer","null"]}}}},"required":["success","code","message","error","data"]}}}}},"x-envless-scopes":["roles:read"],"parameters":[{"name":"limit","in":"query","schema":{"type":"integer","minimum":1,"maximum":100,"default":25},"description":"Rows per page, 1 to 100."},{"name":"offset","in":"query","schema":{"type":"integer","minimum":0,"default":0},"description":"Rows to skip."},{"name":"search","in":"query","schema":{"type":"string"},"description":"Case-insensitive substring match on role name and description."},{"name":"sortBy","in":"query","schema":{"type":"string","enum":["updated","created","name"],"default":"name"},"description":"Order within each group. `updated` and `created` are newest first, `name` is A to Z. System roles always come first whatever this is set to. Unrecognised values fall back to `name`."}]},"post":{"operationId":"createRole","tags":["Roles"],"summary":"Create a custom role","description":"Creates a custom role with an explicit permission list. Take the permission strings from GET /permissions - anything not in that catalogue is rejected.\\n\\nTwo separate ceilings apply. First, `workspace:delete` and `billing:manage` can never be granted to a custom role by anyone; asking for either fails validation with HTTP 400 `request.body_invali
1d`. Second, you can only grant permissions you already hold yourself: the requested set is checked against the effective permissions of the user who owns the API key, and anything beyond that fails with HTTP 403 `auth.permission_denied` listing the offending permissions in `message`. An admin therefore cannot mint a role more powerful than admin.\\n\\nNames are trimmed and must be unique within the workspace, case-insensitively. A workspace can hold at most 25 custom roles; system roles do not count against it. Emits `role.created`.","responses":{"201":{"description":"Create a custom role succeeded.","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","const":true},"code":{"type":"integer","example":200},"message":{"type":"string","example":"OK"},"error":{"type":"null"},"data":{"$ref":"#/components/schemas/Role"},"_req":{"type":"object","properties":{"reqId":{"type":"string"},"resTime":{"type":["integer","null"]}}}},"required":["success","code","message","error","data"]}}}}
1,"400":{"description":"`request.body_invalid` - the name, description or permission list is invalid, including a permission that no custom role may hold.","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","const":false},"code":{"type":"integer","example":400},"message":{"type":"string","example":"Something went wrong."},"error":{"$ref":"#/components/schemas/ApiError"},"data":{"type":"null"},"_req":{"type":"object","properties":{"reqId":{"type":"string"},"resTime":{"type":["integer","null"]}}}},"required":["success","code","message","error","data"]}}}},"401":{"description":"Missing, malformed, revoked or non-member API key (`auth.api_key_*`).","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","const":false},"code":{"type":"integer","example":400},"message":{"type":"string","example":"Something went wrong."},"error":{"$ref":"#/components/schemas/ApiError"},"data":{"type":"null"},"_req":{"type":"object","properties":{"reqId":{"type":"string"},"resTime":{"type":["integer","null"]}}}},"required":["success","code","message","error","data"]}}}},"403":{"description":"`auth.permission_denied` - you requested a permission you do not hold yourself.","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","const":false},"code":{"type":"integer","example":400},"message":{"type":"string","example":"Something went wrong."},"error":{"$ref":"#/components/schemas/ApiError"},"data":{"type":"null"},"_req":{"type":"object","properties":{"reqId":{"type":"string"},"resTime":{"type":["integer","null"]}}}},"required":["success","code","message","error","data"]}}}},"409":{"description":"`role.name_conflict` - a role with that name already exists.","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","const":false},"code":{"type":"integer","example":400},"message":{"type":"string","example":"Something went wrong."},"error":{"$ref":"#/components/schemas/ApiError"},"data":{"type":"null"},"_req":{"type":"object","properties":{"reqId":{"type":"string"},"resTime":{"type":["integer","null"]}}}},"required":["success","code","message","error","data"]}}}},"500":{"description":"Unexpected server error (`server.error`).","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","const":false},"code":{"type":"integer","example":400},"message":{"type":"string","example":"Something went wrong."},"error":{"$ref":"#/components/schemas/ApiError"},"data":{"type":"null"},"_req":{"type":"object","properties":{"reqId":{"type":"string"},"resTime":{"type":["integer","null"]}}}},"required":["success","code","message","error","data"]}}}}},"x-envless-scopes":["roles:write"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"name":{"type":"string","minLength":2,"maxLength":40,"description":"Role name, 2 to 40 characters after trimming. Must not collide with an existing role name in the workspace, comparison is case-insensitive.","example":"Billing"},"description":{"type":["string","null"],"maxLength":200,"description":"Optional human description, up to 200 characters."},"permissions":{"type":"array","items":{"type":"string"},"description":"Exact permission strings from GET /permissions where `assignableToCustomRoles` is true. An empty array is valid and creates a role with no permissions.","example":["projects:read","variables:read"]}},"required":["name","permissions"]}}}}}},"/roles/{id}":{"get":{"operationId":"getRole","tags":["Roles"],"summary":"Get a role","description":"Returns one role by id. The id must be the role\'s id from GET /roles; names and slugs are not accepted.\\n\\nFor a system role, `permissions` is the canonical catalogue list for that `systemKey` (`owner`, `admin` or `viewer`) rather than the stored column, so it stays correct as the platform\'s permission set evolves. `systemKey` is null for custom roles.","responses":{"200":{"description":"Get a role succeeded.","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","const":true},"code":{"type":"integer","example":200},"message":{"type":"string","example":"OK"},"error":{"type":"null"},"data":{"$ref":"#/components/schemas/Role"},"_req":{"type":"object","properties":{"reqId":{"type":"string"},"resTime":{"type":["integer","null"]}}}},"required":["success","code","message","error","data"]}}}},"401":{"description":"Missing, malformed, revoked or non-member API key (`auth.api_key_*`).","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","const":false},"code":{"type":"integer","example":400},"message":{"type":"string","example":"Something went wrong."},"error":{"$ref":"#/components/schemas/ApiError"},"data":{"type":"null"},"_req":{"type":"object","properties":{"reqId":{"type":"string"},"resTime":{"type":["integer","null"]}}}},"required":["success","code","message","error","data"]}}}}
1,"404":{"description":"`role.not_found` - no role with that id exists in this workspace, or it has been deleted.","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","const":false},"code":{"type":"integer","example":400},"message":{"type":"string","example":"Something went wrong."},"error":{"$ref":"#/components/schemas/ApiError"},"data":{"type":"null"},"_req":{"type":"object","properties":{"reqId":{"type":"string"},"resTime":{"type":["integer","null"]}}}},"required":["success","code","message","error","data"]}}}},"500":{"description":"Unexpected server error (`server.error`).","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","const":false},"code":{"type":"integer","example":400},"message":{"type":"string","example":"Something went wrong."},"error":{"$ref":"#/components/schemas/ApiError"},"data":{"type":"null"},"_req":{"type":"object","properties":{"reqId":{"type":"string"},"resTime":{"type":["integer","null"]}}}},"required":["success","code","message","error","data"]}}}}},"x-envless-scopes":["roles:read"],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"},"description":"Role id from GET /roles. No name or slug form is accepted."}]},"patch":{"operationId":"updateRole","tags":["Roles"],"summary":"Update a custom role","description":"Updates a custom role. Every field is optional, but `permissions` is a full replacement, not a merge - send the complete list you want the role to end up with, or omit the key entirely to leave permissions untouched. Sending `\\"description\\": null` clears the description.\\n\\nSystem roles are immutable. Attempting to update owner, admin or viewer returns HTTP 409 - and, because of how the controller maps conflicts, it carries the code `role.name_conflict` even though nothing about the name conflicted. Check `isSystem` before patching.\\n\\nThe same two ceilings as role creation apply to `permissions`: `workspace:delete` and `billing:manage` are rejected at validation with 400 `request.body_invali
1d`, and anything the API key\'s owner does not hold themselves is rejected with 403 `auth.permission_denied`.\\n\\nA permission change takes effect immediately for every member holding the role. Existing API keys owned by those members are not re-clamped by this route (only a member\'s role change does that), so a key can keep a scope its owner\'s role no longer grants until the key is updated or the member\'s role is changed. Emits `role.updated`.","responses":{"200":{"description":"Update a custom role succeeded.","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","const":true},"code":{"type":"integer","example":200},"message":{"type":"string","example":"OK"},"error":{"type":"null"},"data":{"$ref":"#/components/schemas/Role"},"_req":{"type":"object","properties":{"reqId":{"type":"string"},"resTime":{"type":["integer","null"]}}}},"required":["success","code","message","error","data"]}}}},"400":{"description":"`request.body_invalid` - the name, description or permission list is invalid.","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","const":false},"code":{"type":"integer","example":400},"message":{"type":"string","example":"Something went wrong."},"error":{"$ref":"#/components/schemas/ApiError"},"data":{"type":"null"},"_req":{"type":"object","properties":{"reqId":{"type":"string"},"resTime":{"type":["integer","null"]}}}},"required":["success","code","message","error","data"]}}}},"401":{"description":"Missing, malformed, revoked or non-member API key (`auth.api_key_*`).","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","const":false},"code":{"type":"integer","example":400},"message":{"type":"string","example":"Something went wrong."},"error":{"$ref":"#/components/schemas/ApiError"},"data":{"type":"null"},"_req":{"type":"object","properties":{"reqId":{"type":"string"},"resTime":{"type":["integer","null"]}}}},"required":["success","code","message","error","data"]}}}},"403":{"description":"`auth.permission_denied` - you requested a permission you do not hold yourself.","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","const":false},"code":{"type":"integer","example":400},"message":{"type":"string","example":"Something went wrong."},"error":{"$ref":"#/components/schemas/ApiError"},"data":{"type":"null"},"_req":{"type":"object","properties":{"reqId":{"type":"string"},"resTime":{"type":["integer","null"]}}}},"required":["success","code","message","error","data"]}}}},"404":{"description":"`role.not_found` - no role matches.","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","const":false},"code":{"type":"integer","example":400},"message":{"type":"string","example":"Something went wrong."},"error":{"$ref":"#/components/schemas/ApiError"},"data":{"type":"null"},"_req":{"type":"object","properties":{"reqId":{"type":"string"},"resTime":{"type":["integer","null"]}}}},"required":["success","code","message","error","data"]}}}},"409":{"description":"`role.name_conflict` - another role already has that name.","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","const":false},"code":{"type":"integer","example":400},"message":{"type":"string","example":"Something went wrong."},"error":{"$ref":"#/components/schemas/ApiError"},"data":{"type":"null"},"_req":{"type":"object","properties":{"reqId":{"type":"string"},"resTime":{"type":["integer","null"]}}}},"required":["success","code","message","error","data"]}}}},"500":{"description":"Unexpected server error (`server.error`).","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","const":false},"code":{"type":"integer","example":400},"message":{"type":"string","example":"Something went wrong."},"error":{"$ref":"#/components/schemas/ApiError"},"data":{"type":"null"},"_req":{"type":"object","properties":{"reqId":{"type":"string"},"resTime":{"type":["integer","null"]}}}},"required":["success","code","message","error","data"]}}}}},"x-envless-scopes":["roles:write"],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"},"description":"Role id from GET /roles. Must be a custom role."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"name":{"type":"string","minLength":2,"maxLength":40,"description":"New name, 2 to 40 characters after trimming, unique in the workspace case-insensitively.","example":"Billing"},"description":{"type":["string","null"],"maxLength":200,"description":"New description, up to 200 characters. Pass null to clear it, omit the key to leave it alone."},"permissions":{"type":"array","items":{"type":"string"},"description":"Complete replacement permission list from GET /permissions. Omit to leave permissions unchanged.","example":["projects:read","variables:read"]}},"additionalProperties":false}}}}},"delete":{"operationId":"deleteRole","tags":["Roles"],"summary":"Delete a custom role","description":"Deletes a custom role. The role must be unused: reassign every member holding it and revoke every pending invite that references it first, otherwise the delete is refused and tells you how many of each are in the way. System roles can never be deleted.\\n\\nThe delete is soft; the id is not reused. Emits `role.deleted`.","responses":{"200":{"description":"Delete a custom role succeeded.","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","const":true},"code":{"type":"integer","example":200},"message":{"type":"string","example":"OK"},"error":{"type":"null"},"data":{"type":"object","properties":{"id":{"type":"string"},"name":{"type":"string","description":"Name of the deleted role."}},"required":["id","name"]},"_req":{"type":"object","properties":{"reqId":{"type":"string"},"resTime":{"type":["integer","null"]}}}},"required":["success","code","message","error","data"]}}}},"401":{"description":"Missing, malformed, revoked or non-member API key (`auth.api_key_*`).","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","const":false},"code":{"type":"integer","example":400},"message":{"type":"string","example":"Something went wrong."},"error":{"$ref":"#/components/schemas/ApiError"},"data":{"type":"null"},"_req":{"type":"object","properties":{"reqId":{"type":"string"},"resTime":{"type":["integer","null"]}}}},"required":["success","code","message","error","data"]}}}},"403":{"description":"`auth.scope_missing` - the key lacks roles:write.","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","const":false},"code":{"type":"integer","example":400},"message":{"type":"string","example":"Something went wrong."},"error":{"$ref":"#/components/schemas/ApiError"},"data":{"type":"null"},"_req":{"type":"object","properties":{"reqId":{"type":"string"},"resTime":{"type":["integer","null"]}}}},"required":["success","code","message","error","data"]}}}}
1,"404":{"description":"`role.not_found` - no role matches.","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","const":false},"code":{"type":"integer","example":400},"message":{"type":"string","example":"Something went wrong."},"error":{"$ref":"#/components/schemas/ApiError"},"data":{"type":"null"},"_req":{"type":"object","properties":{"reqId":{"type":"string"},"resTime":{"type":["integer","null"]}}}},"required":["success","code","message","error","data"]}}}},"409":{"description":"`role.in_use` - members or pending invites still reference the role.","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","const":false},"code":{"type":"integer","example":400},"message":{"type":"string","example":"Something went wrong."},"error":{"$ref":"#/components/schemas/ApiError"},"data":{"type":"null"},"_req":{"type":"object","properties":{"reqId":{"type":"string"},"resTime":{"type":["integer","null"]}}}},"required":["success","code","message","error","data"]}}}},"500":{"description":"Unexpected server error (`server.error`).","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","const":false},"code":{"type":"integer","example":400},"message":{"type":"string","example":"Something went wrong."},"error":{"$ref":"#/components/schemas/ApiError"},"data":{"type":"null"},"_req":{"type":"object","properties":{"reqId":{"type":"string"},"resTime":{"type":["integer","null"]}}}},"required":["success","code","message","error","data"]}}}}},"x-envless-scopes":["roles:write"],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"},"description":"Role id from GET /roles. Must be a custom role with no members and no pending invites attached."}]}},"/variables/{id}":{"get":{"operationId":"getVariable","tags":["Variables"],"summary":"Get a variable by id","description":"Id-addressed twin of `GET /projects/{slug}/environments/{environmentSlug}/variables/{name}`. Use this when you already hold a variable id, for example from a list response or a webhook payload, and do not want to know or care which project and environment it lives in. The lookup is scoped to the workspace behind the API key and joins through the environment and project, so soft-deleted variables and variables in deleted environments or projects are invisible.\\n\\nThe name-addressed route is the one to use when you know the environment and the human name. This one is stable across renames, since the id never changes.\\n\\n`value` and `defaultValue` are **ciphertext** and are returned untouched. The server cannot decrypt them.\\n\\nOrder of checks matters for key-restricted keys: a variable that does not exist in the workspace returns 404 before any project restriction is evaluated, so a 403 here confirms the variable exists.","responses":{"200":{"description":"Get a variable by id succeeded.","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","const":true},"code":{"type":"integer","example":200},"message":{"type":"string","example":"OK"},"error":{"type":"null"},"data":{"$ref":"#/components/schemas/Variable"},"_req":{"type":"object","properties":{"reqId":{"type":"string"},"resTime":{"type":["integer","null"]}}}},"required":["success","code","message","error","data"]}}}},"401":{"description":"Missing, malformed, revoked or non-member API key (`auth.api_key_*`).","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","const":false},"code":{"type":"integer","example":400},"message":{"type":"string","example":"Something went wrong."},"error":{"$ref":"#/components/schemas/ApiError"},"data":{"type":"null"},"_req":{"type":"object","properties":{"reqId":{"type":"string"},"resTime":{"type":["integer","null"]}}}},"required":["success","code","message","error","data"]}}}},"402":{"description":"`plan.upgrade_required` - the variable\'s project is locked because the workspace exceeds its plan\'s project limit.","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","const":false},"code":{"type":"integer","example":400},"message":{"type":"string","example":"Something went wrong."},"error":{"$ref":"#/components/schemas/ApiError"},"data":{"type":"null"},"_req":{"type":"object","properties":{"reqId":{"type":"string"},"resTime":{"type":["integer","null"]}}}},"required":["success","code","message","error","data"]}}}},"403":{"description":"`auth.key_project_restricted` - the key\'s project allowlist excludes the variable\'s project, or `auth.product_restricted` when the key owner cannot access the private product it belongs to.","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","const":false},"code":{"type":"integer","example":400},"message":{"type":"string","example":"Something went wrong."},"error":{"$ref":"#/components/schemas/ApiError"},"data":{"type":"null"},"_req":{"type":"object","properties":{"reqId":{"type":"string"},"resTime":{"type":["integer","null"]}}}},"required":["success","code","message","error","data"]}}}}
1,"404":{"description":"`variable.not_found` - no live variable with that id in this workspace, including when its environment or project has been deleted. Sent with `error: null`.","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","const":false},"code":{"type":"integer","example":400},"message":{"type":"string","example":"Something went wrong."},"error":{"$ref":"#/components/schemas/ApiError"},"data":{"type":"null"},"_req":{"type":"object","properties":{"reqId":{"type":"string"},"resTime":{"type":["integer","null"]}}}},"required":["success","code","message","error","data"]}}}},"500":{"description":"Unexpected server error (`server.error`).","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","const":false},"code":{"type":"integer","example":400},"message":{"type":"string","example":"Something went wrong."},"error":{"$ref":"#/components/schemas/ApiError"},"data":{"type":"null"},"_req":{"type":"object","properties":{"reqId":{"type":"string"},"resTime":{"type":["integer","null"]}}}},"required":["success","code","message","error","data"]}}}}},"x-envless-scopes":["variables:read"],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"},"description":"Variable uniqueId (uuid v7). Names are not accepted on this route."}]},"patch":{"operationId":"updateVariableById","tags":["Variables"],"summary":"Update a variable by id","description":"Id-addressed twin of `PATCH /projects/{slug}/environments/{environmentSlug}/variables/{name}`, with identical body and semantics. Prefer this one in sync clients that already track ids, since it survives renames and needs no project or environment lookup.\\n\\n**`value` is ciphertext** and must start with `v1:` or `v2:`, otherwise 400 `variable.ciphertext_invalid` with `error.field: \\"value\\"`. **`defaultValue` is ciphertext too**, same workspace key and same prefix, `null` clears it and omitting leaves it alone. The server holds no key and cannot encrypt on your behalf.\\n\\nNote the ordering quirk: the variable is looked up before the ciphertext is validated on this route, the reverse of the name-addressed route, so a bad ciphertext against an unknown id returns 404 rather than 400.","responses":{"200":{"description":"Update a variable by id succeeded.","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","const":true},"code":{"type":"integer","example":200},"message":{"type":"string","example":"OK"},"error":{"type":"null"},"data":{"$ref":"#/components/schemas/Variable"},"_req":{"type":"object","properties":{"reqId":{"type":"string"},"resTime":{"type":["integer","null"]}}}},"required":["success","code","message","error","data"]}}}},"400":{"description":"`variable.ciphertext_invalid` - `value` or `defaultValue` is not `v1:`/`v2:` ciphertext, with `error.field` naming it. A non-JSON body and service-level validation failures also return 400, but with `error: null`.","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","const":false},"code":{"type":"integer","example":400},"message":{"type":"string","example":"Something went wrong."},"error":{"$ref":"#/components/schemas/ApiError"},"data":{"type":"null"},"_req":{"type":"object","properties":{"reqId":{"type":"string"},"resTime":{"type":["integer","null"]}}}},"required":["success","code","message","error","data"]}}}},"401":{"description":"Missing, malformed, revoked or non-member API key (`auth.api_key_*`).","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","const":false},"code":{"type":"integer","example":400},"message":{"type":"string","example":"Something went wrong."},"error":{"$ref":"#/components/schemas/ApiError"},"data":{"type":"null"},"_req":{"type":"object","properties":{"reqId":{"type":"string"},"resTime":{"type":["integer","null"]}}}},"required":["success","code","message","error","data"]}}}},"402":{"description":"`plan.upgrade_required` - the variable\'s project is locked by the plan\'s project limit.","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","const":false},"code":{"type":"integer","example":400},"message":{"type":"string","example":"Something went wrong."},"error":{"$ref":"#/components/schemas/ApiError"},"data":{"type":"null"},"_req":{"type":"object","properties":{"reqId":{"type":"string"},"resTime":{"type":["integer","null"]}}}},"required":["success","code","message","error","data"]}}}},"403":{"description":"`auth.key_project_restricted` - the key\'s project allowlist excludes the variable\'s project, or `auth.product_restricted` for an inaccessible private product.","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","const":false},"code":{"type":"integer","example":400},"message":{"type":"string","example":"Something went wrong."},"error":{"$ref":"#/components/schemas/ApiError"},"data":{"type":"null"},"_req":{"type":"object","properties":{"reqId":{"type":"string"},"resTime":{"type":["integer","null"]}}}},"required":["success","code","message","error","data"]}}}}
1,"404":{"description":"`variable.not_found` - no live variable with that id in this workspace. Sent with `error: null`.","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","const":false},"code":{"type":"integer","example":400},"message":{"type":"string","example":"Something went wrong."},"error":{"$ref":"#/components/schemas/ApiError"},"data":{"type":"null"},"_req":{"type":"object","properties":{"reqId":{"type":"string"},"resTime":{"type":["integer","null"]}}}},"required":["success","code","message","error","data"]}}}},"409":{"description":"`variable.name_conflict` - a rename collides with another live variable in the same environment, compared without regard to case. Sent with `error: null`.","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","const":false},"code":{"type":"integer","example":400},"message":{"type":"string","example":"Something went wrong."},"error":{"$ref":"#/components/schemas/ApiError"},"data":{"type":"null"},"_req":{"type":"object","properties":{"reqId":{"type":"string"},"resTime":{"type":["integer","null"]}}}},"required":["success","code","message","error","data"]}}}},"500":{"description":"Unexpected server error (`server.error`).","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","const":false},"code":{"type":"integer","example":400},"message":{"type":"string","example":"Something went wrong."},"error":{"$ref":"#/components/schemas/ApiError"},"data":{"type":"null"},"_req":{"type":"object","properties":{"reqId":{"type":"string"},"resTime":{"type":["integer","null"]}}}},"required":["success","code","message","error","data"]}}}}},"x-envless-scopes":["variables:write"],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"},"description":"Variable uniqueId (uuid v7)."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","minProperties":1,"properties":{"name":{"type":"string","minLength":1,"maxLength":100,"pattern":"^[A-Za-z_][A-Za-z0-9_]*$","example":"STRIPE_SECRET_KEY","description":"New name. Must match `^[A-Za-z_][A-Za-z0-9_]*$` and be 1 to 100 characters, is stored with the casing you send, and is rejected when another live variable in the same environment already holds it, compared without regard to case."},"value":{"type":"string","minLength":1,"maxLength":20000,"pattern":"^v[12]:","description":"CIPHERTEXT. Must start with `v1:` or `v2:`.","example":"v1:8Wm3kQ...ciphertext"},"type":{"type":"string","enum":["string","number","boolean"],"example":"string"},"isSecret":{"type":"boolean"},"visibility":{"type":"string","enum":["server","client"],"example":"server"},"required":{"type":"boolean","example":false},"defaultValue":{"type":["string","null"],"maxLength":20000,"pattern":"^v[12]:","description":"CIPHERTEXT, same key and prefix as `value`. `null` clears it."}}}}}}},"delete":{"operationId":"deleteVariableById","tags":["Variables"],"summary":"Delete a variable by id","description":"Id-addressed twin of `DELETE /projects/{slug}/environments/{environmentSlug}/variables/{name}`. Soft-deletes the variable, so version snapshots taken earlier keep their copy and a rollback can restore it.\\n\\nDeleting an id that does not exist, or that has already been deleted, is a 404 rather than a no-op.","responses":{"200":{"description":"Delete a variable by id succeeded.","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","const":true},"code":{"type":"integer","example":200},"message":{"type":"string","example":"OK"},"error":{"type":"null"},"data":{"type":"object","properties":{"id":{"type":"string"},"name":{"type":"string","example":"STRIPE_SECRET_KEY"},"environmentId":{"type":"string"}},"required":["id","name","environmentId"]},"_req":{"type":"object","properties":{"reqId":{"type":"string"},"resTime":{"type":["integer","null"]}}}},"required":["success","code","message","error","data"]}}}},"401":{"description":"Missing, malformed, revoked or non-member API key (`auth.api_key_*`).","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","const":false},"code":{"type":"integer","example":400},"message":{"type":"string","example":"Something went wrong."},"error":{"$ref":"#/components/schemas/ApiError"},"data":{"type":"null"},"_req":{"type":"object","properties":{"reqId":{"type":"string"},"resTime":{"type":["integer","null"]}}}},"required":["success","code","message","error","data"]}}}},"402":{"description":"`plan.upgrade_required` - the variable\'s project is locked by the plan\'s project limit.","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","const":false},"code":{"type":"integer","example":400},"message":{"type":"string","example":"Something went wrong."},"error":{"$ref":"#/components/schemas/ApiError"},"data":{"type":"null"},"_req":{"type":"object","properties":{"reqId":{"type":"string"},"resTime":{"type":["integer","null"]}}}},"required":["success","code","message","error","data"]}}}},"403":{"description":"`auth.key_project_restricted` - the key\'s project allowlist excludes the variable\'s project, or `auth.product_restricted` for an inaccessible private product.","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","const":false},"code":{"type":"integer","example":400},"message":{"type":"string","example":"Something went wrong."},"error":{"$ref":"#/components/schemas/ApiError"},"data":{"type":"null"},"_req":{"type":"object","properties":{"reqId":{"type":"string"},"resTime":{"type":["integer","null"]}}}},"required":["success","code","message","error","data"]}}}}
1,"404":{"description":"`variable.not_found` - no live variable with that id in this workspace. Sent with `error: null`.","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","const":false},"code":{"type":"integer","example":400},"message":{"type":"string","example":"Something went wrong."},"error":{"$ref":"#/components/schemas/ApiError"},"data":{"type":"null"},"_req":{"type":"object","properties":{"reqId":{"type":"string"},"resTime":{"type":["integer","null"]}}}},"required":["success","code","message","error","data"]}}}},"500":{"description":"Unexpected server error (`server.error`).","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","const":false},"code":{"type":"integer","example":400},"message":{"type":"string","example":"Something went wrong."},"error":{"$ref":"#/components/schemas/ApiError"},"data":{"type":"null"},"_req":{"type":"object","properties":{"reqId":{"type":"string"},"resTime":{"type":["integer","null"]}}}},"required":["success","code","message","error","data"]}}}}},"x-envless-scopes":["variables:write"],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"},"description":"Variable uniqueId (uuid v7)."}]}},"/versions/{id}":{"get":{"operationId":"getVersion","tags":["Versions"],"summary":"Get a version","description":"Returns one snapshot with its captured variables, addressed by version id and scoped to the workspace behind the API key. There is no environment-scoped read for a single version, ids are the only way in.\\n\\nEach entry is `{ name, value }` and **`value` is the ciphertext exactly as it stood when the version was taken**. The server cannot decrypt it. Decrypt with the workspace key that was in force at snapshot time, which is the reason a passphrase rotation must rewrite version entries as well as live variables.\\n\\nThe snapshot also stores `defaultValue`, `type`, `isSecret`, `visibility` and `required` per entry, and a rollback restores all of them, but this response deliberately exposes only `name` and `value`. Use `GET .../versions/entries` if you need the stored `defaultValue` ciphertext.\\n\\nEntries are sorted by name. Requires both `versions:read` and `variables:read`.\\n\\n**Plan gate.** Free workspaces can read only the latest version of each environment. Any older version returns 402 `plan.upgrade_required` with `error.resource: \\"version\\"` and `data: null`; the check runs after the existence check, so a 402 confirms the version exists. Dev, Team and Enterprise read every version.","responses":{"200":{"description":"Get a version succeeded.","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","const":true},"code":{"type":"integer","example":200},"message":{"type":"string","example":"OK"},"error":{"type":"null"},"data":{"type":"object","properties":{"id":{"type":"string"},"label":{"type":"string"},"note":{"type":["string","null"]},"variableCount":{"type":"integer"},"environmentId":{"type":"string"},"createdAt":{"type":"string","format":"date-time"},"variables":{"type":"array","items":{"type":"object","properties":{"name":{"type":"string","example":"STRIPE_SECRET_KEY"},"value":{"type":["string","null"],"description":"CIPHERTEXT as captured. Decrypt with the workspace key in force when the version was taken."}},"required":["name"]}}},"required":["id","label","variableCount","environmentId","createdAt","variables"]},"_req":{"type":"object","properties":{"reqId":{"type":"string"},"resTime":{"type":["integer","null"]}}}},"required":["success","code","message","error","data"]}}}},"401":{"description":"Missing, malformed, revoked or non-member API key (`auth.api_key_*`).","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","const":false},"code":{"type":"integer","example":400},"message":{"type":"string","example":"Something went wrong."},"error":{"$ref":"#/components/schemas/ApiError"},"data":{"type":"null"},"_req":{"type":"object","properties":{"reqId":{"type":"string"},"resTime":{"type":["integer","null"]}}}},"required":["success","code","message","error","data"]}}}},"402":{"description":"`plan.upgrade_required` - the version\'s project is locked by the plan\'s project limit, or the workspace is on the Free plan and the version is not the latest one in its environment. In the second case `error.resource` is `version` and `data` is null; upgrade to read older versions.","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","const":false},"code":{"type":"integer","example":400},"message":{"type":"string","example":"Something went wrong."},"error":{"$ref":"#/components/schemas/ApiError"},"data":{"type":"null"},"_req":{"type":"object","properties":{"reqId":{"type":"string"},"resTime":{"type":["integer","null"]}}}},"required":["success","code","message","error","data"]}}}},"403":{"description":"`auth.scope_missing` - the key lacks `versions:read` or `variables:read`, both are required. Also `auth.key_project_restricted` and `auth.product_restricted` when the key or its owner cannot reach the version\'s project or product.","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","const":false},"code":{"type":"integer","example":400},"message":{"type":"string","example":"Something went wrong."},"error":{"$ref":"#/components/schemas/ApiError"},"data":{"type":"null"},"_req":{"type":"object","properties":{"reqId":{"type":"string"},"resTime":{"type":["integer","null"]}}}},"required":["success","code","message","error","data"]}}}}
1,"404":{"description":"`version.not_found` - no version with that id in this workspace. The check runs before any project restriction, so a 403 on this route confirms the version exists. Sent with `error: null`.","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","const":false},"code":{"type":"integer","example":400},"message":{"type":"string","example":"Something went wrong."},"error":{"$ref":"#/components/schemas/ApiError"},"data":{"type":"null"},"_req":{"type":"object","properties":{"reqId":{"type":"string"},"resTime":{"type":["integer","null"]}}}},"required":["success","code","message","error","data"]}}}},"500":{"description":"Unexpected server error (`server.error`).","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","const":false},"code":{"type":"integer","example":400},"message":{"type":"string","example":"Something went wrong."},"error":{"$ref":"#/components/schemas/ApiError"},"data":{"type":"null"},"_req":{"type":"object","properties":{"reqId":{"type":"string"},"resTime":{"type":["integer","null"]}}}},"required":["success","code","message","error","data"]}}}}},"x-envless-scopes":["versions:read","variables:read"],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"},"description":"Version uniqueId (uuid v7). Labels such as `v3` are not accepted."}]}},"/versions/{id}/rollback":{"post":{"operationId":"rollbackVersion","tags":["Versions"],"summary":"Roll back to a version","description":"Restores an environment to a snapshot, in one transaction behind the same per-environment advisory lock that `variables/apply` uses. The environment is derived from the version, there is no environment in the path.\\n\\nWhat it does, by name: variables present in the snapshot but missing live are re-created, variables present in both are overwritten when anything differs (`value`, `type`, `isSecret`, `visibility`, `required`, `defaultValue`), and live variables absent from the snapshot are soft-deleted. Ids are not preserved, a re-created variable gets a new id, so any client caching ids must re-read afterwards.\\n\\n**Rollback does not snapshot the current state first.** Call `POST .../versions` before rolling back if you might want to come back.\\n\\nThe restored ciphertext is whatever was stored in the snapshot, copied verbatim. If the workspace passphrase was rotated without also re-encrypting the version entries, this call succeeds and writes values that no longer decrypt under the current key. Nothing warns you. Rotate version entries whenever you rotate live variables.\\n\\nRequires both `versions:write` and `variables:write`.\\n\\n**Plan gate.** Rollback needs a paid plan. On Free every rollback, including one to the latest version, returns 402 `plan.upgrade_required` with `error.resource: \\"version\\"` and nothing is restored. Dev, Team and Enterprise can roll back to any version.","responses":{"200":{"description":"Roll back to a version succeeded.","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","const":true},"code":{"type":"integer","example":200},"message":{"type":"string","example":"OK"},"error":{"type":"null"},"data":{"type":"object","properties":{"versionLabel":{"type":"string","description":"Label of the version that was restored, for example `v3`."},"added":{"type":"integer","description":"Variables re-created because they were in the snapshot but not live. New ids."},"updated":{"type":"integer","description":"Live variables overwritten because at least one field differed."},"removed":{"type":"integer","description":"Live variables soft-deleted because the snapshot did not contain them."}},"required":["versionLabel","added","updated","removed"]},"_req":{"type":"object","properties":{"reqId":{"type":"string"},"resTime":{"type":["integer","null"]}}}},"required":["success","code","message","error","data"]}}}},"401":{"description":"Missing, malformed, revoked or non-member API key (`auth.api_key_*`).","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","const":false},"code":{"type":"integer","example":400},"message":{"type":"string","example":"Something went wrong."},"error":{"$ref":"#/components/schemas/ApiError"},"data":{"type":"null"},"_req":{"type":"object","properties":{"reqId":{"type":"string"},"resTime":{"type":["integer","null"]}}}},"required":["success","code","message","error","data"]}}}},"402":{"description":"`plan.upgrade_required` - the version\'s project is locked by the plan\'s project limit, or the workspace is on the Free plan, where rollback is unavailable for every version including the latest. In the plan case `error.resource` is `version` and nothing is restored.","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","const":false},"code":{"type":"integer","example":400},"message":{"type":"string","example":"Something went wrong."},"error":{"$ref":"#/components/schemas/ApiError"},"data":{"type":"null"},"_req":{"type":"object","properties":{"reqId":{"type":"string"},"resTime":{"type":["integer","null"]}}}},"required":["success","code","message","error","data"]}}}},"403":{"description":"`auth.scope_missing` - the key lacks `versions:write` or `variables:write`, both are required. Also `auth.key_project_restricted` and `auth.product_restricted` when the key or its owner cannot reach the version\'s project or product.","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","const":false},"code":{"type":"integer","example":400},"message":{"type":"string","example":"Something went wrong."},"error":{"$ref":"#/components/schemas/ApiError"},"data":{"type":"null"},"_req":{"type":"object","properties":{"reqId":{"type":"string"},"resTime":{"type":["integer","null"]}}}},"required":["success","code","message","error","data"]}}}}
1,"404":{"description":"`version.not_found` - no version with that id in this workspace, or the version disappeared between the lookup and the transaction. Sent with `error: null`.","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","const":false},"code":{"type":"integer","example":400},"message":{"type":"string","example":"Something went wrong."},"error":{"$ref":"#/components/schemas/ApiError"},"data":{"type":"null"},"_req":{"type":"object","properties":{"reqId":{"type":"string"},"resTime":{"type":["integer","null"]}}}},"required":["success","code","message","error","data"]}}}},"500":{"description":"Unexpected server error (`server.error`).","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","const":false},"code":{"type":"integer","example":400},"message":{"type":"string","example":"Something went wrong."},"error":{"$ref":"#/components/schemas/ApiError"},"data":{"type":"null"},"_req":{"type":"object","properties":{"reqId":{"type":"string"},"resTime":{"type":["integer","null"]}}}},"required":["success","code","message","error","data"]}}}}},"x-envless-scopes":["versions:write","variables:write"],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"},"description":"Version uniqueId (uuid v7) to restore. Must belong to the workspace behind the key."}]}},"/webhooks":{"get":{"operationId":"listWebhooks","tags":["Webhooks"],"summary":"List webhook endpoints","description":"Lists the workspace\'s webhook endpoints. Signing secrets are never included - each endpoint exposes only `secretLastFour`, which is enough to confirm which secret a receiver is verifying against.\\n\\nOrdering defaults to `name`, **A to Z**. `order=asc` and `order=desc` switch to `createdAt`, oldest or newest first; any other value falls back to name order.\\n\\n`search` matches `name`, `url` and `description`. Deleted endpoints are excluded permanently.\\n\\n**Every webhook route, including this read, is refused for project-restricted API keys** with 403 `auth.key_project_restricted`. Webhook endpoints are workspace-wide and subscribe to workspace-wide events, so there is no coherent way to scope them to a project subset. Use a key without a `projectIds` fence.","responses":{"200":{"description":"List webhook endpoints succeeded.","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","const":true},"code":{"type":"integer","example":200},"message":{"type":"string","example":"OK"},"error":{"type":"null"},"data":{"type":"object","properties":{"webhooks":{"type":"array","items":{"$ref":"#/components/schemas/Webhook"}},"pagination":{"$ref":"#/components/schemas/Pagination"}},"required":["webhooks","pagination"]},"_req":{"type":"object","properties":{"reqId":{"type":"string"},"resTime":{"type":["integer","null"]}}}},"required":["success","code","message","error","data"]}}}},"400":{"description":"`request.invalid_pagination` - `limit` or `offset` is not a whole number, or `limit` is outside 1-100.","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","const":false},"code":{"type":"integer","example":400},"message":{"type":"string","example":"Something went wrong."},"error":{"$ref":"#/components/schemas/ApiError"},"data":{"type":"null"},"_req":{"type":"object","properties":{"reqId":{"type":"string"},"resTime":{"type":["integer","null"]}}}},"required":["success","code","message","error","data"]}}}},"401":{"description":"Missing, malformed, revoked or non-member API key (`auth.api_key_*`).","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","const":false},"code":{"type":"integer","example":400},"message":{"type":"string","example":"Something went wrong."},"error":{"$ref":"#/components/schemas/ApiError"},"data":{"type":"null"},"_req":{"type":"object","properties":{"reqId":{"type":"string"},"resTime":{"type":["integer","null"]}}}},"required":["success","code","message","error","data"]}}}},"403":{"description":"`auth.key_project_restricted` - the calling key is fenced to specific projects; webhooks are workspace-wide and have no project dimension.","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","const":false},"code":{"type":"integer","example":400},"message":{"type":"string","example":"Something went wrong."},"error":{"$ref":"#/components/schemas/ApiError"},"data":{"type":"null"},"_req":{"type":"object","properties":{"reqId":{"type":"string"},"resTime":{"type":["integer","null"]}}}},"required":["success","code","message","error","data"]}}}},"500":{"description":"Unexpected server error (`server.error`).","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","const":false},"code":{"type":"integer","example":400},"message":{"type":"string","example":"Something went wrong."},"error":{"$ref":"#/components/schemas/ApiError"},"data":{"type":"null"},"_req":{"type":"object","properties":{"reqId":{"type":"string"},"resTime":{"type":["integer","null"]}}}},"required":["success","code","message","error","data"]}}}}},"x-envless-scopes":["webhooks:read"],"parameters":[{"name":"limit","in":"query","required":false,"schema":{"type":"integer","minimum":1,"maximum":100,"default":25},"description":"Page size. Must be a whole number between 1 and 100."},{"name":"offset","in":"query","required":false,"schema":{"type":"integer","minimum":0,"default":0},"description":"Number of endpoints to skip. Must be a whole number of 0 or greater."},{"name":"search","in":"query","required":false,"schema":{"type":"string"},"description":"Case-insensitive substring match against `name`, `url` and `description`."},{"name":"order","in":"query","required":false,"schema":{"type":"string","enum":["name","asc","desc"],"default":"name"},"description":"`asc` and `desc` sort oldest and newest first by `createdAt`. Anything else, including omitting it, sorts by `name` A to Z."}]},"post":{"operationId":"createWebhook","tags":["Webhooks"],"summary":"Create a webhook endpoint","description":"Registers an HTTPS endpoint and subscribes it to a set of events.\\n\\n**`data.secret` is returned exactly once, on this response.** Reads only ever expose `secretLastFour`. If you lose it, the only way to get a working secret again is `POST /webhooks/{id}/rotate`, which invalidates every signature already in flight. Store it before you do anything else.\\n\\nThe secret is formatted `ev_whsec_<base64url>`. Deliveries are signed per the Standard Webhooks spec and carry `webhook-id`, `webhook-timestamp` and `webhook-signature` headers, plus `Envless-Event` (the event type) and `Envless-Delivery` (the delivery id). The HMAC ke
1y is the **full secret string including the `ev_whsec_` prefix** - if your verification library expects a base64 secret, pass `base64(utf8(secret))`. Do not strip the prefix.\\n\\n**URL rules, all enforced:** `https` only, at most 2048 characters, no embedded credentials, and the host must be publicly routable. Loopback, private IPv4 ranges, carrier-grade NAT, link-local and unique-local IPv6, `localhost`, cloud metadata hosts, and any host ending `.internal`, `.local`, `.localdomain` or `.home.arpa` are all rejected. Redirects are not followed - a 3xx from your receiver is recorded as a failed attempt, so register the final URL.\\n\\n`eventTypes` must be a non-empty array drawn from `GET /webhooks/event-types`. Unknown names are rejected with 400 and the message names each offender.\\n\\nEndpoints are created `enabled: true`. Delivery is at-least-once with up to 5 attempts, backing off 30s, 2m, 10m, 30m then 1h, with a 10 second request timeout; any 2xx counts as success. Make your handler idempotent on `webhook-id`.\\n\\nA workspace is capped at 20 endpoints and at 500 simultaneously queued deliveries.\\n\\nRefused for project-restricted keys.","responses":{"201":{"description":"Create a webhook endpoint succeeded.","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","const":true},"code":{"type":"integer","example":200},"message":{"type":"string","example":"OK"},"error":{"type":"null"},"data":{"allOf":[{"$ref":"#/components/schemas/Webhook"},{"type":"object","properties":{"secret":{"type":"string","description":"The plaintext signing secret, e.g. `ev_whsec_...`. Returned on this response only. Reads expose just `secretLastFour`; the only way to get a fresh one is a rotation, which breaks in-flight deliveries."}},"required":["secret"]}
1]},"_req":{"type":"object","properties":{"reqId":{"type":"string"},"resTime":{"type":["integer","null"]}}}},"required":["success","code","message","error","data"]}}}},"400":{"description":"`request.body_invalid` - `name` or `url` is missing or not a string; `eventTypes` is absent, empty, or contains a name outside the catalogue (`error.field` is `eventTypes`); the URL is not https, is over 2048 characters, carries credentials, or points at a private, loopback, link-local, metadata or `.internal`/`.local`/`.localdomain`/`.home.arpa` host; or `description` exceeds 200 characters.","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","const":false},"code":{"type":"integer","example":400},"message":{"type":"string","example":"Something went wrong."},"error":{"$ref":"#/components/schemas/ApiError"},"data":{"type":"null"},"_req":{"type":"object","properties":{"reqId":{"type":"string"},"resTime":{"type":["integer","null"]}}}},"required":["success","code","message","error","data"]}}}},"401":{"description":"`auth.api_key_user_missing` - the owner of the calling key could not be resolved, so the endpoint has no creator to attribute.","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","const":false},"code":{"type":"integer","example":400},"message":{"type":"string","example":"Something went wrong."},"error":{"$ref":"#/components/schemas/ApiError"},"data":{"type":"null"},"_req":{"type":"object","properties":{"reqId":{"type":"string"},"resTime":{"type":["integer","null"]}}}},"required":["success","code","message","error","data"]}}}},"403":{"description":"`auth.key_project_restricted` - the calling key is fenced to specific projects; webhooks are workspace-wide and have no project dimension.","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","const":false},"code":{"type":"integer","example":400},"message":{"type":"string","example":"Something went wrong."},"error":{"$ref":"#/components/schemas/ApiError"},"data":{"type":"null"},"_req":{"type":"object","properties":{"reqId":{"type":"string"},"resTime":{"type":["integer","null"]}}}},"required":["success","code","message","error","data"]}}}},"409":{"description":"`request.conflict` - the workspace already has 20 webhook endpoints.","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","const":false},"code":{"type":"integer","example":400},"message":{"type":"string","example":"Something went wrong."},"error":{"$ref":"#/components/schemas/ApiError"},"data":{"type":"null"},"_req":{"type":"object","properties":{"reqId":{"type":"string"},"resTime":{"type":["integer","null"]}}}},"required":["success","code","message","error","data"]}}}},"500":{"description":"Unexpected server error (`server.error`).","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","const":false},"code":{"type":"integer","example":400},"message":{"type":"string","example":"Something went wrong."},"error":{"$ref":"#/components/schemas/ApiError"},"data":{"type":"null"},"_req":{"type":"object","properties":{"reqId":{"type":"string"},"resTime":{"type":["integer","null"]}}}},"required":["success","code","message","error","data"]}}}}},"x-envless-scopes":["webhooks:write"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"name":{"type":"string","minLength":1,"maxLength":64,"description":"Label for the endpoint. Required, trimmed, at most 64 characters.","example":"Billing"},"url":{"type":"string","format":"uri","maxLength":2048,"description":"Required. Must be `https`, at most 2048 characters, free of embedded credentials, and resolve to a public host. Register the final URL - redirects are recorded as failures.","example":"https://example.com/hooks/envless"},"description":{"type":["string","null"],"maxLength":200,"description":"Optional note, at most 200 characters. Empty string is stored as null."},"eventTypes":{"type":"array","minItems":1,"items":{"type":"string"},"description":"Non-empty array of event names from `GET /webhooks/event-types`. Any unrecognised name rejects the whole request.","example":["variable.created","variable.updated"]}},"required":["name","url","eventTypes"]}}}}}},"/webhooks/event-types":{"get":{"operationId":"listEventTypes","tags":["Webhooks"],"summary":"List webhook event types","description":"Returns the authoritative catalogue of event names this API can deliver. `eventTypes` on `POST /webhooks` and `PATCH /webhooks/{id}` is validated against exactly this list, so call it before you build a subscription UI or hardcode a name - anything not present here is rejected with 400.\\n\\nThe list is global, not workspace-specific, and is not paginated: `totalCount` is simply the array length.\\n\\nThe payload envelope your receiver gets is `{ id, type, apiVersion, createdAt, workspaceId, actor: { userId, name, email }, data }`, where `type` is one of these names and `data` is the per-event payload. `apiVersion` is currently `2026-05-31`.\\n\\nThe enum below is a snapshot; treat the live response as the source of truth.\\n\\nRefused for project-restr
1icted keys, like every other webhook route.","responses":{"200":{"description":"List webhook event types succeeded.","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","const":true},"code":{"type":"integer","example":200},"message":{"type":"string","example":"OK"},"error":{"type":"null"},"data":{"type":"object","properties":{"eventTypes":{"type":"array","items":{"type":"string","enum":["workspace.created","workspace.updated","workspace.deleted","product.created","product.updated","product.deleted","product_access.granted","product_access.revoked","project.created","project.updated","project.deleted","environment.created","environment.updated","environment.deleted","environment.exposed","environment.unexposed","environment.example_enabled","environment.example_disabled","variable.created","variable.updated","variable.deleted","variable.bulk_created","variable.bulk_deleted","variable.bulk_updated","variable.applied","variable_version.created","variable_version.rolled_back","member.invited","member.invite_resent","member.invite_revoked","member.accepted","member.updated","member.removed","key.created","key.updated","key.rotated","key.deleted","cli_token.created","cli_token.revoked","role.created","role.updated","role.deleted","subscription.created","subscription.updated","subscription.duplicate_detected","webhook.created","webhook.updated","webhook.deleted","webhook.secret_rotated","webhook.delivery_failed"]},"description":"Every event name that can be subscribed to."},"totalCount":{"type":"integer","description":"Length of `eventTypes`. Not a pagination total - this endpoint returns the whole catalogue."}},"required":["eventTypes","totalCount"]},"_req":{"type":"object","properties":{"reqId":{"type":"string"},"resTime":{"type":["integer","null"]}}}},"required":["success","code","message","error","data"]}}}},"401":{"description":"Missing, malformed, revoked or non-member API key (`auth.api_key_*`).","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","const":false},"code":{"type":"integer","example":400},"message":{"type":"string","example":"Something went wrong."},"error":{"$ref":"#/components/schemas/ApiError"},"data":{"type":"null"},"_req":{"type":"object","properties":{"reqId":{"type":"string"},"resTime":{"type":["integer","null"]}}}},"required":["success","code","message","error","data"]}}}},"403":{"description":"`auth.key_project_restricted` - the calling key is fenced to specific projects; webhooks are workspace-wide and have no project dimension.","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","const":false},"code":{"type":"integer","example":400},"message":{"type":"string","example":"Something went wrong."},"error":{"$ref":"#/components/schemas/ApiError"},"data":{"type":"null"},"_req":{"type":"object","properties":{"reqId":{"type":"string"},"resTime":{"type":["integer","null"]}}}},"required":["success","code","message","error","data"]}}}},"500":{"description":"Unexpected server error (`server.error`).","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","const":false},"code":{"type":"integer","example":400},"message":{"type":"string","example":"Something went wrong."},"error":{"$ref":"#/components/schemas/ApiError"},"data":{"type":"null"},"_req":{"type":"object","properties":{"reqId":{"type":"string"},"resTime":{"type":["integer","null"]}}}},"required":["success","code","message","error","data"]}}}}},"x-envless-scopes":["webhooks:read"]}},"/webhooks/{id}":{"get":{"operationId":"getWebhook","tags":["Webhooks"],"summary":"Get a webhook endpoint","description":"Returns one webhook endpoint. The signing secret is not included and never will be - only `secretLastFour`, the last four characters, so you can confirm which secret a receiver holds. If you have lost the secret your only option is `POST /webhooks/{id}/rotate`.\\n\\n`lastSuccessAt` and `lastFailureAt` are the quickest health signal; use `GET /webhooks/{id}/deliveries` for the detail behind them.\\n\\nRefused for project-restr
1icted keys.","responses":{"200":{"description":"Get a webhook endpoint succeeded.","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","const":true},"code":{"type":"integer","example":200},"message":{"type":"string","example":"OK"},"error":{"type":"null"},"data":{"$ref":"#/components/schemas/Webhook"},"_req":{"type":"object","properties":{"reqId":{"type":"string"},"resTime":{"type":["integer","null"]}}}},"required":["success","code","message","error","data"]}}}},"401":{"description":"Missing, malformed, revoked or non-member API key (`auth.api_key_*`).","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","const":false},"code":{"type":"integer","example":400},"message":{"type":"string","example":"Something went wrong."},"error":{"$ref":"#/components/schemas/ApiError"},"data":{"type":"null"},"_req":{"type":"object","properties":{"reqId":{"type":"string"},"resTime":{"type":["integer","null"]}}}},"required":["success","code","message","error","data"]}}}},"403":{"description":"`auth.key_project_restricted` - the calling key is fenced to specific projects.","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","const":false},"code":{"type":"integer","example":400},"message":{"type":"string","example":"Something went wrong."},"error":{"$ref":"#/components/schemas/ApiError"},"data":{"type":"null"},"_req":{"type":"object","properties":{"reqId":{"type":"string"},"resTime":{"type":["integer","null"]}}}},"required":["success","code","message","error","data"]}}}},"404":{"description":"`webhook.not_found` - no live endpoint with that id exists in this workspace.","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","const":false},"code":{"type":"integer","example":400},"message":{"type":"string","example":"Something went wrong."},"error":{"$ref":"#/components/schemas/ApiError"},"data":{"type":"null"},"_req":{"type":"object","properties":{"reqId":{"type":"string"},"resTime":{"type":["integer","null"]}}}},"required":["success","code","message","error","data"]}}}},"500":{"description":"Unexpected server error (`server.error`).","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","const":false},"code":{"type":"integer","example":400},"message":{"type":"string","example":"Something went wrong."},"error":{"$ref":"#/components/schemas/ApiError"},"data":{"type":"null"},"_req":{"type":"object","properties":{"reqId":{"type":"string"},"resTime":{"type":["integer","null"]}}}},"required":["success","code","message","error","data"]}}}}},"x-envless-scopes":["webhooks:read"],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"},"description":"The endpoint\'s `id` (UUIDv7). Webhook endpoints have no slug form. The literal path `/webhooks/event-types` is a separate route and is matched first, so it can never be read as an id."}]},"patch":{"operationId":"updateWebhook","tags":["Webhooks"],"summary":"Update a webhook endpoint","description":"Updates an endpoint\'s name, URL, description, subscriptions or enabled state. At least one of `name`, `url`, `description`, `eventTypes`, `enabled` must be present or the request is rejected with 400 - an empty object is not a no-op here.\\n\\n**`eventTypes` replaces the subscription set wholesale**, unlike `scopes` on `PATCH /keys/{id}` which merges. Send the complete list you want, not a delta. It must stay non-empty; there is no way to subscribe to nothing, so disable the endpoint instead.\\n\\n`url` is re-validated against the full https/public-host ruleset on every change. `description: null` or `\\"\\"` clears the note.\\n\\n**Disabling does not drain the queue.** Deliveries already queued for a disabled endpoint are not cancelled: the worker picks them up, sees the endpoint is disabled and marks them `failed` with the error `Endpoint disabled`. Expect a burst of failures in the delivery log right after you disable. Nothing new is queued while `enabled` is false - events that occur during the downtime are lost to this endpoint, not buffered.\\n\\nThe secret is untouched by this route. Use `POST /webhooks/{id}
1/rotate`.\\n\\nRefused for project-restricted keys.","responses":{"200":{"description":"Update a webhook endpoint succeeded.","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","const":true},"code":{"type":"integer","example":200},"message":{"type":"string","example":"OK"},"error":{"type":"null"},"data":{"$ref":"#/components/schemas/Webhook"},"_req":{"type":"object","properties":{"reqId":{"type":"string"},"resTime":{"type":["integer","null"]}}}},"required":["success","code","message","error","data"]}}}},"400":{"description":"`request.body_invalid` - none of `name`, `url`, `description`, `eventTypes`, `enabled` is present; `enabled` is not a boolean; `eventTypes` is empty or contains a name outside the catalogue; or `name`, `url` or `description` fails its length or URL validation.","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","const":false},"code":{"type":"integer","example":400},"message":{"type":"string","example":"Something went wrong."},"error":{"$ref":"#/components/schemas/ApiError"},"data":{"type":"null"},"_req":{"type":"object","properties":{"reqId":{"type":"string"},"resTime":{"type":["integer","null"]}}}},"required":["success","code","message","error","data"]}}}},"401":{"description":"Missing, malformed, revoked or non-member API key (`auth.api_key_*`).","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","const":false},"code":{"type":"integer","example":400},"message":{"type":"string","example":"Something went wrong."},"error":{"$ref":"#/components/schemas/ApiError"},"data":{"type":"null"},"_req":{"type":"object","properties":{"reqId":{"type":"string"},"resTime":{"type":["integer","null"]}}}},"required":["success","code","message","error","data"]}}}},"403":{"description":"`auth.key_project_restricted` - the calling key is fenced to specific projects.","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","const":false},"code":{"type":"integer","example":400},"message":{"type":"string","example":"Something went wrong."},"error":{"$ref":"#/components/schemas/ApiError"},"data":{"type":"null"},"_req":{"type":"object","properties":{"reqId":{"type":"string"},"resTime":{"type":["integer","null"]}}}},"required":["success","code","message","error","data"]}}}},"404":{"description":"`webhook.not_found` - no live endpoint with that id exists in this workspace.","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","const":false},"code":{"type":"integer","example":400},"message":{"type":"string","example":"Something went wrong."},"error":{"$ref":"#/components/schemas/ApiError"},"data":{"type":"null"},"_req":{"type":"object","properties":{"reqId":{"type":"string"},"resTime":{"type":["integer","null"]}}}},"required":["success","code","message","error","data"]}}}},"500":{"description":"Unexpected server error (`server.error`).","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","const":false},"code":{"type":"integer","example":400},"message":{"type":"string","example":"Something went wrong."},"error":{"$ref":"#/components/schemas/ApiError"},"data":{"type":"null"},"_req":{"type":"object","properties":{"reqId":{"type":"string"},"resTime":{"type":["integer","null"]}}}},"required":["success","code","message","error","data"]}}}}},"x-envless-scopes":["webhooks:write"],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"},"description":"The endpoint\'s `id` (UUIDv7). No slug form."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","minProperties":1,"properties":{"name":{"type":"string","minLength":1,"maxLength":64,"description":"New label, trimmed, at most 64 characters.","example":"Billing"},"url":{"type":"string","format":"uri","maxLength":2048,"description":"New target. Re-validated against the same https and public-host rules as create.","example":"https://example.com/hooks/envless"},"description":{"type":["string","null"],"maxLength":200,"description":"New note, at most 200 characters. `null` or `\\"\\"` clears it."},"eventTypes":{"type":"array","minItems":1,"items":{"type":"string"},"description":"REPLACES the subscription set. Must be non-empty and drawn entirely from `GET /webhooks/event-types`.","example":["variable.created","variable.updated"]},"enabled":{"type":"boolean","description":"`false` stops new deliveries being queued and causes any already-queued delivery to be marked failed with `Endpoint disabled`. Must be a boolean; anything else is a 400.","example":true}}}}}}},"delete":{"operationId":"deleteWebhook","tags":["Webhooks"],"summary":"Delete a webhook endpoint","description":"Soft-deletes an endpoint. It disappears from `GET /webhooks`, returns 404 from every other webhook route, and the id is never reused. Its delivery history goes with it - fetch anything you need for an audit trail first.\\n\\nDeleting is irreversible and the signing secret is destroyed with the row. If you only want to pause deliveries, use `PATCH /webhooks/{id}` with `enabled: false` instead.\\n\\nOrdering quirk worth knowing: the `webhook.deleted` event is emitted *before* the row is removed. An endpoint subscribed to `webhook.deleted` therefore gets a delivery queued for its own deletion, which the worker then marks `failed` because the endpoint is gone by the time it runs. That failure is expected, not a bug in your receiver.\\n\\nRefused for project-restr
1icted keys.","responses":{"200":{"description":"Delete a webhook endpoint succeeded.","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","const":true},"code":{"type":"integer","example":200},"message":{"type":"string","example":"OK"},"error":{"type":"null"},"data":{"type":"object","properties":{"id":{"type":"string","description":"The deleted endpoint\'s id."},"deleted":{"type":"boolean","const":true,"description":"Always true on success."}},"required":["id","deleted"]},"_req":{"type":"object","properties":{"reqId":{"type":"string"},"resTime":{"type":["integer","null"]}}}},"required":["success","code","message","error","data"]}}}},"401":{"description":"Missing, malformed, revoked or non-member API key (`auth.api_key_*`).","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","const":false},"code":{"type":"integer","example":400},"message":{"type":"string","example":"Something went wrong."},"error":{"$ref":"#/components/schemas/ApiError"},"data":{"type":"null"},"_req":{"type":"object","properties":{"reqId":{"type":"string"},"resTime":{"type":["integer","null"]}}}},"required":["success","code","message","error","data"]}}}},"403":{"description":"`auth.key_project_restricted` - the calling key is fenced to specific projects.","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","const":false},"code":{"type":"integer","example":400},"message":{"type":"string","example":"Something went wrong."},"error":{"$ref":"#/components/schemas/ApiError"},"data":{"type":"null"},"_req":{"type":"object","properties":{"reqId":{"type":"string"},"resTime":{"type":["integer","null"]}}}},"required":["success","code","message","error","data"]}}}},"404":{"description":"`webhook.not_found` - no live endpoint with that id exists in this workspace.","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","const":false},"code":{"type":"integer","example":400},"message":{"type":"string","example":"Something went wrong."},"error":{"$ref":"#/components/schemas/ApiError"},"data":{"type":"null"},"_req":{"type":"object","properties":{"reqId":{"type":"string"},"resTime":{"type":["integer","null"]}}}},"required":["success","code","message","error","data"]}}}},"500":{"description":"Unexpected server error (`server.error`).","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","const":false},"code":{"type":"integer","example":400},"message":{"type":"string","example":"Something went wrong."},"error":{"$ref":"#/components/schemas/ApiError"},"data":{"type":"null"},"_req":{"type":"object","properties":{"reqId":{"type":"string"},"resTime":{"type":["integer","null"]}}}},"required":["success","code","message","error","data"]}}}}},"x-envless-scopes":["webhooks:write"],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"},"description":"The endpoint\'s `id` (UUIDv7). No slug form."}]}},"/webhooks/{id}/deliveries":{"get":{"operationId":"listDeliveries","tags":["Webhooks"],"summary":"List webhook deliveries","description":"Lists delivery attempts for one endpoint, newest first by `createdAt`. This is the log you read when a receiver stops seeing events.\\n\\nA delivery moves `pending` -> `processing` -> `succeeded` or `failed`. `attempts` counts tries so far, up to 5; `nextAttemptAt` is when the next retry is due (backoff 30s, 2m, 10m, 30m, 1h). `responseStatus` and `error` record what the receiver said. Anything outside 2xx, a 3xx redirect, or a timeout past 10 seconds is a failure.\\n\\n**Response bodies are omitted from this list.** Fetch a single delivery with `GET /webhooks/{id}/deliveries/{deliveryId}` to see `responseBody`, which is truncated at 4000 characters.\\n\\nSeveral deliveries can share one `eventId` when an event fans out to multiple endpoints, and a redelivery creates a new delivery row reusing the original `eventId`, so `eventId` is not unique. De-duplicate on it in your handler.\\n\\nRefused for project-restr
1icted keys.","responses":{"200":{"description":"List webhook deliveries succeeded.","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","const":true},"code":{"type":"integer","example":200},"message":{"type":"string","example":"OK"},"error":{"type":"null"},"data":{"type":"object","properties":{"deliveries":{"type":"array","items":{"$ref":"#/components/schemas/WebhookDelivery"}},"pagination":{"$ref":"#/components/schemas/Pagination"}},"required":["deliveries","pagination"]},"_req":{"type":"object","properties":{"reqId":{"type":"string"},"resTime":{"type":["integer","null"]}}}},"required":["success","code","message","error","data"]}}}},"400":{"description":"`request.invalid_pagination` - `limit` or `offset` is not a whole number, or `limit` is outside 1-100.","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","const":false},"code":{"type":"integer","example":400},"message":{"type":"string","example":"Something went wrong."},"error":{"$ref":"#/components/schemas/ApiError"},"data":{"type":"null"},"_req":{"type":"object","properties":{"reqId":{"type":"string"},"resTime":{"type":["integer","null"]}}}},"required":["success","code","message","error","data"]}}}},"401":{"description":"Missing, malformed, revoked or non-member API key (`auth.api_key_*`).","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","const":false},"code":{"type":"integer","example":400},"message":{"type":"string","example":"Something went wrong."},"error":{"$ref":"#/components/schemas/ApiError"},"data":{"type":"null"},"_req":{"type":"object","properties":{"reqId":{"type":"string"},"resTime":{"type":["integer","null"]}}}},"required":["success","code","message","error","data"]}}}},"403":{"description":"`auth.key_project_restricted` - the calling key is fenced to specific projects.","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","const":false},"code":{"type":"integer","example":400},"message":{"type":"string","example":"Something went wrong."},"error":{"$ref":"#/components/schemas/ApiError"},"data":{"type":"null"},"_req":{"type":"object","properties":{"reqId":{"type":"string"},"resTime":{"type":["integer","null"]}}}},"required":["success","code","message","error","data"]}}}},"404":{"description":"`webhook.not_found` - no live endpoint with that id exists in this workspace.","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","const":false},"code":{"type":"integer","example":400},"message":{"type":"string","example":"Something went wrong."},"error":{"$ref":"#/components/schemas/ApiError"},"data":{"type":"null"},"_req":{"type":"object","properties":{"reqId":{"type":"string"},"resTime":{"type":["integer","null"]}}}},"required":["success","code","message","error","data"]}}}},"500":{"description":"Unexpected server error (`server.error`).","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","const":false},"code":{"type":"integer","example":400},"message":{"type":"string","example":"Something went wrong."},"error":{"$ref":"#/components/schemas/ApiError"},"data":{"type":"null"},"_req":{"type":"object","properties":{"reqId":{"type":"string"},"resTime":{"type":["integer","null"]}}}},"required":["success","code","message","error","data"]}}}}},"x-envless-scopes":["webhooks:read"],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"},"description":"The endpoint\'s `id` (UUIDv7). Only deliveries belonging to this endpoint are returned."},{"name":"status","in":"query","required":false,"schema":{"type":"string","enum":["pending","processing","succeeded","failed"]},"description":"Filter by delivery status. Any other value is a 400, not an empty page."},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","minimum":1,"maximum":100,"default":25},"description":"Page size. Must be a whole number between 1 and 100."},{"name":"offset","in":"query","required":false,"schema":{"type":"integer","minimum":0,"default":0},"description":"Number of deliveries to skip. Must be a whole number of 0 or greater."}]}},"/webhooks/{id}/deliveries/{deliveryId}":{"get":{"operationId":"getDelivery","tags":["Webhooks"],"summary":"Get a webhook delivery","description":"Returns one delivery attempt in full, including `responseBody` - what your receiver actually wrote back, truncated at 4000 characters. That field is the only thing this adds over the list endpoint, and it is usually what tells you why a receiver 4xx\'d.\\n\\nThe delivery must belong to the endpoint named in the path. A valid delivery id under the wrong `{id}` returns 404 `webhook.delivery_not_found`, not the delivery.\\n\\n`error` is populated for anything the worker considered a failure, including a receiver that returned a 3xx (redirects are never followed) or that took longer than the 10 second timeout. `nextAttemptAt` is non-null only while more retries remain; after 5 attempts the delivery is terminal.\\n\\nRefused for project-restr
1icted keys.","responses":{"200":{"description":"Get a webhook delivery succeeded.","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","const":true},"code":{"type":"integer","example":200},"message":{"type":"string","example":"OK"},"error":{"type":"null"},"data":{"allOf":[{"$ref":"#/components/schemas/WebhookDelivery"},{"type":"object","properties":{"responseBody":{"type":["string","null"],"description":"What the receiver returned, truncated at 4000 characters. Returned only by this single-delivery route, never in the list."}}}]},"_req":{"type":"object","properties":{"reqId":{"type":"string"},"resTime":{"type":["integer","null"]}}}},"required":["success","code","message","error","data"]}}}},"401":{"description":"Missing, malformed, revoked or non-member API key (`auth.api_key_*`).","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","const":false},"code":{"type":"integer","example":400},"message":{"type":"string","example":"Something went wrong."},"error":{"$ref":"#/components/schemas/ApiError"},"data":{"type":"null"},"_req":{"type":"object","properties":{"reqId":{"type":"string"},"resTime":{"type":["integer","null"]}}}},"required":["success","code","message","error","data"]}}}},"403":{"description":"`auth.key_project_restricted` - the calling key is fenced to specific projects.","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","const":false},"code":{"type":"integer","example":400},"message":{"type":"string","example":"Something went wrong."},"error":{"$ref":"#/components/schemas/ApiError"},"data":{"type":"null"},"_req":{"type":"object","properties":{"reqId":{"type":"string"},"resTime":{"type":["integer","null"]}}}},"required":["success","code","message","error","data"]}}}},"404":{"description":"`webhook.delivery_not_found` - no delivery with that id exists on this endpoint - including a delivery that is real but belongs to a different endpoint.","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","const":false},"code":{"type":"integer","example":400},"message":{"type":"string","example":"Something went wrong."},"error":{"$ref":"#/components/schemas/ApiError"},"data":{"type":"null"},"_req":{"type":"object","properties":{"reqId":{"type":"string"},"resTime":{"type":["integer","null"]}}}},"required":["success","code","message","error","data"]}}}},"500":{"description":"Unexpected server error (`server.error`).","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","const":false},"code":{"type":"integer","example":400},"message":{"type":"string","example":"Something went wrong."},"error":{"$ref":"#/components/schemas/ApiError"},"data":{"type":"null"},"_req":{"type":"object","properties":{"reqId":{"type":"string"},"resTime":{"type":["integer","null"]}}}},"required":["success","code","message","error","data"]}}}}},"x-envless-scopes":["webhooks:read"],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"},"description":"The endpoint\'s `id` (UUIDv7). The delivery must belong to it."},{"name":"deliveryId","in":"path","required":true,"schema":{"type":"string","format":"uuid"},"description":"The delivery\'s `id` (UUIDv7), as returned by `GET /webhooks/{id}/deliveries` or in the `Envless-Delivery` header on the request your receiver got."}]}},"/webhooks/{id}/deliveries/{deliveryId}/redeliver":{"post":{"operationId":"redeliverWebhook","tags":["Webhooks"],"summary":"Redeliver a webhook delivery","description":"Re-queues an event for one endpoint. This does **not** retry the original delivery row - it creates a new one with a fresh `id` that reuses the source delivery\'s `eventId` and `eventType`, and the response returns both so you can correlate them. The original row is left untouched as the historical record.\\n\\nBecause the `eventId` is reused, your receiver will see the same `webhook-id` header again. Idempotency on that value is what stops a redelivery from double-applying.\\n\\n**Only finished deliveries can be redelivered.** A source in `pending` or `processing` is refused with 409 - the worker still owns it and will retry it on its own schedule. Wait for `succeeded` or `failed`.\\n\\nThe delivery must belong to the endpoint in the path; a real delivery id under the wrong `{id}` gets 404 `webhook.delivery_not_found`.\\n\\nThe endpoint must be `enabled`. Redelivering to a disabled endpoint is refused with 409 rather than queuing work that would immediately be marked failed.\\n\\nThe new delivery is created `pending` and picked up by the worker within a few seconds. The workspace is capped at 500 simultaneously queued (`pending` plus `processing`) deliveries; hitting that cap is a 409.\\n\\nReturns **201** - a new delivery row is created.\\n\\nRefused for project-restr
1icted keys.","responses":{"201":{"description":"Redeliver a webhook delivery succeeded.","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","const":true},"code":{"type":"integer","example":200},"message":{"type":"string","example":"OK"},"error":{"type":"null"},"data":{"type":"object","properties":{"id":{"type":"string","description":"The NEW delivery\'s id. Poll `GET /webhooks/{id}/deliveries/{deliveryId}` with this to watch it."},"webhookId":{"type":"string","description":"The endpoint the new delivery targets."},"sourceDeliveryId":{"type":"string","description":"The delivery it was copied from. Its `eventId` and `eventType` are reused, so your receiver sees the same `webhook-id` header."},"status":{"type":"string","const":"pending","description":"Always `pending` - the worker has not run yet."}},"required":["id","webhookId","sourceDeliveryId","status"]},"_req":{"type":"object","properties":{"reqId":{"type":"string"},"resTime":{"type":["integer","null"]}}}},"required":["success","code","message","error","data"]}}}},"401":{"description":"Missing, malformed, revoked or non-member API key (`auth.api_key_*`).","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","const":false},"code":{"type":"integer","example":400},"message":{"type":"string","example":"Something went wrong."},"error":{"$ref":"#/components/schemas/ApiError"},"data":{"type":"null"},"_req":{"type":"object","properties":{"reqId":{"type":"string"},"resTime":{"type":["integer","null"]}}}},"required":["success","code","message","error","data"]}}}},"403":{"description":"`auth.key_project_restricted` - the calling key is fenced to specific projects.","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","const":false},"code":{"type":"integer","example":400},"message":{"type":"string","example":"Something went wrong."},"error":{"$ref":"#/components/schemas/ApiError"},"data":{"type":"null"},"_req":{"type":"object","properties":{"reqId":{"type":"string"},"resTime":{"type":["integer","null"]}}}},"required":["success","code","message","error","data"]}}}},"404":{"description":"`webhook.delivery_not_found` - no delivery with that id exists on this endpoint, including a real delivery that belongs to a different endpoint.","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","const":false},"code":{"type":"integer","example":400},"message":{"type":"string","example":"Something went wrong."},"error":{"$ref":"#/components/schemas/ApiError"},"data":{"type":"null"},"_req":{"type":"object","properties":{"reqId":{"type":"string"},"resTime":{"type":["integer","null"]}}}},"required":["success","code","message","error","data"]}}}},"409":{"description":"`request.conflict` - the source delivery is still `pending` or `processing`, the endpoint is disabled, or the workspace already has 500 queued deliveries.","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","const":false},"code":{"type":"integer","example":400},"message":{"type":"string","example":"Something went wrong."},"error":{"$ref":"#/components/schemas/ApiError"},"data":{"type":"null"},"_req":{"type":"object","properties":{"reqId":{"type":"string"},"resTime":{"type":["integer","null"]}}}},"required":["success","code","message","error","data"]}}}},"500":{"description":"Unexpected server error (`server.error`).","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","const":false},"code":{"type":"integer","example":400},"message":{"type":"string","example":"Something went wrong."},"error":{"$ref":"#/components/schemas/ApiError"},"data":{"type":"null"},"_req":{"type":"object","properties":{"reqId":{"type":"string"},"resTime":{"type":["integer","null"]}}}},"required":["success","code","message","error","data"]}}}}},"x-envless-scopes":["webhooks:write"],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"},"description":"The endpoint\'s `id` (UUIDv7). Must be enabled, and must own the delivery."},{"name":"deliveryId","in":"path","required":true,"schema":{"type":"string","format":"uuid"},"description":"The source delivery\'s `id` (UUIDv7). Must already be `succeeded` or `failed`."}]}},"/webhooks/{id}/rotate":{"post":{"operationId":"rotateWebhookSecret","tags":["Webhooks"],"summary":"Rotate a webhook signing secret","description":"Generates a new signing secret for the endpoint and returns it.\\n\\n**There is no dual-secret grace window.** The old secret stops being valid the instant this call commits. Any delivery already in flight was signed with the old secret and will fail verification at your receiver, and any retry of a previously-failed delivery is re-signed with the new one. Plan for a short window of rejected requests, or accept both secrets in your handler across the rollout.\\n\\nThe recommended sequence: deploy a receiver that accepts the old secret *and* a new one read from config, call this endpoint, write the returned secret to config, then drop the old one once `lastSuccessAt` is advancing again. If you cannot do that, rotate during a quiet period and expect the failures.\\n\\n**`data.secret` is returned exactly once**, here. Reads only ever give you `secretLastFour`. Losing it means rotating again.\\n\\nThis returns **200, not 201** - nothing new is created, an existing endpoint is mutated.\\n\\nA `webhook.secret_rotated` event is emitted, carrying only the id, name, `secretLastFour` and `secretRolledAt`, never the secret itself.\\n\\nRefused for project-restr
1icted keys.","responses":{"200":{"description":"Rotate a webhook signing secret succeeded.","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","const":true},"code":{"type":"integer","example":200},"message":{"type":"string","example":"OK"},"error":{"type":"null"},"data":{"type":"object","properties":{"id":{"type":"string","description":"The endpoint\'s id."},"secret":{"type":"string","description":"The new plaintext signing secret, e.g. `ev_whsec_...`. Returned only here; the previous secret is already dead."},"secretLastFour":{"type":["string","null"],"description":"Last four characters of the new secret, matching what reads will show from now on."},"secretRolledAt":{"type":"string","format":"date-time","description":"When the rotation committed. Deliveries signed before this timestamp used the old secret."}},"required":["id","secret","secretLastFour","secretRolledAt"]},"_req":{"type":"object","properties":{"reqId":{"type":"string"},"resTime":{"type":["integer","null"]}}}},"required":["success","code","message","error","data"]}}}},"401":{"description":"Missing, malformed, revoked or non-member API key (`auth.api_key_*`).","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","const":false},"code":{"type":"integer","example":400},"message":{"type":"string","example":"Something went wrong."},"error":{"$ref":"#/components/schemas/ApiError"},"data":{"type":"null"},"_req":{"type":"object","properties":{"reqId":{"type":"string"},"resTime":{"type":["integer","null"]}}}},"required":["success","code","message","error","data"]}}}},"403":{"description":"`auth.key_project_restricted` - the calling key is fenced to specific projects.","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","const":false},"code":{"type":"integer","example":400},"message":{"type":"string","example":"Something went wrong."},"error":{"$ref":"#/components/schemas/ApiError"},"data":{"type":"null"},"_req":{"type":"object","properties":{"reqId":{"type":"string"},"resTime":{"type":["integer","null"]}}}},"required":["success","code","message","error","data"]}}}},"404":{"description":"`webhook.not_found` - no live endpoint with that id exists in this workspace.","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","const":false},"code":{"type":"integer","example":400},"message":{"type":"string","example":"Something went wrong."},"error":{"$ref":"#/components/schemas/ApiError"},"data":{"type":"null"},"_req":{"type":"object","properties":{"reqId":{"type":"string"},"resTime":{"type":["integer","null"]}}}},"required":["success","code","message","error","data"]}}}},"500":{"description":"Unexpected server error (`server.error`).","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","const":false},"code":{"type":"integer","example":400},"message":{"type":"string","example":"Something went wrong."},"error":{"$ref":"#/components/schemas/ApiError"},"data":{"type":"null"},"_req":{"type":"object","properties":{"reqId":{"type":"string"},"resTime":{"type":["integer","null"]}}}},"required":["success","code","message","error","data"]}}}}},"x-envless-scopes":["webhooks:write"],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"},"description":"The endpoint\'s `id` (UUIDv7). No slug form."}]}},"/workspace":{"get":{"operationId":"getCurrentWorkspace","tags":["Workspace"],"summary":"Get the current workspace","description":"Returns the workspace the API key is bound to. The workspace comes from the key, never from the request, so there is no way to address another workspace here. `GET /workspaces` lists the others the key owner belongs to, but a key can only ever act inside this one.\\n\\nNote the shape differs slightly from the PATCH response, which omits `createdAt`.","responses":{"200":{"description":"Get the current workspace succeeded.","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","const":true},"code":{"type":"integer","example":200},"message":{"type":"string","example":"OK"},"error":{"type":"null"},"data":{"type":"object","properties":{"id":{"type":"string"},"name":{"type":"string"},"slug":{"type":"string"},"icon":{"type":["string","null"],"description":"Absolute URL of the workspace icon, or null."},"createdAt":{"type":"string","format":"date-time"}},"required":["id","name","slug","createdAt"]},"_req":{"type":"object","properties":{"reqId":{"type":"string"},"resTime":{"type":["integer","null"]}}}},"required":["success","code","message","error","data"]}}}},"401":{"description":"Missing, malformed, revoked or non-member API key (`auth.api_key_*`).","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","const":false},"code":{"type":"integer","example":400},"message":{"type":"string","example":"Something went wrong."},"error":{"$ref":"#/components/schemas/ApiError"},"data":{"type":"null"},"_req":{"type":"object","properties":{"reqId":{"type":"string"},"resTime":{"type":["integer","null"]}}}},"required":["success","code","message","error","data"]}}}},"404":{"description":"`(none)` - the workspace has been soft-deleted while the key still exists; note this controller does not set an error code, so the envelope arrives with `error: null` and only `message` to go on.","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","const":false},"code":{"type":"integer","example":400},"message":{"type":"string","example":"Something went wrong."},"error":{"$ref":"#/components/schemas/ApiError"},"data":{"type":"null"},"_req":{"type":"object","properties":{"reqId":{"type":"string"},"resTime":{"type":["integer","null"]}}}},"required":["success","code","message","error","data"]}}}},"500":{"description":"Unexpected server error (`server.error`).","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","const":false},"code":{"type":"integer","example":400},"message":{"type":"string","example":"Something went wrong."},"error":{"$ref":"#/components/schemas/ApiError"},"data":{"type":"null"},"_req":{"type":"object","properties":{"reqId":{"type":"string"},"resTime":{"type":["integer","null"]}}}},"required":["success","code","message","error","data"]}}}}},"x-envless-scopes":["workspace:read"]}
1,"patch":{"operationId":"updateWorkspace","tags":["Workspace"],"summary":"Update the current workspace","description":"Renames the workspace, changes its slug, or toggles virtual environments. Every field is optional and applied independently; an empty body `{}` is accepted and succeeds, returning the workspace unchanged.\\n\\nThe workspace icon cannot be changed here. The controller reads `name`, `slug` and `virtualEnvsEnabled` and silently ignores every other key in the body. Upload icons in the dashboard.\\n\\nChanging the slug changes every dashboard URL for the workspace and any exposed-environment URL built from it. Old slugs are not reserved or redirected, so another workspace can claim the one you release.\\n\\n`virtualEnvsEnabled` is the workspace half of the two-flag gate on exposed environments. Turning it on exposes nothing by itself; each environment still needs its own opt-in through `POST /projects/{slug}/environments/{environmentSlug}/expose`. Turning it off is a kill switch: every exposed feed in the workspace stops serving immediately.\\n\\nEmits the `workspace.updated` webhook event, with `changes` naming the fields that moved. The response payload deliberately omits `createdAt`, which `GET /workspace` does return.","responses":{"200":{"description":"Update the current workspace succeeded.","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","const":true},"code":{"type":"integer","example":200},"message":{"type":"string","example":"OK"},"error":{"type":"null"},"data":{"type":"object","properties":{"id":{"type":"string"},"name":{"type":"string"},"slug":{"type":"string"},"icon":{"type":["string","null"]},"virtualEnvsEnabled":{"type":"boolean"}},"required":["id","name","slug","virtualEnvsEnabled"]},"_req":{"type":"object","properties":{"reqId":{"type":"string"},"resTime":{"type":["integer","null"]}}}},"required":["success","code","message","error","data"]}}}},"400":{"description":"`(none)` - the body is not valid JSON, or `name`/`slug` fails validation (wrong length, or a slug containing anything other than lowercase letters, digits and single hyphens); this controller sets no error code, so `error` is `null` and the reason is only in `message`.","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","const":false},"code":{"type":"integer","example":400},"message":{"type":"string","example":"Something went wrong."},"error":{"$ref":"#/components/schemas/ApiError"},"data":{"type":"null"},"_req":{"type":"object","properties":{"reqId":{"type":"string"},"resTime":{"type":["integer","null"]}}}},"required":["success","code","message","error","data"]}}}},"401":{"description":"Missing, malformed, revoked or non-member API key (`auth.api_key_*`).","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","const":false},"code":{"type":"integer","example":400},"message":{"type":"string","example":"Something went wrong."},"error":{"$ref":"#/components/schemas/ApiError"},"data":{"type":"null"},"_req":{"type":"object","properties":{"reqId":{"type":"string"},"resTime":{"type":["integer","null"]}}}},"required":["success","code","message","error","data"]}}}},"404":{"description":"`(none)` - the workspace has been soft-deleted.","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","const":false},"code":{"type":"integer","example":400},"message":{"type":"string","example":"Something went wrong."},"error":{"$ref":"#/components/schemas/ApiError"},"data":{"type":"null"},"_req":{"type":"object","properties":{"reqId":{"type":"string"},"resTime":{"type":["integer","null"]}}}},"required":["success","code","message","error","data"]}}}},"409":{"description":"`(none)` - another workspace already owns the requested slug; again reported with `error: null` and the detail in `message`.","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","const":false},"code":{"type":"integer","example":400},"message":{"type":"string","example":"Something went wrong."},"error":{"$ref":"#/components/schemas/ApiError"},"data":{"type":"null"},"_req":{"type":"object","properties":{"reqId":{"type":"string"},"resTime":{"type":["integer","null"]}}}},"required":["success","code","message","error","data"]}}}},"500":{"description":"Unexpected server error (`server.error`).","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","const":false},"code":{"type":"integer","example":400},"message":{"type":"string","example":"Something went wrong."},"error":{"$ref":"#/components/schemas/ApiError"},"data":{"type":"null"},"_req":{"type":"object","properties":{"reqId":{"type":"string"},"resTime":{"type":["integer","null"]}}}},"required":["success","code","message","error","data"]}}}}},"x-envless-scopes":["workspace:write"],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"name":{"type":"string","minLength":3,"maxLength":50,"description":"New display name, 3 to 50 characters.","example":"Billing"},"slug":{"type":"string","minLength":3,"maxLength":50,"pattern":"^[a-z0-9]+(?:-[a-z0-9]+)*$","description":"New URL slug, 3 to 50 characters, lowercase letters, digits and single hyphens only. Must be globally unique across all Envless workspaces.","example":"billing"},"virtualEnvsEnabled":{"type":"boolean","example":true,"description":"Allows environments in this workspace to be exposed publicly. Off by default. Turning it off immediately stops every exposed feed in the workspace."}},"additionalProperties":false}}}}},"delete":{"operationId":"deleteWorkspace","tags":["Workspace"],"summary":"Delete the current workspace","description":"Permanently deletes the workspace the key is bound to. This is irreversible and it destroys the key making the request along with every other key, member, role, webhook and product in the workspace.\\n\\nA live subscription is canceled as part of the delete, immediately and with no refund for the remainder of the peri
1od. It never blocks the call: the workspace goes either way, so a cancellation the billing provider refuses leaves the subscription live and it has to be canceled from the customer portal.\\n\\nFour guards apply, in this order, and each one is a hard refusal rather than a warning:\\n\\n1. The key owner must hold the owner role. `workspace:write` alone is not enough.\\n2. The owner must own at least one other workspace, so nobody can delete their way to having none.\\n3. The workspace must be at least 7 days old.\\n4. Every project must already be deleted.\\n\\nBecause a workspace with projects is refused outright, deleting a real workspace means deleting its projects first, which cascades to environments, variables and version history. Emits `workspace.deleted` before the row is removed, so the event is still deliverable.\\n\\nIf the owner had this workspace selected in the dashboard, their selection moves to another workspace they belong to.","responses":{"200":{"description":"Delete the current workspace succeeded.","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","const":true},"code":{"type":"integer","example":200},"message":{"type":"string","example":"OK"},"error":{"type":"null"},"data":{"type":"object","properties":{"id":{"type":"string"},"name":{"type":"string"},"slug":{"type":"string"}},"required":["id","name","slug"]},"_req":{"type":"object","properties":{"reqId":{"type":"string"},"resTime":{"type":["integer","null"]}}}},"required":["success","code","message","error","data"]}}}},"401":{"description":"Missing, malformed, revoked or non-member API key (`auth.api_key_*`).","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","const":false},"code":{"type":"integer","example":400},"message":{"type":"string","example":"Something went wrong."},"error":{"$ref":"#/components/schemas/ApiError"},"data":{"type":"null"},"_req":{"type":"object","properties":{"reqId":{"type":"string"},"resTime":{"type":["integer","null"]}}}},"required":["success","code","message","error","data"]}}}},"403":{"description":"`auth.permission_denied` - the key owner is not the workspace owner.","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","const":false},"code":{"type":"integer","example":400},"message":{"type":"string","example":"Something went wrong."},"error":{"$ref":"#/components/schemas/ApiError"},"data":{"type":"null"},"_req":{"type":"object","properties":{"reqId":{"type":"string"},"resTime":{"type":["integer","null"]}}}},"required":["success","code","message","error","data"]}}}},"404":{"description":"`workspace.not_found` - the workspace is already soft-deleted.","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","const":false},"code":{"type":"integer","example":400},"message":{"type":"string","example":"Something went wrong."},"error":{"$ref":"#/components/schemas/ApiError"},"data":{"type":"null"},"_req":{"type":"object","properties":{"reqId":{"type":"string"},"resTime":{"type":["integer","null"]}}}},"required":["success","code","message","error","data"]}}}},"409":{"description":"`workspace.delete_has_projects` - the workspace still contains at least one project.","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","const":false},"code":{"type":"integer","example":400},"message":{"type":"string","example":"Something went wrong."},"error":{"$ref":"#/components/schemas/ApiError"},"data":{"type":"null"},"_req":{"type":"object","properties":{"reqId":{"type":"string"},"resTime":{"type":["integer","null"]}}}},"required":["success","code","message","error","data"]}}}},"500":{"description":"Unexpected server error (`server.error`).","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","const":false},"code":{"type":"integer","example":400},"message":{"type":"string","example":"Something went wrong."},"error":{"$ref":"#/components/schemas/ApiError"},"data":{"type":"null"},"_req":{"type":"object","properties":{"reqId":{"type":"string"},"resTime":{"type":["integer","null"]}}}},"required":["success","code","message","error","data"]}}}}},"x-envless-scopes":["workspace:write"]}}
1,"/workspace/domain":{"get":{"operationId":"getCustomDomain","tags":["Custom domain"],"summary":"Get the custom domain","description":"Returns the custom domain attached to the current workspace, including the DNS records you still need to publish and the current lifecycle `status`.\\n\\n`domain` is `null` when no domain has ever been claimed. A removed domain also reads as absent. Poll this after `POST /workspace/domain/verify` rather than assuming verification finished synchronously, because certificate issuance happens at the edge and lands afterwards.\\n\\n`records` is the authoritative list of what your DNS must contain right now. It changes as the domain moves through ownership proof and then certificate validation, so re-read it between steps instead of caching the first response.","responses":{"200":{"description":"Get the custom domain succeeded.","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","const":true},"code":{"type":"integer","example":200},"message":{"type":"string","example":"OK"},"error":{"type":"null"},"data":{"type":"object","properties":{"domain":{"oneOf":[{"$ref":"#/components/schemas/CustomDomain"},{"type":"null"}]}},"required":["domain"]},"_req":{"type":"object","properties":{"reqId":{"type":"string"},"resTime":{"type":["integer","null"]}}}},"required":["success","code","message","error","data"]}}}},"401":{"description":"Missing, malformed, revoked or non-member API key (`auth.api_key_*`).","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","const":false},"code":{"type":"integer","example":400},"message":{"type":"string","example":"Something went wrong."},"error":{"$ref":"#/components/schemas/ApiError"},"data":{"type":"null"},"_req":{"type":"object","properties":{"reqId":{"type":"string"},"resTime":{"type":["integer","null"]}}}},"required":["success","code","message","error","data"]}}}},"403":{"description":"`auth.scope_missing` - the key lacks workspace:read.","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","const":false},"code":{"type":"integer","example":400},"message":{"type":"string","example":"Something went wrong."},"error":{"$ref":"#/components/schemas/ApiError"},"data":{"type":"null"},"_req":{"type":"object","properties":{"reqId":{"type":"string"},"resTime":{"type":["integer","null"]}}}},"required":["success","code","message","error","data"]}}}},"500":{"description":"Unexpected server error (`server.error`).","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","const":false},"code":{"type":"integer","example":400},"message":{"type":"string","example":"Something went wrong."},"error":{"$ref":"#/components/schemas/ApiError"},"data":{"type":"null"},"_req":{"type":"object","properties":{"reqId":{"type":"string"},"resTime":{"type":["integer","null"]}}}},"required":["success","code","message","error","data"]}}}}},"x-envless-scopes":["workspace:read"]},"post":{"operationId":"claimCustomDomain","tags":["Custom domain"],"summary":"Claim a custom domain","description":"Attaches a hostname to the current workspace and returns the DNS records that prove you own it. Nothing is served on the domain until you publish those records and call `POST /workspace/domain/verify`.\\n\\nA workspace holds at most one custom domain. Claiming again replaces the pending one and resets its challenge, so an in-flight verification is discarded. Re-claiming a hostname that is already `active` is a no-op and returns it unchanged.\\n\\nThe hostname is canonicalised before validation, so casing and a trailing dot are tolerated. A hostname another workspace has already verified is refused: verified ownership wins permanently. Claiming is not debounced the way verification is, though a custom domain requires a paid plan: Free has none, while Dev, Team and Enterprise each include the one custom domain the workspace holds.","responses":{"200":{"description":"Claim a custom domain succeeded.","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","const":true},"code":{"type":"integer","example":200},"message":{"type":"string","example":"OK"},"error":{"type":"null"},"data":{"type":"object","properties":{"domain":{"oneOf":[{"$ref":"#/components/schemas/CustomDomain"},{"type":"null"}]}},"required":["domain"]},"_req":{"type":"object","properties":{"reqId":{"type":"string"},"resTime":{"type":["integer","null"]}}}},"required":["success","code","message","error","data"]}}}}
1,"400":{"description":"`request.body_invalid` - `hostname` is missing or empty.","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","const":false},"code":{"type":"integer","example":400},"message":{"type":"string","example":"Something went wrong."},"error":{"$ref":"#/components/schemas/ApiError"},"data":{"type":"null"},"_req":{"type":"object","properties":{"reqId":{"type":"string"},"resTime":{"type":["integer","null"]}}}},"required":["success","code","message","error","data"]}}}},"401":{"description":"Missing, malformed, revoked or non-member API key (`auth.api_key_*`).","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","const":false},"code":{"type":"integer","example":400},"message":{"type":"string","example":"Something went wrong."},"error":{"$ref":"#/components/schemas/ApiError"},"data":{"type":"null"},"_req":{"type":"object","properties":{"reqId":{"type":"string"},"resTime":{"type":["integer","null"]}}}},"required":["success","code","message","error","data"]}}}},"402":{"description":"`plan.upgrade_required` - the workspace plan does not include a custom domain.","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","const":false},"code":{"type":"integer","example":400},"message":{"type":"string","example":"Something went wrong."},"error":{"$ref":"#/components/schemas/ApiError"},"data":{"type":"null"},"_req":{"type":"object","properties":{"reqId":{"type":"string"},"resTime":{"type":["integer","null"]}}}},"required":["success","code","message","error","data"]}}}},"403":{"description":"`auth.scope_missing` - the key lacks workspace:write.","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","const":false},"code":{"type":"integer","example":400},"message":{"type":"string","example":"Something went wrong."},"error":{"$ref":"#/components/schemas/ApiError"},"data":{"type":"null"},"_req":{"type":"object","properties":{"reqId":{"type":"string"},"resTime":{"type":["integer","null"]}}}},"required":["success","code","message","error","data"]}}}},"404":{"description":"`workspace.not_found` - the workspace is soft-deleted.","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","const":false},"code":{"type":"integer","example":400},"message":{"type":"string","example":"Something went wrong."},"error":{"$ref":"#/components/schemas/ApiError"},"data":{"type":"null"},"_req":{"type":"object","properties":{"reqId":{"type":"string"},"resTime":{"type":["integer","null"]}}}},"required":["success","code","message","error","data"]}}}},"409":{"description":"`domain.invalid` - the hostname is malformed, or another workspace has already verified it.","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","const":false},"code":{"type":"integer","example":400},"message":{"type":"string","example":"Something went wrong."},"error":{"$ref":"#/components/schemas/ApiError"},"data":{"type":"null"},"_req":{"type":"object","properties":{"reqId":{"type":"string"},"resTime":{"type":["integer","null"]}}}},"required":["success","code","message","error","data"]}}}},"500":{"description":"`domain.not_configured` - this deployment has no custom-domain provider configured.","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","const":false},"code":{"type":"integer","example":400},"message":{"type":"string","example":"Something went wrong."},"error":{"$ref":"#/components/schemas/ApiError"},"data":{"type":"null"},"_req":{"type":"object","properties":{"reqId":{"type":"string"},"resTime":{"type":["integer","null"]}}}},"required":["success","code","message","error","data"]}}}}},"x-envless-scopes":["workspace:write"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"hostname":{"type":"string","example":"secrets.acme.com","description":"The hostname to attach, such as `secrets.acme.com`. Canonicalised before validation."}},"additionalProperties":false,"required":["hostname"]}}}}},"delete":{"operationId":"removeCustomDomain","tags":["Custom domain"],"summary":"Remove the custom domain","description":"Detaches the custom domain and tears down its certificate. The workspace falls back to its `*.envless.cloud` hostname immediately, which breaks any exposed-environment URL built on the custom domain.\\n\\nRemoving a domain that was never claimed succeeds and does nothing, so this is safe to call defensively in teardown scripts.\\n\\nIf the certificate cannot be detached at the edge, the call fails with `500` and the domain is left in a `remov
1ing` state. Retry: the operation resumes from there rather than starting over.","responses":{"200":{"description":"Remove the custom domain succeeded.","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","const":true},"code":{"type":"integer","example":200},"message":{"type":"string","example":"OK"},"error":{"type":"null"},"data":{"type":"object","properties":{"removed":{"type":"boolean","const":true}},"required":["removed"]},"_req":{"type":"object","properties":{"reqId":{"type":"string"},"resTime":{"type":["integer","null"]}}}},"required":["success","code","message","error","data"]}}}},"401":{"description":"Missing, malformed, revoked or non-member API key (`auth.api_key_*`).","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","const":false},"code":{"type":"integer","example":400},"message":{"type":"string","example":"Something went wrong."},"error":{"$ref":"#/components/schemas/ApiError"},"data":{"type":"null"},"_req":{"type":"object","properties":{"reqId":{"type":"string"},"resTime":{"type":["integer","null"]}}}},"required":["success","code","message","error","data"]}}}},"403":{"description":"`auth.scope_missing` - the key lacks workspace:write.","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","const":false},"code":{"type":"integer","example":400},"message":{"type":"string","example":"Something went wrong."},"error":{"$ref":"#/components/schemas/ApiError"},"data":{"type":"null"},"_req":{"type":"object","properties":{"reqId":{"type":"string"},"resTime":{"type":["integer","null"]}}}},"required":["success","code","message","error","data"]}}}},"500":{"description":"`server.error` - the certificate could not be detached at the edge; the domain stays in `removing` and the call can be retried.","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","const":false},"code":{"type":"integer","example":400},"message":{"type":"string","example":"Something went wrong."},"error":{"$ref":"#/components/schemas/ApiError"},"data":{"type":"null"},"_req":{"type":"object","properties":{"reqId":{"type":"string"},"resTime":{"type":["integer","null"]}}}},"required":["success","code","message","error","data"]}}}}},"x-envless-scopes":["workspace:write"]}},"/workspace/domain/verify":{"post":{"operationId":"verifyCustomDomain","tags":["Custom domain"],"summary":"Verify the custom domain","description":"Runs one verification pass against the DNS you published. It is safe to call repeatedly and it never throws for a domain that simply is not ready yet: a failed check returns `200` with the domain\'s new `status` and `failureReason`, not an error status. Branch on `domain.status`, not on the HTTP code.\\n\\nVerification is two-staged. First the Envless ownership TXT record must resolve, which flips `challengeVerifiedAt`. Only then is the certificate requested and its own validation records appear in `records`, meaning a full setup normally needs at least two calls with a DNS publish between them.\\n\\nCalls are debounced. Verifying inside the debounce window returns the current state untouched, with `retryAfterSeconds` telling you when the next real attempt is allowed. Attempts are also capped: once spent, remove the domain and claim it again.","responses":{"200":{"description":"Verify the custom domain succeeded.","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","const":true},"code":{"type":"integer","example":200},"message":{"type":"string","example":"OK"},"error":{"type":"null"},"data":{"type":"object","properties":{"domain":{"oneOf":[{"$ref":"#/components/schemas/CustomDomain"},{"type":"null"}]}},"required":["domain"]},"_req":{"type":"object","properties":{"reqId":{"type":"string"},"resTime":{"type":["integer","null"]}}}},"required":["success","code","message","error","data"]}}}},"401":{"description":"Missing, malformed, revoked or non-member API key (`auth.api_key_*`).","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","const":false},"code":{"type":"integer","example":400},"message":{"type":"string","example":"Something went wrong."},"error":{"$ref":"#/components/schemas/ApiError"},"data":{"type":"null"},"_req":{"type":"object","properties":{"reqId":{"type":"string"},"resTime":{"type":["integer","null"]}}}},"required":["success","code","message","error","data"]}}}},"403":{"description":"`auth.scope_missing` - the key lacks workspace:write.","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","const":false},"code":{"type":"integer","example":400},"message":{"type":"string","example":"Something went wrong."},"error":{"$ref":"#/components/schemas/ApiError"},"data":{"type":"null"},"_req":{"type":"object","properties":{"reqId":{"type":"string"},"resTime":{"type":["integer","null"]}}}},"required":["success","code","message","error","data"]}}}}
1,"404":{"description":"`domain.not_found` - no custom domain has been claimed for this workspace.","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","const":false},"code":{"type":"integer","example":400},"message":{"type":"string","example":"Something went wrong."},"error":{"$ref":"#/components/schemas/ApiError"},"data":{"type":"null"},"_req":{"type":"object","properties":{"reqId":{"type":"string"},"resTime":{"type":["integer","null"]}}}},"required":["success","code","message","error","data"]}}}},"409":{"description":"`domain.attempt_limit` - the verification attempt limit is spent; remove the domain and claim it again.","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","const":false},"code":{"type":"integer","example":400},"message":{"type":"string","example":"Something went wrong."},"error":{"$ref":"#/components/schemas/ApiError"},"data":{"type":"null"},"_req":{"type":"object","properties":{"reqId":{"type":"string"},"resTime":{"type":["integer","null"]}}}},"required":["success","code","message","error","data"]}}}},"500":{"description":"`domain.not_configured` - this deployment has no custom-domain provider configured.","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","const":false},"code":{"type":"integer","example":400},"message":{"type":"string","example":"Something went wrong."},"error":{"$ref":"#/components/schemas/ApiError"},"data":{"type":"null"},"_req":{"type":"object","properties":{"reqId":{"type":"string"},"resTime":{"type":["integer","null"]}}}},"required":["success","code","message","error","data"]}}}}},"x-envless-scopes":["workspace:write"],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"reattempt":{"type":"boolean","default":false,"example":false,"description":"Set true to force a fresh certificate attempt after a failure, instead of only re-reading the current state."}},"additionalProperties":false}}}}}},"/workspaces":{"get":{"operationId":"listWorkspaces","tags":["Workspace"],"summary":"List your workspaces","description":"Lists every workspace the API key\'s owner belongs to, and is the only endpoint that reads outside the key\'s own workspace. It resolves memberships for the key owner rather than rows inside the bound workspace, which is why a key scoped to one workspace can still see the names of the others.\\n\\nSeeing a workspace here does not mean you can act on it. A key is permanently bound to one workspace at creation time and there is no way to retarget it, so `current: true` marks the only workspace the rest of the API will touch. To manage another one, create a key inside it.\\n\\nPagination is applied in memory after every membership is loaded, so `totalCount` always reflects the complete set rather than the current page.","responses":{"200":{"description":"List your workspaces succeeded.","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","const":true},"code":{"type":"integer","example":200},"message":{"type":"string","example":"OK"},"error":{"type":"null"},"data":{"type":"object","properties":{"workspaces":{"type":"array","items":{"$ref":"#/components/schemas/Workspace"}},"pagination":{"$ref":"#/components/schemas/Pagination"}},"required":["workspaces","pagination"]},"_req":{"type":"object","properties":{"reqId":{"type":"string"},"resTime":{"type":["integer","null"]}}}},"required":["success","code","message","error","data"]}}}},"400":{"description":"`request.invalid_pagination` - `limit` or `offset` is not a whole number, or `limit` is outside 1 to 100; `error.field` names the offending parameter.","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","const":false},"code":{"type":"integer","example":400},"message":{"type":"string","example":"Something went wrong."},"error":{"$ref":"#/components/schemas/ApiError"},"data":{"type":"null"},"_req":{"type":"object","properties":{"reqId":{"type":"string"},"resTime":{"type":["integer","null"]}}}},"required":["success","code","message","error","data"]}}}},"401":{"description":"`auth.api_key_user_missing` - the key is valid but its owner row can no longer be read, so memberships cannot be resolved.","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","const":false},"code":{"type":"integer","example":400},"message":{"type":"string","example":"Something went wrong."},"error":{"$ref":"#/components/schemas/ApiError"},"data":{"type":"null"},"_req":{"type":"object","properties":{"reqId":{"type":"string"},"resTime":{"type":["integer","null"]}}}},"required":["success","code","message","error","data"]}}}},"403":{"description":"`auth.scope_missing` - the key lacks workspace:read.","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","const":false},"code":{"type":"integer","example":400},"message":{"type":"string","example":"Something went wrong."},"error":{"$ref":"#/components/schemas/ApiError"},"data":{"type":"null"},"_req":{"type":"object","properties":{"reqId":{"type":"string"},"resTime":{"type":["integer","null"]}}}},"required":["success","code","message","error","data"]}}}},"500":{"description":"Unexpected server error (`server.error`).","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","const":false},"code":{"type":"integer","example":400},"message":{"type":"string","example":"Something went wrong."},"error":{"$ref":"#/components/schemas/ApiError"},"data":{"type":"null"},"_req":{"type":"object","properties":{"reqId":{"type":"string"},"resTime":{"type":["integer","null"]}}}},"required":["success","code","message","error","data"]}}}}},"x-envless-scopes":["workspace:read"],"parameters":[{"name":"limit","in":"query","schema":{"type":"integer","minimum":1,"maximum":100,"default":25},"description":"Rows per page, 1 to 100. Must be a whole number."},{"name":"offset","in":"query","schema":{"type":"integer","minimum":0,"default":0},"description":"Rows to skip. Must be a whole number of 0 or more."}]}
1,"post":{"operationId":"createWorkspace","tags":["Workspace"],"summary":"Create a workspace","description":"Creates a new workspace owned by the API key\'s owner. The caller becomes its owner with the full owner role.\\n\\n**The new workspace is not reachable with the key that created it.** Keys are bound to a single workspace at creation, so the response is the last thing this key will ever see of it. Mint a key inside the new workspace, in the dashboard or from a key that already lives there, before you can add products, projects or variables.\\n\\n`slug` is optional and defaults to a slugified `name`. Slugs are globally unique across every Envless workspace, not just yours, so a common name may already be taken. Each user may own at most 100 workspaces.\\n\\nUnlike creating a workspace in the dashboard, this does **not** change which workspace the owner currently has selected there. Emits the `workspace.created` webhook event, delivered to the endpoints of the new workspace.","responses":{"201":{"description":"Create a workspace succeeded.","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","const":true},"code":{"type":"integer","example":200},"message":{"type":"string","example":"OK"},"error":{"type":"null"},"data":{"$ref":"#/components/schemas/Workspace"},"_req":{"type":"object","properties":{"reqId":{"type":"string"},"resTime":{"type":["integer","null"]}}}},"required":["success","code","message","error","data"]}}}}
1,"400":{"description":"`request.body_invalid` - `name` is missing or empty, or `name`/`slug` fails validation.","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","const":false},"code":{"type":"integer","example":400},"message":{"type":"string","example":"Something went wrong."},"error":{"$ref":"#/components/schemas/ApiError"},"data":{"type":"null"},"_req":{"type":"object","properties":{"reqId":{"type":"string"},"resTime":{"type":["integer","null"]}}}},"required":["success","code","message","error","data"]}}}},"401":{"description":"Missing, malformed, revoked or non-member API key (`auth.api_key_*`).","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","const":false},"code":{"type":"integer","example":400},"message":{"type":"string","example":"Something went wrong."},"error":{"$ref":"#/components/schemas/ApiError"},"data":{"type":"null"},"_req":{"type":"object","properties":{"reqId":{"type":"string"},"resTime":{"type":["integer","null"]}}}},"required":["success","code","message","error","data"]}}}},"403":{"description":"`auth.scope_missing` - the key lacks workspace:write.","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","const":false},"code":{"type":"integer","example":400},"message":{"type":"string","example":"Something went wrong."},"error":{"$ref":"#/components/schemas/ApiError"},"data":{"type":"null"},"_req":{"type":"object","properties":{"reqId":{"type":"string"},"resTime":{"type":["integer","null"]}}}},"required":["success","code","message","error","data"]}}}},"409":{"description":"`workspace.limit_reached` - the owner already has 100 workspaces.","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","const":false},"code":{"type":"integer","example":400},"message":{"type":"string","example":"Something went wrong."},"error":{"$ref":"#/components/schemas/ApiError"},"data":{"type":"null"},"_req":{"type":"object","properties":{"reqId":{"type":"string"},"resTime":{"type":["integer","null"]}}}},"required":["success","code","message","error","data"]}}}},"500":{"description":"Unexpected server error (`server.error`).","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","const":false},"code":{"type":"integer","example":400},"message":{"type":"string","example":"Something went wrong."},"error":{"$ref":"#/components/schemas/ApiError"},"data":{"type":"null"},"_req":{"type":"object","properties":{"reqId":{"type":"string"},"resTime":{"type":["integer","null"]}}}},"required":["success","code","message","error","data"]}}}}},"x-envless-scopes":["workspace:write"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"name":{"type":"string","minLength":3,"maxLength":50,"description":"Display name, 3 to 50 characters.","example":"Billing"},"slug":{"type":"string","minLength":3,"maxLength":50,"pattern":"^[a-z0-9]+(?:-[a-z0-9]+)*$","description":"URL slug, 3 to 50 characters, lowercase letters, digits and single hyphens only. Globally unique across all Envless workspaces. Defaults to a slugified `name`.","example":"billing"}},"additionalProperties":false,"required":["name"]}}}}}}}'),Is={servers:_s,components:As,paths:Es},be=Is;var ze,Ge;const xt=(Ge=(ze=be.servers)==null?void 0:ze[0])==null?void 0:Ge.url,Ts="ev_sk_xxxxxxxxxxxx",qt="application/json",fe=12,Ss={200:"OK",201:"Created",202:"Accepted",204:"No Content",400:"Bad Request",401:"Unauthorized",402:"Payment Required",403:"Forbidden",404:"Not Found",409:"Conflict",422:"Unprocessable Entity",429:"Too Many Requests",500:"Internal Server Error"},v={AUTHORIZATION:{slug:"authorization",text:"Authorization"},PATH:{slug:"path-parameters",text:"Path parameters"},QUERY:{slug:"query-parameters",text:"Query parameters"},BODY:{slug:"request-body",text:"Request body"},RESPONSES:{slug:"responses",text:"Responses"}},$s="'\\''",D=e=>`response-${e}`,Ps=e=>{var o,n;const t=e.replace(/^#\/components\/schemas\//,"");return((n=(o=be.components)==null?void 0:o.schemas)==null?void 0:n[t])??{}},Ls=e=>{const{$ref:t,...o}=e;return o},te=(e,t=0)=>{var c;if(t>fe)return{};if(e.$ref)return te({...Ps(e.$ref),...Ls(e)},t+1);if(!e.allOf)return e;const{allOf:o,...n}=e,a={...n},i={},p=new Set(n.required??[]);for(const l of o){const d=te(l,t+1);Object.assign(i,d.properties??{}
1),(c=d.required)==null||c.forEach(m=>p.add(m)),!a.type&&d.type&&(a.type=d.type),!a.description&&d.description&&(a.description=d.description),d.additionalProperties!==void 0&&a.additionalProperties===void 0&&(a.additionalProperties=d.additionalProperties)}return n.properties&&Object.assign(i,n.properties),Object.keys(i).length>0&&(a.properties=i),p.size>0&&(a.required=[...p]),!a.type&&a.properties&&(a.type="object"),a},kt=e=>Array.isArray(e.type)?e.type:e.type?[e.type]:e.properties||e.additionalProperties?["object"]:e.items?["array"]:e.enum?[typeof e.enum[0]=="number"?"number":"string"]:e.const!==void 0?[typeof e.const=="boolean"?"boolean":"string"]:["any"],Ee=(e,t,o)=>{if(o)return o.map(p=>p.type).join(" | ");const n=kt(e).map(p=>p==="array"?t?`${t.type.includes(" | ")?`(${t.type})`:t.type}[]`:"array":p==="integer"?"integer":e.enum&&p!=="null"?`enum<${p}>`:p),a=n.filter(p=>p!=="null"),i=n.length!==a.length;return`${a.join(" | ")||"null"}${i&&a.length?" | null":""}`},Rs=e=>{const t=[];return e.format&&t.push(e.format),e.minimum!==void 0&&t.push(`min ${e.minimum}`),e.maximum!==void 0&&t.push(`max ${e.maximum}`),e.minLength!==void 0&&t.push(`min length ${e.minLength}`),e.maxLength!==void 0&&t.push(`max length ${e.maxLength}`),e.minItems!==void 0&&t.push(`min items ${e.minItems}`),e.maxItems!==void 0&&t.push(`max items ${e.maxItems}`),e.minProperties!==void 0&&t.push(`min keys ${e.minProperties}`),e.pattern&&t.push(`pattern ${e.pattern}`),e.writeOnly&&t.push("write-only"),t},I=(e,t=0)=>{var u,y,g;const o=te(e);if(t>fe)return{type:Ee(o),constraints:[]};const n=(u=o.oneOf)==null?void 0:u.map(h=>I(h,t+1)),a=o.items?I(o.items,t+1):void 0,i=new Set(o.required??[]),p=([h,S])=>({name:h,required:i.has(h),schema:I(S,t+1)}),c=o.properties?Object.entries(o.properties).map(p):void 0,l=o.additionalProperties&&typeof o.additionalProperties=="object"?I(o.additionalProperties,t+1):void 0,d=(g=(y=o.propertyNames)==null?void 0:y.enum)==null?void 0:g.map(h=>String(h)),m={type:Ee(o,a,n),constraints:Rs(o)};return o.description&&(m.description=o.description),o.enum&&(m.enum=o.enum),o.default!==void 0&&(m.default=o.default),o.example!==void 0&&(m.example=o.example),c!=null&&c.length&&(m.fields=c),a&&(m.items=a),l&&(m.additional=l),d!=null&&d.length&&(m.keys=d),n!=null&&n.length&&(m.oneOf=n),m},Ns=e=>({name:e.name,in:e.in,required:e.in==="path"?!0:!!e.required,description:e.description,schema:I(e.schema??{})}),_t=e=>{var t,o;return((t=e==null?void 0:e[qt])==null?void 0:t.schema)??((o=Object.values(e??{})[0])==null?void 0:o.schema)},$=(e,t=0)=>{var a,i,p,c;const o=te(e);if(t>fe)return null;if(o.example!==void 0)return o.example;if(o.const!==void 0)return o.const;if(o.default!==void 0)return o.default;if((a=o.oneOf)!=null&&a.length)return $(o.oneOf[0]??{},t+1);if((i=o.enum)!=null&&i.length)return o.enum[0]??null;const[n]=kt(o).filter(l=>l!=="null");if(n==="object"){const l={};for(const[d,m]of Object.entries(o.properties??{}))l[d]=$(m,t+1);if(o.additionalProperties&&typeof o.additionalProperties=="object"){const d=((c=(p=o.propertyNames)==null?void 0:p.enum)==null?void 0:c.map(String))??["<key>"];for(const m of d.slice(0,2))l[m]=$(o.additionalProperties,t+1)}return l}return n==="array"?o.items?[$(o.items,t+1)]:[]:n==="string"?o.format==="date-time"?"2026-05-30T10:14:22.000Z":o.format==="uuid"?"0b0d3f1e-6c1a-4f2b-9a5e-2b7f0c9d4a13":o.format==="email"?"[email protected]":o.format==="uri"||o.format==="url"?"https://example.com":"<string>":n==="integer"||n==="number"?o.minimum??1:n==="boolean"?!0:null},Ms=(e,t)=>{const o=_t(t.content),n=e.startsWith("2"),a={status:e,reason:Ss[e]??"",success:n,description:t.description??""};return o&&(a.schema=I(o),a.example=JSON.stringify($(o),null,4)),a},Y=e=>`'${e.replace(/'/g,$s)}'`,Cs=(e,t,o,n)=>{const a=t.replace(/\{([^}]+)\}/g,(l,d)=>`<${d}>`),i=o.filter(l=>l.required).map(l=>`${l.name}=<${l.name}>`).join("&"),p=`${xt}${a}${i?`?${i}`:""}`,c=[`curl --request ${e}
1 \\`,` --url ${Y(p)} \\`,` --header ${Y(`Authorization: Bearer ${Ts}`)}`];return n&&(c[c.length-1]+=" \\",c.push(` --header ${Y("Content-Type: application/json")} \\`),c.push(` --data ${Y(n.example)}`)),c.join(` 2`)},Vs=(e,t,o)=>{var d,m,u;const n=(o.parameters??[]).map(Ns),a=n.filter(y=>y.in==="path"),i=n.filter(y=>y.in==="query"),p=_t((d=o.requestBody)==null?void 0:d.content),c=p&&{required:!!((m=o.requestBody)!=null&&m.required),description:(u=o.requestBody)==null?void 0:u.description,schema:I(p),example:JSON.stringify($(p),null,2)},l=Object.entries(o.responses).map(([y,g])=>Ms(y,g)).sort((y,g)=>Number(y.status)-Number(g.status));return{method:e,path:t,url:`${xt}${t}`,operationId:o.operationId,tags:o.tags??[],summary:o.summary,description:o.description,scopes:o["x-envless-scopes"]??[],pathParameters:a,queryParameters:i,body:c,responses:l,curl:Cs(e,t,i,c)}},ne=new Map,Zs=e=>{var l;const t=e==null?void 0:e.trim();if(!t)return;if(ne.has(t))return ne.get(t);const[o="",...n]=t.split(/\s+/),a=o.toUpperCase(),i=n.join(" "),p=(l=be.paths[i])==null?void 0:l[a.toLowerCase()],c=p?Vs(a,i,p):void 0;return ne.set(t,c),c},Os=e=>{var o;const t=e.example??e.default??((o=e.enum)==null?void 0:o[0]);return t==null?"":typeof t=="string"?t:JSON.stringify(t)},Ie=e=>{var o;const t={name:e.name,in:e.in,required:e.required,type:e.schema.type,example:Os(e.schema)};return e.description&&(t.description=e.description),(o=e.schema.enum)!=null&&o.length&&(t.enum=e.schema.enum.map(n=>String(n))),t},Hs=e=>{const t={method:e.method,path:e.path,pathParameters:e.pathParameters.map(Ie),queryParameters:e.queryParameters.map(Ie)};return e.body&&(t.body={contentType:qt,required:e.body.required,example:e.body.example}),t},Ds=e=>{const t=[{depth:2,...v.AUTHORIZATION}];e.pathParameters.length&&t.push({depth:2,...v.PATH}),e.queryParameters.length&&t.push({depth:2,...v.QUERY}),e.body&&t.push({depth:2,...v.BODY}),t.push({depth:2,...v.RESPONSES});for(const o of e.responses)t.push({depth:3,slug:D(o.status),text:`${o.status} ${o.reason}`.trim()});return t},Te=/^\d+\.\s+/,Se=/^[-*]\s+/,Us=e=>{const t=e.split(` 3`);return t.every(o=>Te.test(o))?{kind:"ol",items:t.map(o=>o.replace(Te,""))}:t.every(o=>Se.test(o))?{kind:"ul",items:t.map(o=>o.replace(Se,""))}:{kind:"p",items:[t.join(" ")]}},Fs=e=>e.replace(/\r\n/g,` 4`).split(/\n{2,}/).map(t=>t.trim()).filter(Boolean).map(Us),Ks=e=>e.toLowerCase().replace(/[^a-z0-9]+/g,"-").replace(/^-+|-+$/g,""),Bs=({title:e,className:t,children:o})=>{const n=Ks(e);return s.jsxs("details",{className:b("docs-accordion my-4 overflow-hidden rounded-2xl border border-border",t),id:n,children:[s.jsxs("summary",{className:"docs-accordion-summary flex w-full cursor-pointer list-none items-center justify-between gap-4 px-5 py-4 text-left text-base font-medium text-foreground outline-none select-none focus-visible:ring-[3px] focus-visible:ring-ring/50",id:`${n}-label`,children:[s.jsx("span",{className:"min-w-0 leading-6",children:e}),s.jsx("span",{className:"docs-accordion-plus inline-flex size-8 shrink-0 items-center justify-center rounded-full bg-foreground text-background","aria-hidden":"true",children:s.jsx(pr,{size:14,weight:"bold",color:"currentColor"})})]}),s.jsx("div",{className:"docs-accordion-content px-5 pb-5 text-[0.9375rem] text-body",role:"region","aria-labelledby":`${n}-label`,children:o})]})},zs=({className:e,children:t})=>s.jsx("div",{className:b("docs-accordion-group my-6 flex flex-col gap-2",e),children:t}),Gs=()=>s.jsx("span",{"aria-hidden":"true",className:"absolute top-5 right-5 inline-flex text-muted-foreground transition-fx group-hover:text-primary-text",children:s.jsx(mr,{size:16,weight:"bold",color:"currentColor"})}),Ws=({title:e,hasBody:t,isLink:o,children:n})=>s.jsxs("div",{className:"min-w-0 flex-1",children:[e&&s.jsx("h2",{className:b("docs-card-title font-display text-xl leading-snug font-semibold break-words text-foreground transition-fx",o&&"group-hover:text-primary-text"),children:e}),t&&s.jsx("div",{className:b("docs-card-body text-sm leading-relaxed break-words text-body",e&&"mt-1.5"),children:n})]}),Ys={"app-window":at,"arrow-line-up":ct,"arrows-clockwise":ur,"book-open":yr,"brackets-curly":Jt,"clock-counter-clockwise":gr,code:hr,compass:dt,"credit-card":br,cube:mt,diamond:Xt,"download-simple":fr,envelope:wr,"file-code":jr,"file-py":Qt,"file-ts":Yt,gear:vr,globe:kr,hammer:ut,"hard-drives":Ar,info:Qe,ke
4y:Ir,lightning:Xe,link:Tr,lock:Sr,package:$r,play:yt,"plugs-connected":Lr,shield:gt,"shield-check":Rr,"sign-in":ht,"sign-out":_r,stack:Nr,table:ft,terminal:wt,"terminal-window":Mr,"upload-simple":Cr,user:jt,"user-gear":vt,users:Vr,"webhooks-logo":Pr},$e=bt,Pe=new Set,Qs=e=>{if(!e)return $e;const t=Ys[e];return t||(Pe.has(e)||(Pe.add(e),console.warn(`[docs] no icon mapped for "${e}", add it to site/docs/icons-parts/docsIconMap.ts`)),$e)},ce=({name:e,size:t=20,weight:o="duotone",className:n=""})=>{const a=Qs(e);return s.jsx(a,{size:t,weight:o,color:"currentColor",className:n,"aria-hidden":"true"})},Xs=({icon:e})=>s.jsx("span",{className:"inline-flex size-9 shrink-0 items-center justify-center rounded-[12px] border border-border text-primary-text",children:s.jsx(ce,{name:e,size:18})}),Js=/^(?:[a-z]+:)?\/\//i,eo=e=>{const t=!!(e&&Js.test(e));return{resolvedHref:e,isExternal:t,linkProps:t?{target:"_blank",rel:"noopener noreferrer"}:{}}},Le="docs-card group relative my-5 flex w-full flex-col overflow-hidden rounded-2xl border border-border font-normal no-underline transition-fx",to="cursor-pointer hover:border-foreground
4/20 focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-primary",ro=({title:e,icon:t,href:o,className:n,children:a})=>{const{resolvedHref:i,isExternal:p,linkProps:c}=eo(o),l=s.jsxs("div",{className:b("relative flex flex-1 flex-col gap-4 p-5",p&&"pr-11"),children:[p&&s.jsx(Gs,{}),t&&s.jsx(Xs,{icon:t}),s.jsx(Ws,{title:e,hasBody:r.Children.count(a)>0,isLink:!!i,children:a})]});return i?s.jsx(_,{href:i,...c,className:b(Le,to,n),children:l}):s.jsx("div",{className:b(Le,n),children:l})},so={1:"grid-cols-1",2:"grid-cols-1 sm:grid-cols-2",3:"grid-cols-1 sm:grid-cols-2 lg:grid-cols-3",4:"grid-cols-1 sm:grid-cols-2 lg:grid-cols-4"},oo=({cols:e=2,className:t,children:o})=>s.jsx("div",{className:b("docs-card-group my-5 grid gap-4",so[Math.min(4,Math.max(1,e))],t),children:o}),re="relative [&>*:not(.sliding-highlight)]:relative [&>*:not(.sliding-highlight)]:z-[1]",P={ACTIVE:"rounded-full bg-foreground/[0.07]",HOVER:"rounded-full bg-foreground/5"},no=({panes:e,tablist:t,source:o})=>s.jsxs("div",{className:"flex min-h-10 items-center justify-between gap-3 border-b border-border py-1.5 pr-1.5 pl-1.5",children:[s.jsxs("div",{className:tt({className:`min-w-0 ${re}`}),role:"tablist","aria-label":"Code examples",children:[s.jsx(O,{active:'[data-state="active"]',activeKey:t.selected,activeClass:Je()}),e.map((n,a)=>s.jsxs("button",{...t.tabProps(a),className:et(),children:[s.jsx(er,{lang:n.lang,title:n.title,className:"max-sm:hidden"}),n.label]},`${a}-${n.label}`))]}),s.jsx(We,{source:o})]}),ao=e=>r.Children.toArray(e).filter(t=>r.isValidElement(t)&&t.type===ye).map(({props:t})=>t),io=(e,t)=>({label:e["data-title"]||e["data-lang"]||`Option ${t+1}`,lang:e["data-lang"],title:e["data-title"]}),At=r.createContext({value:null,select:()=>{}}),po=()=>r.useContext(At),Re={ACTIVE:"active",INACTIVE:"inactive"},Ne=` 5`,Et=(e,t,o)=>{const[n,a]=r.useState(0),i=r.useRef([]),p=po(),c=Math.min(n,Math.max(0,t-1)),l=(o==null?void 0:o.join(Ne))??"";r.useEffect(()=>{if(!p.value||!l)return;const u=l.split(Ne).indexOf(p.value);u!==-1&&a(u)},[p.value,l]);const d=(u,y)=>{a(u);const g=o==null?void 0:o[u];if(g&&p.select(g),!y)return;const h=i.current[u];h==null||h.focus(),h==null||h.scrollIntoView({block:"nearest",inline:"nearest"})},m=u=>y=>{const g=ss[y.key];g&&(y.preventDefault(),d(g(u,t),!0))};return{selected:c,tabProps:u=>({id:`${e}-tab-${u}`,type:"button",role:"tab","aria-selected":u===c,"aria-controls":`${e}-panel-${u}`,tabIndex:u===c?0:-1,"data-state":u===c?Re.ACTIVE:Re.INACTIVE,ref:y=>{i.current[u]=y},onClick:()=>d(u,!1),onKeyDown:m(u)}),panelProps:u=>({id:`${e}-panel-${u}`,role:"tabpanel","aria-labelledby":`${e}-tab-${u}`,hidden:u!==c})}},It=({className:e,children:t})=>{const o=ao(t),n=o.map(io),a=r.useRef([]),i=Et(`code-group-${r.useId()}`,n.length,n.map(p=>p.label));return o.length===0?s.jsx("div",{className:b("docs-code-group my-5",e),children:t}):s.jsxs("div",{className:b("docs-code-group my-5 overflow-hidden rounded-2xl border border-border",e),children:[s.jsx(no,{panes:n,tablist:i,source:()=>a.current[i.selected]??null}),o.map((p,c)=>{var l;return s.jsx("div",{...i.panelProps(c),children:s.jsx(tr,{...p,ref:d=>{a.current[c]=d}})},`${c}-${(l=n[c])==null?void 0:l.label}`)})]})},K=({id:e})=>s.jsx("a",{href:`#${e}`,className:"docs-heading-anchor","aria-hidden":"true",tabIndex:-1,children:"#"}),co="docs-card-title",we=e=>({id:t,className:o,children:n,...a})=>s.jsxs(e,{id:t,className:o,...a,children:[n,t&&!(o!=null&&o.split(" ").includes(co))&&s.jsx(K,{id:t})]}),lo=we("h2"),mo=we("h3"),uo=we("h4"),yo="docs-link text-primary-text underline decoration-primary-text/40 underline-offset-[3px] transition-[text-decoration-color] [overflow-wrap:anywhere] hover:decoration-primary-text focus-visible:rounded-xs focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-primary [&>code]:text-inherit",go=/^(?:[a-z]+:)?\/\//i,Tt=({href:e,className:t,children:o,...n})=>{const a=typeof e=="string"?e:void 0,i=a&&go.test(a)?{target:"_blank",rel:"noopener noreferrer"}:{},p=b(yo,t);return a===void 0?s.jsx("a",{className:p,...n,children:o}):s.jsx(_,{href:a,className:p,...i,...n,children:o})},St=({type:e="note",className:t,children:o})=>{const n=e==="warning",a=n?Zr:Qe;return s.jsxs("div",{role:"note","aria-label":n?"Warning":"Note",className:b("docs-callout relative my-6 flex gap-3.5 overflow-hidden rounded-2xl border border-border py-4 pr-5 pl-6",n&&"docs-callout-warning",t),children:[s.jsx("span",{className:b("mt-[3px] inline-flex shrink-0",n?"text-warning":"text-primary-text"),children:s.jsx(a,{size:18,weight:"duotone",color:"currentColor","aria-hidden":"true"})}),s.jsx("div",{className:"docs-callout-body min-w-0 flex-1 text-[0.9375rem] leading-relaxed text-body",children:o})]})},ho=({title:e,className:t,children:o})=>s.jsxs("div",{role:"listitem",className:b("docs-step relative flex gap-4",t),children:[s.jsxs("div",{className:"flex w-7 shrink-0 flex-col items-center",children:[s.jsx("div",{className:"docs-step-indicator flex size-7 shrink-0 items-center justify-center rounded-full border border-border text-xs font-semibold text-primary-text tabular-nums",children:s.jsx("span",{className:"docs-step-counter"})}),s.jsx("span",{className:"docs-step-line mt-2 w-px flex-1 bg-foreground
5/[0.08]","aria-hidden":"true"})]}),s.jsxs("div",{className:"docs-step-body min-w-0 flex-1 pb-8",children:[e&&s.jsx("p",{className:"docs-step-title text-base font-semibold text-foreground",children:e}),s.jsx("div",{className:"docs-step-content",children:o})]})]}),bo=({className:e,children:t})=>s.jsx("div",{role:"list",className:b("docs-steps my-8",e),children:t}),$t=({children:e})=>s.jsx(s.Fragment,{children:e}),fo=e=>r.Children.toArray(e).filter(t=>r.isValidElement(t)&&t.type===$t),wo=({className:e,children:t})=>{const o=fo(t),n=Et(`docs-tabs-${r.useId()}`,o.length);return o.length===0?s.jsx(s.Fragment,{children:t}):s.jsxs("div",{className:b("docs-tab-group my-6",e),children:[s.jsxs("div",{role:"tablist",className:tt(),children:[s.jsx(O,{active:'[data-state="active"]',activeKey:n.selected,activeClass:Je()}),o.map(({props:a},i)=>s.jsx("button",{...n.tabProps(i),className:et(),children:a.title},`${i}-${a.title}`))]}),s.jsx("div",{className:"docs-tab-panels pt-4",children:o.map(({props:a},i)=>s.jsx("div",{...n.panelProps(i),tabIndex:0,className:b("docs-tab-panel",a.className),children:a.children},`${i}-${a.title}`))})]})},jo=e=>e.toLowerCase().replace(/[^a-z0-9]+/g,"-").replace(/^-+|-+$/g,""),vo=({label:e,description:t,className:o,children:n})=>{const a=jo(e);return s.jsxs("section",{id:a,className:b("docs-update relative grid scroll-mt-28 grid-cols-1 gap-x-10 gap-y-4 border-t border-foreground
5/[0.06] py-8 first:border-t-0 first:pt-2 lg:grid-cols-[11rem_minmax(0,1fr)]",o),"aria-label":e,children:[s.jsxs("div",{className:"flex flex-row flex-wrap items-center gap-x-3 gap-y-2 self-start lg:sticky lg:top-28 lg:flex-col lg:items-start",children:[s.jsx(F,{asChild:!0,variant:"secondary",className:"docs-update-label outline-none",children:s.jsx("a",{href:`#${encodeURIComponent(a)}`,children:e})}),t&&s.jsx("p",{className:"m-0 text-sm text-body lg:mt-3",children:t})]}),s.jsx("div",{className:"docs-update-content min-w-0",children:n})]})},xo=({className:e,children:t})=>s.jsx(St,{type:"warning",className:e,children:t}),qo={Note:St,Warning:xo,Card:ro,CardGroup:oo,Steps:bo,Step:ho,Tabs:wo,Tab:$t,CodeGroup:It,Accordion:Bs,AccordionGroup:zs,Update:vo,pre:ye,a:Tt,h2:lo,h3:mo,h4:uo},Me=e=>e.map(t=>({name:t.name,required:t.required,schema:t.description?{...t.schema,description:t.description}:t.schema})),ko=[{name:"Authorization",required:!0,schema:{type:"string",constraints:["header"],description:"Bearer token: an Envless API key (`ev_sk_â¦`), created in the dashboard or with `POST /keys`. The key is bound to one workspace; every request runs inside it."}}],U=({section:e})=>s.jsxs("h2",{id:e.slug,children:[e.text,s.jsx(K,{id:e.slug})]}),_o=/`([^`\n]+)`|\[([^\]]+)\]\(([^)\s]+)\)|\*\*(.+?)\*\*|(^|[\s(])\*([^*\n]+)\*(?=[\s).,;:!?]|$)/g,V=e=>{const t=[];let o=0;for(const n of e.matchAll(_o)){const[a,i,p,c,l,d="",m]=n,u=n.index+d.length,y=`${u}`;u>o&&t.push(e.slice(o,u)),i!==void 0?t.push(s.jsx("code",{children:i},y)):p!==void 0?t.push(s.jsx(Tt,{href:c,children:V(p)},y)):l!==void 0?t.push(s.jsx("strong",{children:V(l)},y)):t.push(s.jsx("em",{children:V(m??"")},y)),o=n.index+a.length}return o<e.length&&t.push(e.slice(o)),t},B=({value:e,className:t})=>s.jsx("div",{className:t,children:Fs(e).map(({kind:o,items:n},a)=>{if(o==="p")return s.jsx("p",{children:V(n[0]??"")},a);const i=o;return s.jsx(i,{children:n.map((p,c)=>s.jsx("li",{children:V(p)},c))},a)})}),Pt=e=>{var t,o,n;if((t=e.fields)!=null&&t.length)return e.fields;if(e.items)return Pt(e.items);if((n=(o=e.additional)==null?void 0:o.fields)!=null&&n.length)return e.additional.fields},Ao=e=>e.additional&&!e.fields?{type:e.additional.type,keys:e.keys}:void 0,Eo=e=>{var o,n;const t=e.enum??((o=e.items)==null?void 0:o.enum)??((n=e.additional)==null?void 0:n.enum);return t==null?void 0:t.map(a=>JSON.stringify(a))},Io=e=>JSON.stringify(e),To="docs-schema-toggle inline-flex cursor-pointer list-none items-center gap-1.5 rounded-full px-2.5 py-1 text-xs font-medium text-body transition-fx outline-none select-none hover:bg-foreground
5/5 hover:text-foreground focus-visible:ring-[3px] focus-visible:ring-ring/50",So=({childFields:e,depth:t})=>!e||t>=6?null:s.jsxs("details",{className:"docs-schema-children mt-2.5",children:[s.jsxs("summary",{className:To,children:[s.jsx("span",{className:"docs-schema-caret inline-flex text-muted-foreground",children:s.jsx(rt,{size:11,weight:"bold",color:"currentColor","aria-hidden":"true"})}),s.jsx("span",{className:"docs-schema-toggle-open",children:"Show child attributes"}),s.jsx("span",{className:"docs-schema-toggle-close",children:"Hide child attributes"})]}),s.jsx("div",{className:"mt-2 rounded-[12px] border border-foreground/[0.06] px-4",children:s.jsx(T,{fields:e,depth:t+1})})]}),X=(e,t)=>e.map((o,n)=>s.jsxs(r.Fragment,{children:[n>0&&t(n),s.jsx("code",{children:o})]},`${n}-${o}`)),ae=()=>", ",N="mt-1.5 text-sm text-muted-foreground",$o=({schema:e,map:t,mapKeys:o,options:n,hasOptions:a,showDefault:i})=>s.jsxs(s.Fragment,{children:[e.description&&s.jsx(B,{value:e.description,className:"docs-schema-description mt-1.5 text-[0.9375rem] leading-relaxed text-body"}),t&&o&&s.jsxs("p",{className:N,children:["Keys: ",X(o,ae)," · values ",t.type]}),t&&!o&&s.jsxs("p",{className:N,children:["Any key, values: ",t.type]}),a&&n&&s.jsxs("p",{className:N,children:["Options: ",X(n,ae)]}),i&&s.jsxs("p",{className:N,children:["Default: ",s.jsx("code",{children:Io(e.default)})]}),e.oneOf&&s.jsxs("p",{className:N,children:["One of:"," ",X(e.oneOf.map(p=>p.type),ae)]})]}),Po=({field:e})=>{const{schema:t}=e;return s.jsxs("div",{className:"flex flex-wrap items-baseline gap-x-2.5 gap-y-1",children:[s.jsx("code",{className:"docs-schema-name break-all",children:e.name}),s.jsx("span",{className:"docs-schema-type font-mono text-xs text-muted-foreground",children:t.type}),e.required&&s.jsx("span",{className:"text-xs font-medium text-warning",children:"required"}),t.constraints.map(o=>s.jsx("span",{className:"font-mono text-[12px] text-muted-foreground sm:text-[11px]",children:o},o))]})},Lo=({field:e,depth:t})=>{var d;const{schema:o}=e,n=Pt(o),a=Ao(o),i=(d=a==null?void 0:a.keys)!=null&&d.length?a.keys:void 0,p=Eo(o),c=!!(p!=null&&p.length),l=o.default!==void 0&&!c;return s.jsxs("li",{className:"docs-schema-field border-b border-foreground
5/[0.06] py-3.5 last:border-b-0",children:[s.jsx(Po,{field:e}),s.jsx($o,{schema:o,map:a,mapKeys:i,options:p,hasOptions:c,showDefault:l}),s.jsx(So,{childFields:n,depth:t})]},e.name)},T=({fields:e,depth:t=0})=>s.jsx("ul",{className:b("docs-schema",t>0&&"docs-schema-nested"),children:e.map(o=>s.jsx(Lo,{field:o,depth:t},o.name))}),Ro=({endpoint:{body:e}})=>e?s.jsxs(s.Fragment,{children:[s.jsx(U,{section:v.BODY}),s.jsxs("p",{className:"text-sm text-muted-foreground",children:[s.jsx("code",{children:"application/json"})," · ",e.required?"required":"optional"]}),e.description&&s.jsx(B,{value:e.description}),s.jsx(T,{fields:e.schema.fields??[{name:"body",required:e.required,schema:e.schema}]})]}):null,No=({responses:e})=>e.map(t=>s.jsxs("section",{className:"docs-endpoint-response",children:[s.jsxs("h3",{id:D(t.status),className:"flex flex-wrap items-center gap-2.5",children:[s.jsx(F,{variant:t.status.startsWith("5")?"destructive":"warning",children:t.status}),s.jsx("span",{children:t.reason}),s.jsx(K,{id:D(t.status)})]}),t.description&&s.jsx(B,{value:t.description})]},t.status)),Lt=({nodes:e})=>e.map((t,o)=>typeof t=="string"?t:r.createElement(t.tagName,{...t.props,key:o},s.jsx(Lt,{nodes:t.children}))),je=({code:e})=>s.jsx(It,{children:s.jsx(ye,{...e.pre.props,children:s.jsx(Lt,{nodes:e.pre.children})})}),Mo=({errorShape:e,code:t})=>{var o;return(o=e==null?void 0:e.schema)!=null&&o.fields?s.jsxs("section",{className:"docs-endpoint-response",children:[s.jsxs("h3",{id:"error-envelope",children:["Error envelope",s.jsx(K,{id:"error-envelope"})]}),s.jsxs("p",{children:["Every failure below returns the same shape with ",s.jsx("code",{children:"success: false"}),"; branch on"," ",s.jsx("code",{children:"error.code"}),", never on ",s.jsx("code",{children:"message"}),"."]}),s.jsx(T,{fields:e.schema.fields}),e.example&&t.errorEnvelope&&s.jsx(je,{code:t.errorEnvelope})]}):null},Co=({endpoint:e})=>s.jsxs(s.Fragment,{children:[e.pathParameters.length>0&&s.jsxs(s.Fragment,{children:[s.jsx(U,{section:v.PATH}),s.jsx(T,{fields:Me(e.pathParameters)})]}),e.queryParameters.length>0&&s.jsxs(s.Fragment,{children:[s.jsx(U,{section:v.QUERY}),s.jsx(T,{fields:Me(e.queryParameters)})]})]}),Vo=e=>t=>t===e-1?" or ":", ",Zo=({endpoint:{scopes:e},authHref:t})=>e.length===0?null:s.jsxs("p",{className:"mt-4 flex flex-wrap items-center gap-x-2 gap-y-1 text-sm text-body",children:[s.jsx("span",{className:"inline-flex text-primary-text",children:s.jsx(Or,{size:16,weight:"duotone",color:"currentColor","aria-hidden":"true"})}),s.jsxs("span",{children:["Requires the ",X(e,Vo(e.length))," ",s.jsx(_,{href:t,children:"scope"}),"."]})]}),Oo={GET:"success",POST:"warning",PUT:"warning",PATCH:"warning",DELETE:"destructive"},Rt=({method:e,className:t})=>{const o=e.toUpperCase();return s.jsx(F,{variant:Oo[o]??"muted",className:t,children:o})},Ho=({endpoint:e})=>s.jsxs("div",{className:"docs-endpoint-signature flex flex-wrap items-center gap-3 rounded-2xl border border-border px-4 py-3",children:[s.jsx(Rt,{method:e.method}),s.jsx("code",{className:"docs-endpoint-path min-w-0 font-mono text-[0.9375rem] font-medium break-all text-foreground",children:e.path})]}),Do=({responses:e,code:t})=>e.map(o=>{var a;const n=o.example?t.responses[o.status]:void 0;return s.jsxs("section",{className:"docs-endpoint-response",children:[s.jsxs("h3",{id:D(o.status),className:"flex flex-wrap items-center gap-2.5",children:[s.jsx(F,{variant:"success",children:o.status}),s.jsx("span",{children:o.reason}),s.jsx(K,{id:D(o.status)})]}),o.description&&s.jsx(B,{value:o.description}),((a=o.schema)==null?void 0:a.fields)&&s.jsx(T,{fields:o.schema.fields}),n&&s.jsx(je,{code:n})]},o.status)}),{PARAM_LOCATIONS:le,STATUS_CLASSES:Q,LABELS:x,TOKEN_STORAGE_KEY:de}=rs,Uo="Enter",Ce="application/json",J="token",Z="body",ve="ml-1.5 text-[12px] font-semibold tracking-wide text-warning uppercase sm:text-[10px]",Ve="outline-none focus-visible:ring-[3px] focus-visible:ring-ring/50",xe={autoComplete:"off",autoCapitalize:"off",autoCorrect:"off",spellCheck:!1},Fo=({body:e,state:t})=>{const o=t.errors[Z],n=r.useRef(null);return s.jsxs("div",{className:"flex min-w-0 flex-col gap-1.5",children:[s.jsxs("div",{className:"flex flex-wrap items-center gap-2",children:[s.jsxs(he,{htmlFor:"playground-body",children:["Body",s.jsx("span",{className:"ml-1.5 text-[12px] text-muted-foreground sm:text-[11px]",children:e.contentType}),e.required&&s.jsx("span",{className:ve,children:"required"})]}),s.jsxs(R,{type:"button",variant:"ghost",size:"sm",className:"ml-auto",onClick:()=>{var a;t.resetBody(),t.clearError(Z),(a=n.current)==null||a.focus()},children:[s.jsx(Hr,{weight:"duotone",className:"size-4","aria-hidden":"true"}),"Reset to example"]})]}),s.jsx(Dr,{ref:n,id:"playground-body","data-hj-suppress":"","data-clarity-mask":"true",rows:Math.min(14,Math.max(4,e.example.split(` 6`).length+1)),...xe,"aria-describedby":"playground-body-error","aria-invalid":o?!0:void 0,className:"font-mono leading-relaxed",value:t.body,onChange:a=>{t.setBody(a.target.value),t.clearError(Z)}}),s.jsx(ge,{id:"playground-body-error",children:o})]})},Ko=({authHref:e,outcome:t})=>{const o=r.useRef(null),n=(t==null?void 0:t.kind)==="failure"?t.message:null;return r.useEffect(()=>{var a;n&&((a=o.current)==null||a.scrollIntoView({block:"nearest",behavior:"smooth"}))},[t,n]),s.jsxs("div",{ref:o,role:"alert",className:"border-t border-foreground
6/[0.06] px-4 py-4 text-sm text-body",hidden:!n,children:[s.jsx("span",{children:n})," ",s.jsx(_,{href:e,className:"text-primary-text underline underline-offset-2",children:"Authentication guide"})]})},Bo=({model:e,preview:t})=>s.jsxs("div",{className:"flex flex-wrap items-center gap-x-3 gap-y-2 border-b border-foreground/[0.06] px-4 py-3",children:[s.jsxs("span",{className:"inline-flex items-center gap-2 text-sm font-semibold text-foreground",children:[s.jsx("span",{className:"inline-flex text-primary-text",children:s.jsx(Xe,{size:16,weight:"duotone",color:"currentColor","aria-hidden":"true"})}),"Try it"]}),s.jsxs("span",{className:"ml-auto flex min-w-0 items-center gap-2",children:[s.jsx(Rt,{method:e.method}),s.jsx("code",{className:"docs-playground-url min-w-0 font-mono text-xs wrap-anywhere text-muted-foreground",title:t,children:t})]})]}),oe=e=>`playground-${e.in}-${e.name}`,qe=e=>[...e.pathParameters,...e.queryParameters],zo=e=>{var t;return!((t=e.enum)!=null&&t.length)||!e.required?"":e.enum.includes(e.example)?e.example:e.enum[0]??""},Go=e=>Object.fromEntries(qe(e).map(t=>[oe(t),zo(t)])),Wo=({parameter:e,state:t})=>{var i;const o=oe(e),n=t.errors[o],a={id:o,"aria-describedby":`${o}-error`,"aria-invalid":n?!0:void 0,value:t.values[o]??"",onChange:p=>{t.setValue(o,p.target.value),t.clearError(o)}};return s.jsxs("div",{className:"flex min-w-0 flex-col gap-1.5",children:[s.jsxs(he,{htmlFor:o,children:[s.jsx("code",{className:"font-mono text-[13px] text-foreground",children:e.name}),s.jsx("span",{className:"ml-1.5 text-[12px] text-muted-foreground sm:text-[11px]",children:e.type}),e.required&&s.jsx("span",{className:ve,children:"required"})]}),(i=e.enum)!=null&&i.length?s.jsxs("div",{className:"relative flex",children:[s.jsxs("select",{...a,className:b(_e.SELECT,"w-full"),children:[!e.required&&s.jsx("option",{value:"",children:"(omit)"}),e.enum.map(p=>s.jsx("option",{value:p,children:p},p))]}),s.jsx(st,{weight:"bold","aria-hidden":"true",className:_e.SELECT_ICON})]}):s.jsx(ot,{...a,type:"text",...xe,placeholder:e.example||e.name}),s.jsx(ge,{id:`${o}-error`,children:n})]})},Yo=({model:e,state:t})=>{const o=[{location:le.PATH,title:"Path parameters",parameters:e.pathParameters},{location:le.QUERY,title:"Query parameters",parameters:e.queryParameters}].filter(n=>n.parameters.length>0);return s.jsx(s.Fragment,{children:o.map(n=>s.jsxs("fieldset",{className:"m-0 min-w-0 border-0 p-0",children:[s.jsx("legend",{className:"mb-2 text-xs font-semibold tracking-wider text-foreground uppercase",children:n.title}),s.jsx("div",{className:"grid gap-3 sm:grid-cols-2",children:n.parameters.map(a=>s.jsx(Wo,{parameter:a,state:t},a.name))})]},n.location))})},Qo=e=>e>=200&&e<300?Q.SUCCESS:e>=500?Q.DESTRUCTIVE:e>=400?Q.WARNING:Q.NEUTRAL,Xo=e=>{if(!e)return x.EMPTY_BODY;try{return JSON.stringify(JSON.parse(e),null,2)}catch{return e}},Jo=({outcome:e})=>{const t=r.useRef(null),o=r.useRef(null),n=(e==null?void 0:e.kind)==="response"?e:null;return r.useEffect(()=>{var a;n&&((a=t.current)==null||a.scrollIntoView({block:"nearest",behavior:"smooth"}))}
6,[n]),s.jsxs("div",{ref:t,className:"border-t border-foreground/[0.06]","aria-live":"polite",hidden:!n,children:[s.jsxs("div",{className:"flex flex-wrap items-center gap-3 px-4 py-3",children:[s.jsx(F,{variant:"muted",className:n?Qo(n.status):void 0,children:n?`${n.status}${n.statusText?` ${n.statusText}`:""}`:""}),s.jsx("span",{className:"font-mono text-xs text-muted-foreground",children:n?`${n.duration} ms`:""}),s.jsxs("details",{className:"docs-playground-headers min-w-0 text-xs text-muted-foreground",children:[s.jsx("summary",{className:b("cursor-pointer rounded-sm select-none hover:text-foreground",Ve),children:"Response headers"}),s.jsx("pre",{className:"mt-2 max-h-48 overflow-auto rounded-md border border-border px-3 py-2 font-mono text-[12px] leading-relaxed whitespace-pre-wrap break-all text-body",children:n==null?void 0:n.headers})]})]}),s.jsxs("div",{className:"relative px-4 pb-4",children:[s.jsx("div",{className:"absolute top-2 right-6 z-10",children:s.jsx(We,{source:()=>o.current})}),s.jsx("pre",{ref:o,"data-hj-suppress":"","data-clarity-mask":"true",tabIndex:0,className:b("max-h-[32rem] overflow-auto rounded-md border border-border px-4 py-3 font-mono text-[13px] leading-relaxed whitespace-pre-wrap break-words text-foreground",Ve),children:n?Xo(n.body):""})]})]})},en=({busy:e})=>s.jsxs("div",{className:"flex flex-wrap items-center gap-3",children:[s.jsxs(R,{type:"submit",disabled:e,children:[s.jsx(Ur,{weight:"duotone",className:"size-4","aria-hidden":"true"}),s.jsx("span",{children:e?x.SENDING:x.SEND})]}),s.jsxs("span",{className:"hidden text-xs text-muted-foreground sm:inline",children:["or press ",s.jsx("kbd",{children:"â"})," ",s.jsx("kbd",{children:"âµ"})," in the panel"]})]}),tn=({state:e})=>{const{token:t,errors:o,clearError:n}=e,a=o[J],i=t.revealed?x.HIDE:x.SHOW;return s.jsxs("div",{className:"flex flex-col gap-1.5",children:[s.jsxs(he,{htmlFor:"playground-token",children:["API key",s.jsx("span",{className:ve,children:"required"}),s.jsx("span",{className:"ml-auto text-[12px] font-normal text-muted-foreground sm:text-[11px]",children:"Kept in this tab only"})]}),s.jsxs("div",{className:"flex items-center gap-2",children:[s.jsxs("div",{className:"relative min-w-0 flex-1",children:[s.jsx(ot,{ref:t.inputRef,id:"playground-token","data-hj-suppress":"","data-clarity-mask":"true",type:t.revealed?"text":"password",...xe,placeholder:"ev_sk_â¦","aria-describedby":"playground-token-error","aria-invalid":a?!0:void 0,className:"[&>input]:pr-12",value:t.value,onChange:p=>{t.change(p.target.value),n(J)}}),s.jsx(R,{type:"button",variant:"ghost",size:"icon-sm","aria-label":i,"aria-pressed":t.revealed,title:i,className:"absolute top-1/2 right-1 -translate-y-1/2",onClick:t.toggle,children:t.revealed?s.jsx(Kr,{weight:"duotone",className:"size-4","aria-hidden":"true"}):s.jsx(Fr,{weight:"duotone",className:"size-4","aria-hidden":"true"})})]}),s.jsxs(R,{type:"button",variant:"ghost",size:"sm",title:"Forget the API key in this tab",onClick:()=>{t.forget(),n(J)},children:[s.jsx(Er,{weight:"duotone",className:"size-4","aria-hidden":"true"}),"Forget"]})]}),s.jsx(ge,{id:"playground-token-error",children:a})]})},Nt=(e,t,o,n)=>{const a=new Map,i=new URLSearchParams;for(const l of qe(e)){const d=(o[oe(l)]??"").trim();l.in===le.PATH?a.set(l.name,d):d&&i.append(l.name,d)}const p=e.path.replace(/\{([^}]+)\}/g,(l,d)=>{const m=a.get(d)??"";return m||!n?encodeURIComponent(m):l}),c=i.toString();return`${t.replace(/\/+$/,"")}${p}${c?`?${c}`:""}`},rn=async(e,t)=>{const o=await e.text();return{kind:"response",status:e.status,statusText:e.statusText,duration:Math.round(performance.now()-t),headers:Array.from(e.headers.entries()).map(([n,a])=>`${n}: ${a}`).join(` 7`),body:o}},sn=e=>{const[t,o]=r.useState(!1),[n,a]=r.useState(null),i=r.useRef(!1);return{busy:t,outcome:n,send:async(c,l)=>{if(i.current)return;const d={Authorization:`Bearer ${l.trim()}`,Accept:Ce};c.payload!==null&&(d["Content-Type"]=Ce),i.current=!0,o(!0);const m=performance.now();try{const u=await fetch(c.url,{method:e.toUpperCase(),headers:d,body:c.payload,mode:"cors",credentials:"omit",cache:"no-store"});a(await rn(u,m))}
7catch{a({kind:"failure",message:x.NETWORK_ERROR})}finally{i.current=!1,o(!1)}},isInflight:()=>i.current}},on=()=>{try{return window.sessionStorage.getItem(de)??""}catch{return""}},Ze=e=>{try{e?window.sessionStorage.setItem(de,e):window.sessionStorage.removeItem(de)}catch{}},nn=()=>{const[e,t]=r.useState(""),[o,n]=r.useState(!1),a=r.useRef(null);return r.useEffect(()=>t(on()),[]),{value:e,revealed:o,inputRef:a,change:i=>{t(i),Ze(i.trim())},toggle:()=>n(i=>!i),forget:()=>{var i;t(""),Ze(""),(i=a.current)==null||i.focus()}}},an=e=>{try{return{payload:JSON.stringify(JSON.parse(e))}}catch(t){return{payload:null,error:`${x.BODY_INVALID}${t instanceof Error?t.message:String(t)}`}}},pn=e=>{var m;const{model:t,baseUrl:o,token:n,values:a,body:i}=e,p={};n.trim()||(p[J]=x.TOKEN_REQUIRED);for(const u of qe(t)){const y=oe(u);u.required&&!(a[y]??"").trim()&&(p[y]=x.PARAM_REQUIRED)}const c=t.body?i.trim():"";let l=null;if(c){const u=an(c);l=u.payload,u.error&&(p[Z]=u.error)}else(m=t.body)!=null&&m.required&&(p[Z]=x.BODY_REQUIRED);const d=Object.keys(p).length===0;return{errors:p,request:d?{url:Nt(t,o,a,!1),payload:l}:null}},cn=(e,t)=>{var S;const o=nn(),[n,a]=r.useState(()=>Go(e)),[i,p]=r.useState(((S=e.body)==null?void 0:S.example)??""),[c,l]=r.useState({}),{busy:d,outcome:m,send:u,isInflight:y}=sn(e.method),g=w=>l(A=>{if(!(w in A))return A;const{[w]:z,...j}=A;return j}),h=()=>{if(y())return;const w=pn({model:e,baseUrl:t,token:o.value,values:n,body:i});l(w.errors),w.request&&u(w.request,o.value)};return{token:o,values:n,body:i,errors:c,busy:d,outcome:m,preview:Nt(e,t,n,!0),clearError:g,setValue:(w,A)=>a(z=>({...z,[w]:A})),setBody:p,resetBody:()=>{var w;return p(((w=e.body)==null?void 0:w.example)??"")},submit:h}},ln=({model:e,baseUrl:t,authHref:o,className:n})=>{const a=cn(e,t),i=p=>{p.key!==Uo||!(p.metaKey||p.ctrlKey)||(p.preventDefault(),a.submit())};return s.jsxs("section",{className:b("docs-playground mt-8 overflow-hidden rounded-2xl border border-border text-sm text-body",n),"aria-label":"Try this endpoint","aria-busy":a.busy,onKeyDown:i,children:[s.jsx(Bo,{model:e,preview:a.preview}),s.jsxs("form",{noValidate:!0,className:"flex flex-col gap-5 px-4 py-4",onSubmit:p=>{p.preventDefault(),a.submit()},children:[s.jsx(tn,{state:a}),s.jsx(Yo,{model:e,state:a}),e.body&&s.jsx(Fo,{body:e.body,state:a}),s.jsx(en,{busy:a.busy})]}),s.jsx(Ko,{authHref:o,outcome:a.outcome}),s.jsx(Jo,{outcome:a.outcome})]})},dn=({endpoint:e,code:t,baseUrl:o,authHref:n})=>{const a=e.responses.filter(c=>c.success),i=e.responses.filter(c=>!c.success),p=i.find(c=>c.schema);return s.jsxs("div",{className:"docs-endpoint",children:[s.jsx(Ho,{endpoint:e}),e.description&&s.jsx(B,{value:e.description,className:"docs-endpoint-description mt-6"}),s.jsx(Zo,{endpoint:e,authHref:n}),s.jsx(je,{code:t.curl}),s.jsx(ln,{model:Hs(e),baseUrl:o,authHref:n}),s.jsx(U,{section:v.AUTHORIZATION}),s.jsx(T,{fields:ko}),s.jsx(Co,{endpoint:e}),s.jsx(Ro,{endpoint:e}),s.jsx(U,{section:v.RESPONSES}),s.jsx(Do,{responses:a,code:t}),s.jsx(Mo,{errorShape:p,code:t}),s.jsx(No,{responses:i})]})},mn=({crumbs:e})=>{const t=e.length-1;return s.jsx("span",{className:"docs-mobile-trail flex h-5 min-w-0 flex-1 flex-row-reverse flex-wrap justify-end overflow-hidden text-sm leading-5","aria-hidden":"true",children:e.map((o,n)=>s.jsxs("span",{className:b("whitespace-nowrap",n===t?"min-w-0 truncate font-medium text-foreground":"shrink-0 text-body"),children:[o,n<t&&s.jsx("span",{className:"px-1.5 text-muted-foreground",children:"/"})]},`${n}-${o}`)).reverse()})},Mt=r.createContext({open:!1,setOpen:()=>{},prefetch:()=>{}}),ke=()=>r.useContext(Mt),Oe="docs-mobile-bar-trail",un=({crumbs:e,className:t,drawer:o})=>{const n=ke();return s.jsxs("div",{className:b("docs-mobile-bar -mx-4 flex items-center gap-1 rounded-full p-1 md:-mr-1.5 md:-ml-5 lg:hidden",t),children:[s.jsxs("button",{ref:o.triggerRef,type:"button",className:"docs-mobile-bar-toggle flex h-11 min-w-0 flex-1 items-center gap-2.5 rounded-full pr-3 pl-3.5 text-left outline-none transition-fx hover:cursor-pointer hover:bg-accent-soft focus-visible:ring-[3px] focus-visible:ring-ring/50","aria-controls":"docs-sidebar","aria-expanded":o.open,"aria-label":"Open documentation menu","aria-describedby":Oe,onClick:o.toggle,children:[s.jsx(cr,{weight:"duotone",className:"size-4 shrink-0 text-primary-text","aria-hidden":"true"}),s.jsx(mn,{crumbs:e}),s.jsx(st,{weight:"bold",className:"size-3 shrink-0 text-muted-foreground","aria-hidden":"true"}),s.jsx("span",{id:Oe,className:"sr-only",children:e.join(" / ")})]}),s.jsx(R,{type:"button",variant:"ghost",size:"icon",className:"size-11 sm:size-11","aria-label":"Search documentation","aria-haspopup":"dialog",onClick:()=>n.setOpen(!0),onPointerEnter:n.prefetch,onFocus:n.prefetch,children:s.jsx(nt,{weight:"duotone",className:"size-4","aria-hidden":"true"})})]})},yn=({compact:e,className:t})=>{const{setOpen:o,prefetch:n}=ke();return s.jsxs("button",{type:"button","aria-label":"Search documentation","aria-haspopup":"dialog",onClick:()=>o(!0),onPointerEnter:n,onFocus:n,className:b("flex w-full items-center gap-2 rounded-xl bg-tertiary px-3 text-left text-sm text-muted-foreground transition-colors outline-none hover:cursor-pointer hover:bg-tertiary/70 focus-visible:ring-[3px] focus-visible:ring-ring/50",e?"h-9":"h-10",t),children:[s.jsx(nt,{weight:"duotone",className:"size-4 shrink-0","aria-hidden":"true"}),s.jsx("span",{className:"min-w-0 flex-1 truncate",children:"Search docsâ¦"}),!e&&s.jsx(C,{className:"hidden sm:inline-flex",children:"âK"})]})},gn=({variant:e="default",className:t})=>s.jsx(yn,{compact:e==="compact",className:t}),hn=({label:e,drawer:t})=>s.jsxs("div",{ref:t.headRef,className:"docs-drawer-head pb-6",children:[s.jsxs("div",{className:"mb-5 flex items-center justify-between lg:hidden",children:[s.jsx("span",{className:"text-xs font-semibold tracking-wider text-foreground uppercase",children:e??"Documentation"}),s.jsx(R,{ref:t.closeRef,type:"button",variant:"secondary",size:"icon",className:"size-11 sm:size-11","aria-label":"Close documentation menu",onClick:t.close,children:s.jsx(lr,{weight:"bold",className:"size-4","aria-hidden":"true"})})]}),s.jsx(gn,{})]}),bn="docs-sidebar-link block truncate rounded-full px-3 py-1.5 text-[14px] leading-5 text-body transition-fx hover:text-foreground",fn="docs-sidebar-summary flex cursor-pointer list-none items-center justify-between gap-2 rounded-full px-3 py-1.5 text-[14px] leading-5 text-body transition-fx select-none hover:text-foreground",Ct=({items:e,currentId:t,currentRef:o,lookup:n,depth:a=0})=>s.jsx("ul",{className:b("flex flex-col gap-px",a>
70&&"ml-4 border-l border-foreground/[0.06] pl-1"),children:e.map(i=>i.kind==="page"?s.jsx("li",{ref:i.id===t?o:void 0,children:s.jsx(_,{href:i.href,"aria-current":i.id===t?"page":void 0,className:b(bn,i.id===t&&"font-medium"),title:ee(i.id,n),children:ee(i.id,n)})},i.id):s.jsx("li",{children:s.jsxs("details",{open:i.pageIds.includes(t),className:"docs-sidebar-group",children:[s.jsxs("summary",{className:fn,children:[s.jsx("span",{className:"truncate",children:i.label}),s.jsx("span",{className:"docs-sidebar-caret inline-flex shrink-0 text-muted-foreground",children:s.jsx(rt,{size:12,weight:"bold",color:"currentColor","aria-hidden":"true"})})]}),s.jsx(Ct,{items:i.items,currentId:t,currentRef:o,lookup:n,depth:a+1})]})},i.label))}),wn="docs-sidebar-section flex items-center gap-2 rounded-full px-3 py-1.5 text-[14px] leading-5 text-body transition-fx hover:text-foreground",jn="font-medium",vn=({tabs:e,currentTab:t,groups:o,currentId:n,lookup:a,currentRef:i,className:p})=>s.jsxs("div",{className:b("docs-sidebar flex flex-col gap-6",p),children:[s.jsxs("nav",{"aria-label":"Sections",className:re,children:[s.jsx(O,{active:'[aria-current="true"]',activeKey:t,activeClass:P.ACTIVE,hover:'.docs-sidebar-section:not([aria-current="true"])',hoverClass:P.HOVER}),s.jsx("ul",{className:"flex flex-col gap-px",children:e.map(c=>{const l=c.label===t;return s.jsx("li",{children:s.jsxs(_,{href:c.href,"aria-current":l?"true":void 0,className:`${wn}${l?` ${jn}`:""}`,children:[c.icon&&s.jsx("span",{className:`inline-flex shrink-0 transition-fx ${l?"text-primary-text":"text-muted-foreground"}`,children:s.jsx(ce,{name:c.icon,size:15})}),s.jsx("span",{children:c.label})]})},c.label)})})]}
7),s.jsx("hr",{className:"my-1 h-px border-0 bg-foreground/[0.06]","aria-hidden":"true"}),s.jsxs("nav",{"aria-label":"Documentation pages",className:`flex flex-col gap-7 ${re}`,children:[s.jsx(O,{active:'[aria-current="page"]',activeKey:n,activeClass:P.ACTIVE,hover:'.docs-sidebar-link:not([aria-current="page"]), .docs-sidebar-summary',hoverClass:P.HOVER}),o.map(c=>s.jsxs("div",{children:[s.jsxs("p",{className:"mb-2 flex items-center gap-2 px-3 text-xs font-semibold tracking-wider text-foreground uppercase",children:[c.icon&&s.jsx("span",{className:"inline-flex shrink-0 text-primary-text",children:s.jsx(ce,{name:c.icon,size:15})}),s.jsx("span",{children:c.label})]}),s.jsx(Ct,{items:c.items,currentId:n,currentRef:i,lookup:a})]},c.label))]})]}),xn="docs-drawer lg:sticky lg:top-28 lg:block lg:max-h-[calc(100vh-8.5rem)] lg:w-52 lg:shrink-0 lg:overflow-y-auto lg:pr-2 lg:pb-8",qn=({id:e,tabLabel:t,lookup:o,drawer:n})=>{const a=s.jsxs("aside",{ref:n.drawerRef,id:"docs-sidebar","aria-label":"Documentation navigation",className:b(xn,n.open&&"is-open"),onClick:n.onDrawerClick,children:[s.jsx(hn,{label:t,drawer:n}),s.jsx(vn,{tabs:ar,currentTab:t,groups:js(e),currentId:e,currentRef:n.currentRef,lookup:o})]});return n.floating?Br.createPortal(s.jsxs(s.Fragment,{children:[s.jsx("div",{className:b("docs-drawer-backdrop fixed inset-0 z-50 bg-overlay",n.open&&"is-open"),"aria-hidden":"true",onClick:n.close}),a]}),document.body):a},kn=({eyebrow:e,title:t,description:o,headingRef:n})=>s.jsxs("header",{className:"mb-10",children:[e&&s.jsx("p",{className:"mb-3 text-xs font-medium tracking-wide text-primary-text uppercase",children:e}),s.jsx("h1",{ref:n,className:"font-display text-3xl font-normal tracking-[-0.5px] break-words text-foreground sm:text-4xl md:text-[40px] md:leading-[1.15]",tabIndex:-1,children:t}),o&&s.jsx("p",{className:"mt-4 text-base leading-relaxed break-words text-body md:text-lg",children:o})]}),He="group flex min-w-0 flex-col gap-2 rounded-2xl border border-border p-5 transition-fx hover:border-foreground
7/20 focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-primary",De="inline-flex items-center gap-1.5 text-xs font-medium tracking-wide text-muted-foreground uppercase transition-fx group-hover:text-primary-text",Ue="block font-display text-xl leading-snug font-semibold break-words text-foreground transition-fx group-hover:text-primary-text",_n=({prev:e,next:t,lookup:o})=>!e&&!t?null:s.jsxs("nav",{"aria-label":"Pagination",className:"docs-pagination mt-16 grid grid-cols-1 gap-4 sm:grid-cols-2",children:[e?s.jsxs(_,{href:e.href,rel:"prev",className:He,children:[s.jsxs("span",{className:De,children:[s.jsx(zr,{size:14,weight:"bold",color:"currentColor","aria-hidden":"true"})," Previous"]}),s.jsx("span",{className:Ue,children:ee(e.id,o)})]}):s.jsx("span",{"aria-hidden":"true"}),t&&s.jsxs(_,{href:t.href,rel:"next",className:`${He} items-end text-right`,children:[s.jsxs("span",{className:De,children:["Next ",s.jsx(Gr,{size:14,weight:"bold",color:"currentColor","aria-hidden":"true"})]}),s.jsx("span",{className:Ue,children:ee(t.id,o)})]})]}),Vt=140,An=2,En=e=>{let t=null;for(const n of e)if(n.getBoundingClientRect().top-Vt<=0)t=n;else break;return window.innerHeight+window.scrollY>=document.documentElement.scrollHeight-An&&(t=e[e.length-1]??t),(t==null?void 0:t.id)??null},Fe=`
8`,In=e=>{const[t,o]=r.useState(null),{pathname:n}=ue(),a=e.join(Fe);return r.useEffect(()=>{const i=a.split(Fe).map(m=>m?document.getElementById(m):null).filter(m=>m!==null);let p=0;const c=()=>{p=0,o(En(i))},l=()=>{p||(p=requestAnimationFrame(c))},d=new IntersectionObserver(l,{rootMargin:`-${Vt}px 0px 0px 0px`,threshold:[0,1]});return i.forEach(m=>d.observe(m)),window.addEventListener("scroll",l,{passive:!0}),window.addEventListener("resize",l,{passive:!0}),c(),()=>{d.disconnect(),cancelAnimationFrame(p),window.removeEventListener("scroll",l),window.removeEventListener("resize",l)}},[a,n]),t},Tn=({headings:e,className:t})=>{const o=e.filter(a=>a.depth>=2&&a.depth<=3),n=In(o.map(a=>a.slug));return o.length===0?null:s.jsxs("nav",{"aria-label":"On this page",className:b("docs-toc",t),children:[s.jsx("p",{className:"mb-3 px-3 text-xs font-semibold tracking-wider text-foreground uppercase",children:"On this page"}),s.jsxs("div",{className:`flex flex-col gap-px ${re}`,children:[s.jsx(O,{active:'[aria-current="location"]',activeKey:n,activeClass:P.ACTIVE,hover:'.docs-toc-link:not([aria-current="location"])',hoverClass:P.HOVER}),o.map(a=>s.jsx("a",{href:`#${a.slug}`,title:a.text,"aria-current":n===a.slug?"location":void 0,className:`docs-toc-link block truncate rounded-full py-1.5 pr-3 text-[14px] leading-5 text-body transition-fx hover:text-foreground ${a.depth===2?"pl-3":"pl-6"}`,children:a.text},a.slug))]})]})},Zt="(min-width: 1024px)",Sn=e=>e instanceof Element&&e.closest('[role="dialog"]')!==null,$n="sticky",Pn=e=>e&&getComputedStyle(e).position===$n?e.offsetHeight:0,Ln=(e,t,o)=>{if(!e||!o)return;const n=Pn(t),a=e.getBoundingClientRect(),i=o.getBoundingClientRect(),p=i.top-a.top+e.scrollTop;p>=e.scrollTop+n&&p+i.height<=e.scrollTop+e.clientHeight||(e.scrollTop=Math.max(0,p-n-(e.clientHeight-n)/2+i.height/2))},Rn=()=>{const[e,t]=r.useState(!1);return r.useEffect(()=>{const o=window.matchMedia(Zt),n=()=>t(!o.matches);return n(),o.addEventListener("change",n),()=>o.removeEventListener("change",n)},[]),e},Nn="Escape",Mn=e=>{const[t,o]=r.useState(!1),n=r.useRef(null),a=r.useRef(null),i=r.useRef(null),p=r.useRef(null),c=r.useRef(null),l=ke(),d=r.useRef(l.open),m=Rn(),u=()=>Ln(n.current,i.current,c.current),y=()=>{var g;o(!1),(g=a.current)==null||g.focus({preventScroll:!0})};return r.useEffect(()=>{o(!1),window.matchMedia(Zt).matches&&u()},[e]),r.useEffect(()=>{m||o(!1)},[m]),r.useEffect(()=>{if(!t)return;const g=requestAnimationFrame(()=>{var h;(h=p.current)==null||h.focus(),u()});return document.body.style.overflow="hidden",()=>{cancelAnimationFrame(g),document.body.style.overflow=""}},[t]),r.useEffect(()=>{d.current=l.open},[l.open]),r.useEffect(()=>{if(!t)return;const g=h=>{h.key!==Nn||d.current||Sn(h.target)||y()};return document.addEventListener("keydown",g,!0),()=>document.removeEventListener("keydown",g,!0)},[t]),{open:t,floating:m,drawerRef:n,triggerRef:a,headRef:i,closeRef:p,currentRef:c,toggle:()=>o(g=>!g),close:y,onDrawerClick:g=>{g.target instanceof Element&&g.target.closest("a")&&o(!1)}}},Ke='[aria-hidden="true"], [inert]',Cn={subtree:!0,attributes:!0,attributeFilter:["aria-hidden","inert"]},Vn=()=>document.activeElement===null||document.activeElement===document.body,Zn=e=>{if(!e.closest(Ke))return e.focus({preventScroll:!0}),()=>{};const t=new MutationObserver(()=>{if(!e.isConnected)return t.disconnect();e.closest(Ke)||(t.disconnect(),Vn()&&e.focus({preventScroll:!0}))});return t.observe(document.body,Cn),()=>t.disconnect()},On=(e,t)=>{const o=r.useRef(null),n=r.useRef(e),[a,i]=r.useState("");return r.useEffect(()=>{if(n.current!==e)return n.current=e,i(t),o.current?Zn(o.current):void 0},[e,t]),{headingRef:o,announcement:a}},Hn=({id:e,title:t,description:o,headings:n=[],prev:a,next:i,lookup:p,children:c})=>{const l=se(e),d=H(e),m=[l==null?void 0:l.label,...(d==null?void 0:d.groupPath)??[],t].filter(h=>!!h),u=Mn(e),{headingRef:y,announcement:g}=On(e,t);return s.jsxs("div",{className:"docs-shell min-h-screen bg-background pt-[var(--docs-bar-top)] pb-20 lg:pt-[7.5rem]",children:[s.jsx("div",{className:"max-w-section mx-auto w-full px-5 md:px-[60px]",children:s.jsxs("div",{className:"flex items-start gap-10",children:[s.jsx(qn,{id:e,tabLabel:l==null?void 0:l.label,lookup:p,drawer:u}),s.jsxs("div",{className:"min-w-0 flex-1",children:[s.jsx(un,{crumbs:m,className:"mb-8",drawer:u}),s.jsx(kn,{eyebrow:d==null?void 0:d.groupPath.at(-1),title:t,description:o,headingRef:y}),s.jsx("article",{className:"docs-prose",children:c}),s.jsx(_n,{prev:a,next:i,lookup:p})]}),s.jsx("aside",{className:"scrollbar-hidden sticky top-28 hidden max-h-[calc(100vh-8.5rem)] w-44 shrink-0 overflow-y-auto pb-8 xl:block",children:s.jsx(Tn,{headings:n})})]})}),s.jsx("div",{className:"sr-only",role:"status","aria-live":"polite",children:g})]})},Dn="/docs/search-index.json",Un=24,Fn=3,ie={IDLE:"Search titles, headings and content across the docs.",ERROR:"Search is unavailable right now. Please try again."},q={title:[100,80,60],alt:[70,55,40],endpoint:[80,60,40],description:[20,15,10],intro:[10,8,6],heading:[60,48,3
86],excerpt:[12,10,8],pageForSection:[30,24,18]},Kn=()=>s.jsxs(xr,{className:"hidden border-t border-border/60 sm:flex",children:[s.jsxs("span",{className:"inline-flex items-center gap-1.5",children:[s.jsx(C,{children:s.jsx(lt,{weight:"bold",className:"size-3"})}),s.jsx(C,{children:s.jsx(it,{weight:"bold",className:"size-3"})}),"Navigate"]}),s.jsxs("span",{className:"inline-flex items-center gap-1.5",children:[s.jsx(C,{children:s.jsx(pt,{weight:"bold",className:"size-3"})}),"Open"]}),s.jsxs("span",{className:"inline-flex items-center gap-1.5",children:[s.jsx(C,{children:"esc"}),"Close"]})]}),Bn=(e,t)=>{const o=e.toLowerCase(),n=[];for(const p of t){let c=0;for(;c<o.length;){const l=o.indexOf(p,c);if(l===-1)break;n.push([l,l+p.length]),c=l+p.length}}n.sort((p,c)=>p[0]-c[0]);const a=[];let i=0;for(const[p,c]of n){if(c<=i)continue;const l=Math.max(p,i);l>i&&a.push({text:e.slice(i,l),marked:!1}),a.push({text:e.slice(l,c),marked:!0}),i=c}return i<e.length&&a.push({text:e.slice(i),marked:!1}),a},Be=({text:e,tokens:t})=>s.jsx(s.Fragment,{children:Bn(e,t).map((o,n)=>s.jsx(r.Fragment,{children:o.marked?s.jsx("mark",{className:"bg-transparent font-medium text-primary-text",children:o.text}):o.text},n))}),zn={page:Wr,section:Yr},Gn=({hit:e,tokens:t})=>{const o=zn[e.kind];return s.jsxs(s.Fragment,{children:[s.jsx(o,{size:16,weight:"duotone",className:"mt-0.5 shrink-0 text-muted-foreground","aria-hidden":"true"}),s.jsxs("span",{className:"flex min-w-0 flex-1 flex-col",children:[s.jsx("span",{className:"truncate text-sm font-medium text-body",children:s.jsx(Be,{text:e.title,tokens:t})}),s.jsx("span",{className:"truncate text-[11px] leading-4 text-muted-foreground",children:e.crumb}),e.snippet&&s.jsx("span",{className:"mt-0.5 line-clamp-2 text-xs leading-5 text-muted-foreground",children:s.jsx(Be,{text:e.snippet,tokens:t})})]})]})},Ot=()=>{const e=Kt(),{pathname:t}=ue();return o=>dr(t,o)?!1:(e(o),!0)},Wn=0,Yn=e=>e.button===Wn&&!e.metaKey&&!e.ctrlKey&&!e.shiftKey&&!e.altKey,Qn=e=>{const t=Ot();return o=>{const n=o.target instanceof Element?o.target.closest("a"):null,a=n==null?void 0:n.getAttribute("href");!a||o.defaultPrevented||!Yn(o)||(e(a),t(a)&&o.preventDefault())}},{CommandDialog:Xn,CommandInput:Jn,CommandList:ea,CommandGroup:ta,CommandItem:ra,CommandEmpty:pe,CommandLoading:sa}=qr,oa=({state:e})=>{const{open:t,setOpen:o,query:n,setQuery:a,tokens:i,groups:p,status:c,activeId:l,setActiveId:d,handleKeyDown:m}=e,u=Qn(e.leave);return s.jsxs(Xn,{open:t,onOpenChange:o,label:"Search documentation",description:ie.IDLE,onKeyDown:m,onCloseAutoFocus:e.onCloseAutoFocus,children:[s.jsx(Jn,{value:n,onValueChange:a,placeholder:"Search docsâ¦"}),s.jsx("div",{className:"contents",onClickCapture:u,children:s.jsxs(ea,{children:[c==="loading"&&s.jsx(sa,{}),c==="idle"&&s.jsx(pe,{children:ie.IDLE}),c==="error"&&s.jsx(pe,{children:ie.ERROR}),c==="empty"&&s.jsxs(pe,{children:["No results for â",n.trim(),"â."]}),p.map(([y,g])=>s.jsx(ta,{heading:y,children:g.map(h=>s.jsx(ra,{id:h.href,href:h.href,active:l===h.href,onSelect:()=>o(!1),onMouseMove:()=>d(h.href),children:s.jsx(Gn,{hit:h,tokens:i})},h.href))},y))]})}),s.jsx(Kn,{})]})},na=e=>{const t=new Map;for(const o of e){const n=t.get(o.tab);n?n.push(o):t.set(o.tab,[o])}return Array.from(t.entries())},E=e=>({text:e,lower:e.toLowerCase()}),aa=e=>{const t=e.sections.find(([n,a])=>!n&&!a),o=e.sections.filter(([n,a])=>n||a).map(([n,a,i])=>({anchor:n,heading:E(a),excerpt:E(i)}));return{record:e,title:E(e.title),alt:E(e.alt??""),endpoint:E(e.endpoint??""),description:E(e.description),intro:E((t==null?void 0:t[2])??""),sections:o}},M={index:null},ia=()=>(M.index||(M.index=fetch(Dn).then(e=>{if(!e.ok)throw new Error(String(e.status));return e.json()}).then(e=>e.map(aa)).catch(e=>{throw M.index=null,e})),M.index),Ht=e=>e.filter(Boolean).join(" ⺠"),Dt=(e,t)=>t.score-e.score||e.title.length-t.title.length,pa=(e,t)=>t===0||!/[a-z0-9]/.test(e.charAt(t-1)),k=(e,t,o)=>{if(!e.lower)return 0;if(e.lower.startsWith(t))return o[0];const n=e.lower.indexOf(t);return n===-1?0:pa(e.lower,n)?o[1]:o[2]},me=(...e)=>Math.max(0,...e),ca=(e,t,o)=>{const{record:n}=e;let a=0,i=!0;for(const p of t){const c=me(k(e.title,p,q.title),k(e.alt,p,q.alt),k(e.endpoint,p,q.endpoint),k(e.description,p,q.description),k(e.intro,p,q.intro));if(c===0){i=!1;break}a+=c}return i?(e.title.lower===o&&(a+=50),{kind:"page",href:n.href,tab:n.tab,crumb:Ht([n.tab,...n.group]),title:n.title,snippet:n.description,score:a}):null},la=(e,t)=>{const{record:o}=e,n=[];for(const a of e.sections){let i=0,p=!1,c=!0;for(const l of t){const d=me(k(a.heading,l,q.heading),k(a.excerpt,l,q.excerpt)),m=me(k(e.title,l,q.pageForSection),k(e.alt,l,q.pageForSection));d>0&&(p=!0);const u=Math.max(d,m);if(u===0){c=!1;break}i+=u}!c||!p||n.push({kind:"section",href:`${o.href}
8#${a.anchor}`,tab:o.tab,crumb:Ht([o.tab,o.group.at(-1)??"",o.title]),title:a.heading.text,snippet:a.excerpt.text,score:i})}return n.sort(Dt),n.slice(0,Fn)},Ut=e=>Array.from(new Set(e.toLowerCase().split(/\s+/).filter(Boolean))),da=(e,t)=>{const o=Ut(t);if(o.length===0)return[];const n=[],a=t.trim().toLowerCase();for(const i of e){const p=ca(i,o,a);p&&n.push(p),n.push(...la(i,o))}return n.sort(Dt).slice(0,Un)},ma=(e,t)=>{const{pathname:o}=ue(),n=r.useRef(!1);r.useEffect(()=>{e&&(n.current=!1)},[e]);const a=r.useCallback(p=>{n.current=(p.split(/[?#]/)[0]||o)!==o,t(!1)},[o,t]),i=r.useCallback(p=>{n.current&&(n.current=!1,p.preventDefault())},[]);return{leave:a,onCloseAutoFocus:i}},ua=e=>{const t=e instanceof HTMLElement?e:null;return t?t.isContentEditable||t.tagName==="INPUT"||t.tagName==="TEXTAREA"||t.tagName==="SELECT":!1},ya=(e,t,o,n,a)=>{const i=Ot();r.useEffect(()=>{const l=d=>{const m=(d.key==="k"||d.key==="K")&&(d.metaKey||d.ctrlKey),u=d.key==="/"&&!d.metaKey&&!d.ctrlKey&&!d.altKey&&!ua(d.target);!m&&!u||(d.preventDefault(),n(y=>!y))};return window.addEventListener(Ae.KEYDOWN,l),()=>window.removeEventListener(Ae.KEYDOWN,l)},[n]);const p=l=>{if(e.length===0)return;const d=e.findIndex(y=>y.href===t),u=e[((d===-1?0:d)+l+e.length)%e.length];u&&o(u.href)};return{handleKeyDown:l=>{var d;l.key==="ArrowDown"?(l.preventDefault(),p(1)):l.key==="ArrowUp"?(l.preventDefault(),p(-1)):l.key==="Home"&&e[0]?(l.preventDefault(),o(e[0].href)):l.key==="End"&&e.length>0?(l.preventDefault(),o(((d=e[e.length-1])==null?void 0:d.href)??null)):l.key==="Enter"&&t&&(l.preventDefault(),a(t),i(t)||window.location.assign(t))}}},ga=()=>{const[e,t]=r.useState(!1),[o,n]=r.useState(""),[a,i]=r.useState(null),[p,c]=r.useState(!1),[l,d]=r.useState(null),m=r.useRef(0),u=r.useCallback(()=>{const j=m.current+=1;ia().then(G=>{j===m.current&&i(G)}).catch(()=>{j===m.current&&c(!0)})},[]);r.useEffect(()=>{e&&a===null&&!p&&u()},[e,a,p,u]),r.useEffect(()=>{e||n("")},[e]);const y=r.useMemo(()=>Ut(o),[o]),g=r.useMemo(()=>a&&y.length>0?na(da(a,o)):[],[a,o,y]),h=r.useMemo(()=>g.flatMap(([,j])=>j),[g]),S=p&&a===null?"error":y.length===0?"idle":a===null?"loading":h.length===0?"empty":"results";r.useEffect(()=>{d(j=>{var G;return h.length===0?null:j&&h.some(Ft=>Ft.href===j)?j:((G=h[0])==null?void 0:G.href)??null})},[h]);const{leave:w,onCloseAutoFocus:A}=ma(e,t),{handleKeyDown:z}=ya(h,l,d,t,w);return{open:e,setOpen:t,prefetch:u,query:o,setQuery:n,tokens:y,groups:g,status:S,activeId:l,setActiveId:d,handleKeyDown:z,leave:w,onCloseAutoFocus:A}},ha=({children:e})=>{const t=ga(),{open:o,setOpen:n,prefetch:a}=t,i=r.useMemo(()=>({open:o,setOpen:n,prefetch:a}),[o,n,a]);return s.jsxs(Mt.Provider,{value:i,children:[e,s.jsx(oa,{state:t})]})},ba=({children:e})=>{const[t,o]=r.useState(null),n=r.useMemo(()=>({value:t,select:o}),[t]);return s.jsx(At.Provider,{value:n,children:e})},fa=e=>s.jsx(ba,{children:s.jsx(ha,{children:s.jsx(Hn,{...e})})}),wa="og/docs",ja=e=>`/${wa}/${L(e)}.png`,va=({id:e,title:t,description:o})=>{const n=se(e),a=H(e),i=`${W}${(a==null?void 0:a.href)??`/docs/${e}`}`,p=[{name:"Home",item:`${W}/`},{name:"Documentation",item:`${W}${Ye}`},...n?[{name:n.label,item:`${W}${n.href}`}]:[],{name:t,item:i}];return{title:`${t}${es}Docs`,description:o,ogImage:ja(e),markdownAlternate:!0,bare:!0,jsonLd:{"@type":"BreadcrumbList",itemListElement:p.map((c,l)=>({"@type":"ListItem",position:l+1,...c}))}}},xa=e=>xs(Object.entries(e).map(([t,o])=>({id:t,data:o}))),qa=404,ka=async e=>{if(!Qr(e))throw Bt(null,{status:qa});const t=L(e),{frontmatter:o,navTitles:n}=await Xr(t);return{id:t,titles:n,page:va({id:t,title:o.title,description:o.description})}},_a=e=>ts(e["*"]),Aa=({params:e,request:t})=>{const o=ks[new URL(t.url).pathname.replace(/\/+$/,"")];if(o)throw Wt(o.destination,o.status);return ka(_a(e))},Fi=e=>Aa(e),Ki=zt(function(){const{id:t,titles:o}=Gt(),n=r.useMemo(()=>xa(o),[o]),a=Jr(t),{frontmatter:i,endpointCode:p,headings:c,updates:l,body:d}=a,m=Zs(i.openapi),{prev:u,next:y}=vs(t),g=a.default;if(i.openapi&&!m)throw new Error(`docs/${t}: no "${i.openapi}" operation in openapi.json`);
8return s.jsxs(fa,{id:t,title:i.title,description:i.description,headings:m?Ds(m):c.length>0?c:l,prev:u,next:y,lookup:n,children:[m&&p&&s.jsx(dn,{endpoint:m,code:p,baseUrl:ir,authHref:"/docs/api/authentication"}),(!m||d.trim()!=="")&&s.jsx(g,{components:qo})]})});export{Fi as clientLoader,Ki as default};
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.