[{"data":1,"prerenderedAt":794},["ShallowReactive",2],{"pricing-plans":3,"content-page-\u002Fdocs\u002Fpagination":4,"api-docs-metadata":286,"i-ph:list":3,"i-ph:caret-right":3,"i-ph:copy":3,"i-ph:caret-down":3,"i-ph:twitter-logo":3,"i-ph:youtube-logo":3},null,{"id":5,"title":6,"body":7,"description":276,"extension":277,"meta":278,"navigation":281,"path":282,"seo":283,"stem":284,"__hash__":285},"all\u002Fdocs\u002Fpagination.md","Auto-pagination",{"type":8,"value":9,"toc":269},"minimark",[10,14,23,28,73,80,84,87,118,122,133,137,159,163,262,265],[11,12,6],"h1",{"id":13},"auto-pagination",[15,16,17,18,22],"p",{},"Auto-pagination turns one designed page into a ",[19,20,21],"strong",{},"multi-page PDF whose page count follows the content"," — invoices with any number of line items, catalogs, reports. You design a single page; at render time Bannx measures the content, splits it into pages, and merges them into one PDF.",[24,25,27],"h2",{"id":26},"how-it-works","How it works",[29,30,31,52,61],"ol",{},[32,33,34,35,38,39,43,44,47,48,51],"li",{},"In the editor, enable ",[19,36,37],{},"Paginate"," on the page (",[40,41,42],"code",{},"page.paginate",") and mark exactly one top-level column container as the ",[19,45,46],{},"flow region"," (",[40,49,50],{},"layer.flowRegion",").",[32,53,54,55,60],{},"Fill the flow region with content — typically a ",[56,57,59],"a",{"href":58},"\u002Fdocs\u002Fvariables","loop layer"," bound to a data collection, so rows come from your data.",[32,62,63,64,67,68,72],{},"Render with ",[40,65,66],{},"format: \"pdf\""," via the ",[56,69,71],{"href":70},"\u002Fdocs\u002Frendering","Rendering API",". On HTML-renderer templates, the server measures each item in the flow region at its natural height, packs items into as many virtual pages as needed, and renders them into one merged PDF. On Takumi templates, the PDF engine flows the content across pages natively (CSS fragmentation) — no measure pass.",[15,74,75,76,79],{},"On the HTML pipeline, everything outside the flow region (headers, footers, backgrounds) repeats on every page. On the Takumi pipeline, static layers currently appear on the first page only — prefer the HTML renderer (",[40,77,78],{},"renderType: \"html\"",") for designs whose chrome must repeat.",[24,81,83],{"id":82},"flow-region-rules","Flow region rules",[15,85,86],{},"The flow region must satisfy all of these — otherwise the render falls back to a normal single page (with a server-side warning), so a misconfigured template still produces output:",[88,89,90,97,104,110],"ul",{},[32,91,92,93,96],{},"Exactly ",[19,94,95],{},"one"," visible layer marked as flow region",[32,98,99,100,103],{},"It must be a ",[19,101,102],{},"top-level"," layer (no parent)",[32,105,106,109],{},[40,107,108],{},"flexDirection: column"," (items stack vertically; overflow extends downward)",[32,111,112,113,117],{},"It cannot itself be a loop layer (put loop layers ",[114,115,116],"em",{},"inside"," it)",[24,119,121],{"id":120},"page-number-variables","Page-number variables",[15,123,124,125,128,129,132],{},"Each generated page gets ",[40,126,127],{},"pageNumber"," and ",[40,130,131],{},"totalPages"," merged into its data context — bind them in text layers for \"Page 2 of 7\" footers.",[24,134,136],{"id":135},"limits","Limits",[88,138,139,149],{},[32,140,141,144,145,148],{},[40,142,143],{},"page.paginate.maxPages"," caps generation per page; the hard server cap is ",[19,146,147],{},"50 pages",". Content beyond the cap is dropped (logged as a warning).",[32,150,151,152,155,156,158],{},"Pagination applies to the ",[19,153,154],{},"PDF"," pipeline (",[40,157,66],{},"); PDF renders consume one credit per generated page.",[24,160,162],{"id":161},"example","Example",[164,165,170],"pre",{"className":166,"code":167,"language":168,"meta":169,"style":169},"language-bash shiki shiki-themes github-light github-dark","curl -X POST -H \"Authorization: Bearer YOUR_TOKEN\" \\\n  -H \"Content-Type: application\u002Fjson\" \\\n  -d '{\n    \"pageId\": \"INVOICE_PAGE_ID\",\n    \"format\": \"pdf\",\n    \"output\": \"binary\",\n    \"tweaks\": { \"invoiceNumber\": \"INV-2041\", \"lineItems\": [ \u002F* any number of rows *\u002F ] }\n  }' \\\n  \"https:\u002F\u002Fyour-app.bannx.app\u002Fapi\u002Frender\" -o invoice.pdf\n","bash","",[40,171,172,198,209,218,224,230,236,242,250],{"__ignoreMap":169},[173,174,177,181,185,189,192,195],"span",{"class":175,"line":176},"line",1,[173,178,180],{"class":179},"sScJk","curl",[173,182,184],{"class":183},"sj4cs"," -X",[173,186,188],{"class":187},"sZZnC"," POST",[173,190,191],{"class":183}," -H",[173,193,194],{"class":187}," \"Authorization: Bearer YOUR_TOKEN\"",[173,196,197],{"class":183}," \\\n",[173,199,201,204,207],{"class":175,"line":200},2,[173,202,203],{"class":183},"  -H",[173,205,206],{"class":187}," \"Content-Type: application\u002Fjson\"",[173,208,197],{"class":183},[173,210,212,215],{"class":175,"line":211},3,[173,213,214],{"class":183},"  -d",[173,216,217],{"class":187}," '{\n",[173,219,221],{"class":175,"line":220},4,[173,222,223],{"class":187},"    \"pageId\": \"INVOICE_PAGE_ID\",\n",[173,225,227],{"class":175,"line":226},5,[173,228,229],{"class":187},"    \"format\": \"pdf\",\n",[173,231,233],{"class":175,"line":232},6,[173,234,235],{"class":187},"    \"output\": \"binary\",\n",[173,237,239],{"class":175,"line":238},7,[173,240,241],{"class":187},"    \"tweaks\": { \"invoiceNumber\": \"INV-2041\", \"lineItems\": [ \u002F* any number of rows *\u002F ] }\n",[173,243,245,248],{"class":175,"line":244},8,[173,246,247],{"class":187},"  }'",[173,249,197],{"class":183},[173,251,253,256,259],{"class":175,"line":252},9,[173,254,255],{"class":187},"  \"https:\u002F\u002Fyour-app.bannx.app\u002Fapi\u002Frender\"",[173,257,258],{"class":183}," -o",[173,260,261],{"class":187}," invoice.pdf\n",[15,263,264],{},"A 3-item invoice comes back as one page; a 60-item invoice comes back as however many pages the items need (up to the cap) — same template, same request shape.",[266,267,268],"style",{},"html pre.shiki code .sScJk, html code.shiki .sScJk{--shiki-default:#6F42C1;--shiki-dark:#B392F0}html pre.shiki code .sj4cs, html code.shiki .sj4cs{--shiki-default:#005CC5;--shiki-dark:#79B8FF}html pre.shiki code .sZZnC, html code.shiki .sZZnC{--shiki-default:#032F62;--shiki-dark:#9ECBFF}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}",{"title":169,"searchDepth":200,"depth":200,"links":270},[271,272,273,274,275],{"id":26,"depth":200,"text":27},{"id":82,"depth":200,"text":83},{"id":120,"depth":200,"text":121},{"id":135,"depth":200,"text":136},{"id":161,"depth":200,"text":162},"Content-driven multi-page PDFs — mark one column as the flow region and long content splits into pages automatically.","md",{"layout":279,"updatedAt":280},"docs","2026-07-06",true,"\u002Fdocs\u002Fpagination",{"title":6,"description":276},"docs\u002Fpagination","vOlRdeP2Igz5TAU2hshQ-OqTp-dQZp8C28hLC8FgtC0",{"success":281,"routes":287,"total":792,"generatedAt":793,"canViewAllApiDocs":362},[288,335,347,405,462,483,504,519,535,547,559,576,604,630,649,661,672,683,692,698,716,727,742,754,767],{"path":289,"method":290,"summary":291,"description":292,"tags":293,"group":294,"requestBody":295,"responses":327,"actionName":334},"\u002Fapi\u002Fcode-to-image","POST","Render code snippets as images","Render source code with syntax highlighting to PNG, WebP, or JPEG. No API token required.",[294],"Rendering",{"content":296},{"application\u002Fjson":297},{"schema":298},{"type":299,"required":300,"properties":301},"object",[40],{"code":302,"lang":305,"theme":307,"format":309,"width":315,"height":318,"quality":320,"showLineNumbers":322,"style":325},{"type":303,"description":304},"string","Source code to render",{"type":303,"description":306},"Language for highlighting (e.g. js, ts). Default: js",{"type":303,"description":308},"Shiki theme. Default: github-dark",{"type":303,"enum":310,"description":314},[311,312,313],"png","webp","jpeg","Output format. Default: png (lossless)",{"type":316,"description":317},"number","Optional width",{"type":316,"description":319},"Optional height",{"type":316,"description":321},"Optional quality",{"type":323,"description":324},"boolean","Show 1-based line numbers in a left gutter. Default: false",{"type":299,"description":326},"Optional style options",{"200":328,"400":330,"500":332},{"description":329},"Image (data URL or binary depending on format)",{"description":331},"Missing or invalid code",{"description":333},"Failed to generate code image","codeToImage",{"path":336,"method":290,"summary":337,"description":338,"tags":339,"group":340,"responses":341,"actionName":346},"\u002Fapi\u002Fdemo-token","Create a demo token","Mint a short-lived, IP-throttled demo token (stored only in Redis, ~1h TTL) that can render PUBLIC templates with tweaks — no account or API key required. Each client IP can mint up to 5 tokens per rolling hour. Use the token as `Authorization: Bearer demo_…` or `?demo=demo_…` against GET \u002Fapi\u002Frender\u002F:pageId.",[340],"Authentication",{"200":342,"429":344},{"description":343},"Demo token created",{"description":345},"Per-IP demo token quota reached","createDemoToken",{"path":348,"method":349,"summary":350,"description":351,"tags":352,"group":294,"parameters":353,"responses":397,"actionName":404},"\u002Fapi\u002Frender\u002F:pageId","GET","Render a page by ID (GET)","Render by page ID with query parameters. Supports draft (database), publish cache, png\u002Fsvg\u002Fwebp\u002Fpdf, JSON or binary responses, tweaks, and brandTweaks — aligned with POST \u002Fapi\u002Frender. Auth depends on template requireGetRenderToken (Bearer or gt query).",[294],[354,359,369,373,380,384,388,392],{"in":355,"name":356,"required":281,"schema":357,"description":358},"path","pageId",{"type":303},"Page ID to render",{"in":360,"name":361,"required":362,"schema":363,"description":368},"query","format",false,{"type":303,"enum":364},[311,365,312,366,367],"svg","pdf","pptx","Output format. Default: png",{"in":360,"name":370,"required":362,"schema":371,"description":372},"draft",{"type":323},"If true, load from database instead of publish cache. Default: false",{"in":360,"name":374,"required":362,"schema":375,"description":379},"output",{"type":303,"enum":376},[377,378],"json","binary","Response shape: omit or json for metadata + file URL; binary for raw bytes",{"in":360,"name":381,"required":362,"schema":382,"description":383},"pageIds",{"type":303},"Comma-separated page IDs for merged PDF (format=pdf only)",{"in":360,"name":385,"required":362,"schema":386,"description":387},"gt",{"type":303},"GET render secret when Bearer is not used",{"in":360,"name":389,"required":362,"schema":390,"description":391},"scale",{"type":316,"minimum":176,"maximum":220},"Output resolution multiplier for png\u002Fwebp. Overrides the template's renderScale. Default 2.",{"in":360,"name":393,"required":362,"schema":394,"description":396},"quality",{"type":316,"minimum":176,"maximum":395},100,"WebP encode quality (webp only). Overrides the template's webpQuality. Default 90.",{"200":398,"401":400,"404":402},{"description":399},"Binary image\u002FPDF or application\u002Fjson with file metadata",{"description":401},"Missing or invalid API token",{"description":403},"Page or template not found","renderPage",{"path":406,"method":290,"summary":407,"description":408,"tags":409,"group":294,"requestBody":410,"responses":454,"actionName":461},"\u002Fapi\u002Frender\u002Findex","Render by page ID","Render a page by ID from the publish cache, or from the database when draft: true. Requires API token. Does not accept full inline page payloads. Optional body field renderType (satori, takumi, html) overrides the template's rendererType. Use format pdf for the HTML + Chrome PDF pipeline (always uses the HTML renderer). For multi-page PDFs, send pageIds and optional tweaksPerPage (same length). Default response is application\u002Fjson with timings and a URL to the uploaded render; set output to binary (or binary: true) to return raw bytes.",[294],{"content":411},{"application\u002Fjson":412},{"schema":413},{"type":299,"description":414,"properties":415},"For raster formats use pageId. For PDF use pageId (single) or pageIds (merged in order).",{"pageId":416,"pageIds":418,"tweaksPerPage":422,"templateId":425,"draft":427,"format":429,"tweaks":433,"brandTweaks":435,"emojiType":437,"output":439,"binary":444,"renderType":446,"scale":451,"quality":453},{"type":303,"description":417},"Page ID to render (required for png\u002Fsvg\u002Fwebp; optional for pdf when pageIds is set)",{"type":419,"items":420,"description":421},"array",{"type":303},"Multiple pages for merged PDF (format pdf only)",{"type":419,"items":423,"description":424},{"type":299},"Per-page tweaks aligned with pageIds when rendering PDF",{"type":303,"description":426},"Optional; when set, validated against the page's template (parallel fetch)",{"type":323,"description":428},"If true, load page and template from database instead of publish cache. Default: false",{"type":303,"enum":430,"description":432},[311,365,312,366,367,431],"html5","Output format. Default: png. pdf and pptx use HTML + Chrome; pptx builds an editable slide per page. html5 returns a self-contained HTML5 display-ad ZIP (Google Ads) for a single page.",{"type":299,"description":434},"Variable overrides; keys may use dot paths for nested values. For Variable[] sources, use \"varId.nested.path\" when patching object values.",{"type":299,"description":436},"Brand token overrides by dot path (e.g. logos.icon or brand.logos.icon). Merged into resolved brand tokens before render.",{"type":303,"description":438},"e.g. twemoji, openmoji. Default from template",{"type":303,"enum":440,"description":443},[377,378,441,442],"image","raw","Response shape: omit or json for application\u002Fjson (default); binary, image, or raw for raw body",{"type":323,"description":445},"If true, same as output binary (raw body)",{"type":303,"enum":447,"description":450},[448,449],"takumi","html","Override rendering engine (takumi or html). Ignored when format is pdf (HTML pipeline). Legacy value 'satori' is accepted and treated as 'takumi'.",{"type":316,"minimum":176,"maximum":220,"description":452},"Output resolution multiplier for png\u002Fwebp (logical layout unchanged, pixels multiplied). Overrides the template's renderScale. Default 2.",{"type":316,"minimum":176,"maximum":395,"description":396},{"200":455,"400":457,"401":459,"404":460},{"description":456},"Default: application\u002Fjson with render metadata and file.url. With output binary: image\u002Fpng, image\u002Fsvg+xml, image\u002Fwebp, or application\u002Fpdf.",{"description":458},"Invalid body (e.g. missing pageId)",{"description":401},{"description":403},"render",{"path":463,"method":349,"summary":464,"description":465,"tags":466,"parameters":467,"responses":477,"actionName":482},"\u002Fapi\u002Frenders\u002Flogs","List render logs","Render request logs for the current space, optionally narrowed to one template. Session-authenticated (dashboard login) — not callable with an API key.",[294],[468,471,474],{"in":360,"name":469,"required":362,"description":470},"templateId","Only logs for this template's pages",{"in":360,"name":472,"required":362,"description":473},"page","Page number",{"in":360,"name":475,"required":362,"description":476},"perPage","Items per page (default 50)",{"200":478,"401":480},{"description":479},"JSON { list, count, pagesCount } of render log entries",{"description":481},"Not logged in","listRenderLogs",{"path":484,"method":349,"summary":485,"description":486,"tags":487,"parameters":489,"responses":500,"actionName":503},"\u002Fapi\u002Ftemplates\u002Fpublic","List public templates","List published community\u002Fgallery templates with their cached pages. No authentication required.",[488],"Templates",[490,493,496,498],{"in":360,"name":491,"required":362,"description":492},"search","Search name + description (max 80 chars)",{"in":360,"name":494,"required":362,"description":495},"category","Category filter, or \"featured\" for the curated list",{"in":360,"name":472,"required":362,"description":497},"Page number (default 1)",{"in":360,"name":475,"required":362,"description":499},"Items per page (max 100)",{"200":501},{"description":502},"JSON { list, count, pagesCount } — templates include their published pages","listPublicTemplates",{"path":505,"method":349,"summary":506,"description":507,"tags":508,"parameters":509,"responses":513,"actionName":518},"\u002Fapi\u002Ftemplates\u002Fpublic\u002F:id","Get a public template","Fetch one published template (with its pages) by ID. Only templates with publicOn are returned; private IDs 404. No authentication required.",[488],[510],{"in":355,"name":511,"required":281,"description":512},"id","Template ID",{"200":514,"404":516},{"description":515},"JSON { doc } — the template including published pages",{"description":517},"Template not found or not public","getPublicTemplateDoc",{"path":520,"method":521,"summary":522,"description":523,"tags":524,"parameters":526,"responses":529,"actionName":534},"\u002Fapi\u002Fv1\u002Fbrands\u002F:id","DELETE","Delete a brand","Soft-delete a brand by ID. Session-authenticated (dashboard login; owner\u002Fadmin\u002Feditor).",[525],"Brands",[527],{"in":355,"name":511,"required":281,"description":528},"Brand ID",{"200":530,"404":532},{"description":531},"JSON { success: true, id }",{"description":533},"Brand not found in your space","deleteBrand",{"path":520,"method":349,"summary":536,"description":537,"tags":538,"parameters":539,"responses":541,"actionName":546},"Get a brand","Fetch one brand by ID. Public brands (publicOn set) need no auth; private brands require a dashboard session in the owning space. For API-key access use the MCP server (get_brand).",[525],[540],{"in":355,"name":511,"required":281,"description":528},{"200":542,"404":544},{"description":543},"JSON { doc } — the brand with its token sets",{"description":545},"Not found or not accessible","getBrand",{"path":520,"method":548,"summary":549,"description":550,"tags":551,"parameters":552,"responses":554,"actionName":558},"PUT","Update a brand","Update a brand by ID (same fields as create, all optional). Session-authenticated (dashboard login; owner\u002Fadmin\u002Feditor). For API-key access use the MCP server (update_brand).",[525],[553],{"in":355,"name":511,"required":281,"description":528},{"200":555,"404":557},{"description":556},"JSON { doc } — the updated brand",{"description":533},"updateBrand",{"path":560,"method":349,"summary":561,"description":562,"tags":563,"parameters":564,"responses":570,"actionName":575},"\u002Fapi\u002Fv1\u002Fbrands\u002Findex","List brands","List brands in the current space. Session-authenticated (dashboard login); pass ?public=true to list public brands anonymously. For API-key access use the MCP server (list_brands).",[525],[565,566,567],{"in":360,"name":472,"required":362,"description":497},{"in":360,"name":475,"required":362,"description":476},{"in":360,"name":568,"required":362,"description":569},"public","\"true\" to list public brands without auth",{"200":571,"401":573},{"description":572},"JSON { list, count, pagesCount } of brands",{"description":574},"Not logged in (when public is not set)","listBrands",{"path":560,"method":290,"summary":577,"description":578,"tags":579,"requestBody":580,"responses":599,"actionName":603},"Create a brand","Create a brand in the current space. Session-authenticated (dashboard login; owner\u002Fadmin\u002Feditor). External image URLs inside tokens are re-uploaded to your space. For API-key access use the MCP server (create_brand).",[525],{"content":581},{"application\u002Fjson":582},{"schema":583},{"type":299,"required":584,"properties":586},[585],"name",{"name":587,"draftTokens":589,"liveTokens":591,"tokens":593,"variants":595,"extra":597},{"type":303,"description":588},"Brand name",{"type":299,"description":590},"Token kit being edited (logos, colors, typography, …)",{"type":299,"description":592},"Token kit used by published renders",{"type":299,"description":594},"Resolved token set",{"type":299,"description":596},"Named variations of the kit",{"type":299,"description":598},"Free-form extras",{"200":600,"401":602},{"description":601},"JSON { doc } — the created brand",{"description":481},"createBrand",{"path":605,"method":349,"summary":606,"description":607,"tags":608,"group":609,"parameters":610,"responses":623,"actionName":629},"\u002Fapi\u002Fv1\u002Fpublic\u002Fcontent\u002F:collection\u002F:slug","Get an entry","Read a single PUBLISHED entry by slug. Authenticate with a content.read API key (Authorization: Bearer …). The slug is matched against the collection's configured preview.slugField (defaults to \"slug\"). Only liveData is returned; use ?depth= to resolve references and ?variants= for personalization.",[609],"Content",[611,614,617,620],{"in":355,"name":612,"required":281,"description":613},"collection","The collection's API name",{"in":355,"name":615,"required":281,"description":616},"slug","The entry slug",{"in":360,"name":618,"required":362,"description":619},"depth","Resolve reference fields to this depth (default 0)",{"in":360,"name":621,"required":362,"description":622},"variants","Comma-separated variant ids; returns personalization-resolved values",{"200":624,"401":626,"404":627},{"description":625},"JSON { doc } — the published entry",{"description":401},{"description":628},"Collection or entry not found","publicGetContentBySlug",{"path":631,"method":349,"summary":632,"description":633,"tags":634,"group":609,"parameters":635,"responses":642,"actionName":648},"\u002Fapi\u002Fv1\u002Fpublic\u002Fcontent\u002F:collection\u002Findex","List entries","List PUBLISHED entries in a collection. Authenticate with a content.read API key (Authorization: Bearer …). Only liveData is returned — never drafts. Values under `data` are keyed by field API name. Supports pagination, reference resolution (?depth=), and personalization (?variants=).",[609],[636,637,638,640,641],{"in":355,"name":612,"required":281,"description":613},{"in":360,"name":472,"required":362,"description":497},{"in":360,"name":475,"required":362,"description":639},"Items per page (default 20)",{"in":360,"name":618,"required":362,"description":619},{"in":360,"name":621,"required":362,"description":622},{"200":643,"401":645,"404":646},{"description":644},"JSON { list, count, pagesCount } of published entries",{"description":401},{"description":647},"Collection not found","publicListContent",{"path":650,"method":521,"summary":651,"description":652,"tags":653,"responses":655,"actionName":660},"\u002Fapi\u002Fv1\u002Fshaders\u002F:id","Delete a shader","Permanently remove a shader from the current space.",[654],"Shaders",{"200":656,"404":658},{"description":657},"JSON { deleted: true }",{"description":659},"No such shader","deleteShader",{"path":650,"method":349,"summary":662,"description":663,"tags":664,"responses":665,"actionName":671},"Get a shader","Fetch one shader including its vetted `program` — the only source a client should compile. Status is enforced here on every request, which is what makes revoking a working kill switch: a quarantined or revoked shader returns 410 and stops loading everywhere immediately.",[654],{"200":666,"404":668,"410":669},{"description":667},"JSON { doc }",{"description":659},{"description":670},"Shader is quarantined or revoked","getShader",{"path":650,"method":548,"summary":673,"description":674,"tags":675,"responses":676,"actionName":682},"Update a shader","Editing source or the manifest re-runs the full vetting pipeline and produces a new content hash — an existing approval is never inherited by code that was not vetted. A rejected edit returns 422 and leaves the stored shader untouched.",[654],{"200":677,"404":679,"422":680},{"description":678},"JSON { doc, report }",{"description":659},{"description":681},"Rejected by vetting; the stored shader is unchanged","updateShader",{"path":684,"method":290,"summary":685,"description":686,"tags":687,"responses":688,"actionName":691},"\u002Fapi\u002Fv1\u002Fshaders\u002F:id\u002Fstatus","Set a shader status (kill switch)","Revoke, quarantine, or restore a shader. Because GET enforces status on every fetch, revoking stops the shader loading everywhere at once — there is no client deny-list to push and no cache to wait out. Restoring also clears the accumulated watchdog trips.",[654],{"200":689,"404":690},{"description":667},{"description":659},"setShaderStatus",{"path":693,"method":290,"summary":694,"description":695,"tags":696,"actionName":697},"\u002Fapi\u002Fv1\u002Fshaders\u002F:id\u002Ftelemetry","Report a client watchdog trip","Called by a viewer whose frame watchdog disabled this shader. Enough independent trips ",[654],"reportShaderTrip",{"path":699,"method":349,"summary":700,"description":701,"tags":702,"parameters":703,"responses":711,"actionName":715},"\u002Fapi\u002Fv1\u002Fshaders\u002Findex","List shaders","List the current space's shaders. Pass ?public=true to list published shaders anonymously. Program source is omitted from the listing — fetch a single shader to obtain it.",[654],[704,705,706,709],{"in":360,"name":472,"required":362,"description":497},{"in":360,"name":475,"required":362,"description":476},{"in":360,"name":707,"required":362,"description":708},"status","approved | quarantined | revoked",{"in":360,"name":568,"required":362,"description":710},"\"true\" to list public shaders without auth",{"200":712,"401":714},{"description":713},"JSON { list, count, pagesCount }",{"description":574},"listShaders",{"path":699,"method":290,"summary":717,"description":718,"tags":719,"responses":720,"actionName":726},"Create a shader","Submit a GLSL fragment body plus a typed input manifest. The shader is vetted before anything is stored: byte caps, a static policy scan, loop normalisation to constant bounds, a cost model, then a real compile and fuzz render inside a sandboxed child process. A rejected submission returns 422 with the stage-by-stage report and is not saved.",[654],{"200":721,"401":723,"422":724},{"description":722},"JSON { doc, report } — the stored shader and its vetting report",{"description":481},{"description":725},"Rejected by vetting; data.report explains which stage refused","createShader",{"path":728,"method":521,"summary":729,"description":730,"tags":731,"parameters":733,"responses":736,"actionName":741},"\u002Fapi\u002Fv1\u002Ftokens\u002Fapi-keys\u002F:id","Delete an API key","Revoke an API key immediately. Session-authenticated (dashboard login; owner\u002Fadmin).",[732],"Tokens",[734],{"in":355,"name":511,"required":281,"description":735},"Token ID",{"200":737,"404":739},{"description":738},"JSON { message } confirmation",{"description":740},"Token not found in your space","deleteApiKey",{"path":728,"method":743,"summary":744,"description":745,"tags":746,"parameters":747,"responses":749,"actionName":753},"PATCH","Update an API key","Rename, change expiry, or adjust scopes of an API key. Session-authenticated (dashboard login; owner\u002Fadmin).",[732],[748],{"in":355,"name":511,"required":281,"description":735},{"200":750,"404":752},{"description":751},"JSON { doc } — the updated key",{"description":740},"updateApiKey",{"path":755,"method":349,"summary":756,"description":757,"tags":758,"parameters":759,"responses":762,"actionName":766},"\u002Fapi\u002Fv1\u002Ftokens\u002Fapi-keys\u002Findex","List API keys","List API keys for the current space. Session-authenticated (dashboard login; owner\u002Fadmin).",[732],[760,761],{"in":360,"name":472,"required":362,"description":497},{"in":360,"name":475,"required":362,"description":639},{"200":763,"401":765},{"description":764},"JSON { list, count, pagesCount } of API keys",{"description":481},"listApiKeys",{"path":755,"method":290,"summary":768,"description":769,"tags":770,"requestBody":771,"responses":787,"actionName":791},"Create an API key","Create a space-scoped API key. The plain token is returned once, on creation. Session-authenticated (dashboard login; owner\u002Fadmin).",[732],{"content":772},{"application\u002Fjson":773},{"schema":774},{"type":299,"required":775,"properties":776},[585],{"name":777,"expiresAt":779,"neverExpires":781,"shortToken":783,"scopes":785},{"type":303,"description":778},"Key name (max 200 chars)",{"type":303,"description":780},"ISO datetime expiry",{"type":323,"description":782},"No expiry. Default: false",{"type":323,"description":784},"Shorter ~96-bit token instead of ~256-bit. Default: false",{"type":299,"description":786},"Optional restrictions: { mcpTools?: string[], apiEndpoints?: string[] }. Omit a list to allow all; [] denies all.",{"200":788,"401":790},{"description":789},"JSON { doc } including the plain token (shown only once)",{"description":481},"createApiKey",25,"2026-08-19T19:21:11.342Z",1787167272953]