[{"data":1,"prerenderedAt":1394},["ShallowReactive",2],{"pricing-plans":3,"content-page-\u002Fdocs\u002Fwebhooks":4,"api-docs-metadata":894,"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":885,"extension":886,"meta":887,"navigation":509,"path":890,"seo":891,"stem":892,"__hash__":893},"all\u002Fdocs\u002Fwebhooks.md","Webhooks",{"type":8,"value":9,"toc":874},"minimark",[10,14,28,35,39,42,208,212,218,342,374,379,465,469,483,678,681,685,702,706,733,737,744,783,794,806,813,817,870],[11,12,6],"h1",{"id":13},"webhooks",[15,16,17,18,22,23,27],"p",{},"Webhooks let an external system react to things that happen in your space. Each webhook subscribes to one or more ",[19,20,21],"strong",{},"events"," (per action, grouped by module) and receives an HTTP ",[24,25,26],"code",{},"POST"," whenever a matching event fires.",[15,29,30,31,34],{},"Manage them in ",[19,32,33],{},"Settings → Developers → Webhooks",".",[36,37,38],"h2",{"id":21},"Events",[15,40,41],{},"Events are grouped by module, the same way permissions are grouped on the roles page. Tick the exact actions you care about.",[43,44,45,61],"table",{},[46,47,48],"thead",{},[49,50,51,55,58],"tr",{},[52,53,54],"th",{},"Module",[52,56,57],{},"Event key",[52,59,60],{},"Fires when",[62,63,64,86,99,111,123,136,148,160,172,184,196],"tbody",{},[49,65,66,70,75],{},[67,68,69],"td",{},"Rendering",[67,71,72],{},[24,73,74],{},"render.completed",[67,76,77,78,81,82,85],{},"A page finishes rendering (",[24,79,80],{},"POST \u002Fapi\u002Frender"," or ",[24,83,84],{},"GET \u002Fapi\u002Frender\u002F:pageId",").",[49,87,88,91,96],{},[67,89,90],{},"Brands",[67,92,93],{},[24,94,95],{},"brand.created",[67,97,98],{},"A brand is created.",[49,100,101,103,108],{},[67,102,90],{},[67,104,105],{},[24,106,107],{},"brand.updated",[67,109,110],{},"A brand's tokens or details are updated.",[49,112,113,115,120],{},[67,114,90],{},[67,116,117],{},[24,118,119],{},"brand.deleted",[67,121,122],{},"A brand is deleted.",[49,124,125,128,133],{},[67,126,127],{},"Content",[67,129,130],{},[24,131,132],{},"entry.created",[67,134,135],{},"A content entry is created in a collection.",[49,137,138,140,145],{},[67,139,127],{},[67,141,142],{},[24,143,144],{},"entry.updated",[67,146,147],{},"A content entry is updated.",[49,149,150,152,157],{},[67,151,127],{},[67,153,154],{},[24,155,156],{},"entry.published",[67,158,159],{},"A content entry is published.",[49,161,162,164,169],{},[67,163,127],{},[67,165,166],{},[24,167,168],{},"entry.deleted",[67,170,171],{},"A content entry is deleted.",[49,173,174,176,181],{},[67,175,127],{},[67,177,178],{},[24,179,180],{},"entryType.created",[67,182,183],{},"A content type (collection) is created.",[49,185,186,188,193],{},[67,187,127],{},[67,189,190],{},[24,191,192],{},"entryType.updated",[67,194,195],{},"A content type's fields or settings are updated.",[49,197,198,200,205],{},[67,199,127],{},[67,201,202],{},[24,203,204],{},"entryType.deleted",[67,206,207],{},"A content type is deleted.",[36,209,211],{"id":210},"delivery-payload","Delivery payload",[15,213,214,215,217],{},"Every delivery is a ",[24,216,26],{}," with a JSON body:",[219,220,225],"pre",{"className":221,"code":222,"language":223,"meta":224,"style":224},"language-json shiki shiki-themes github-light github-dark","{\n  \"id\": \"b7c1e0f2-…\",          \u002F\u002F unique per delivery\n  \"event\": \"brand.updated\",     \u002F\u002F the event key\n  \"timestamp\": \"2026-07-08T10:00:00.000Z\",\n  \"spaceId\": \"665f…\",\n  \"data\": { \"doc\": { \"_id\": \"…\", \"name\": \"…\" } }\n}\n","json","",[24,226,227,236,257,274,288,301,336],{"__ignoreMap":224},[228,229,232],"span",{"class":230,"line":231},"line",1,[228,233,235],{"class":234},"sVt8B","{\n",[228,237,239,243,246,250,253],{"class":230,"line":238},2,[228,240,242],{"class":241},"sj4cs","  \"id\"",[228,244,245],{"class":234},": ",[228,247,249],{"class":248},"sZZnC","\"b7c1e0f2-…\"",[228,251,252],{"class":234},",          ",[228,254,256],{"class":255},"sJ8bj","\u002F\u002F unique per delivery\n",[228,258,260,263,265,268,271],{"class":230,"line":259},3,[228,261,262],{"class":241},"  \"event\"",[228,264,245],{"class":234},[228,266,267],{"class":248},"\"brand.updated\"",[228,269,270],{"class":234},",     ",[228,272,273],{"class":255},"\u002F\u002F the event key\n",[228,275,277,280,282,285],{"class":230,"line":276},4,[228,278,279],{"class":241},"  \"timestamp\"",[228,281,245],{"class":234},[228,283,284],{"class":248},"\"2026-07-08T10:00:00.000Z\"",[228,286,287],{"class":234},",\n",[228,289,291,294,296,299],{"class":230,"line":290},5,[228,292,293],{"class":241},"  \"spaceId\"",[228,295,245],{"class":234},[228,297,298],{"class":248},"\"665f…\"",[228,300,287],{"class":234},[228,302,304,307,310,313,315,318,320,323,326,329,331,333],{"class":230,"line":303},6,[228,305,306],{"class":241},"  \"data\"",[228,308,309],{"class":234},": { ",[228,311,312],{"class":241},"\"doc\"",[228,314,309],{"class":234},[228,316,317],{"class":241},"\"_id\"",[228,319,245],{"class":234},[228,321,322],{"class":248},"\"…\"",[228,324,325],{"class":234},", ",[228,327,328],{"class":241},"\"name\"",[228,330,245],{"class":234},[228,332,322],{"class":248},[228,334,335],{"class":234}," } }\n",[228,337,339],{"class":230,"line":338},7,[228,340,341],{"class":234},"}\n",[15,343,344,345,348,349,352,353,325,356,325,359,325,362,325,365,325,368,371,372,34],{},"The ",[24,346,347],{},"data"," shape depends on the event — the affected document for create\u002Fupdate, an ",[24,350,351],{},"{ id }"," for delete, and render metadata (",[24,354,355],{},"pageId",[24,357,358],{},"format",[24,360,361],{},"width",[24,363,364],{},"height",[24,366,367],{},"renderMs",[24,369,370],{},"file",", …) for ",[24,373,74],{},[375,376,378],"h3",{"id":377},"headers-we-set","Headers we set",[43,380,381,391],{},[46,382,383],{},[49,384,385,388],{},[52,386,387],{},"Header",[52,389,390],{},"Description",[62,392,393,406,416,428,442,452],{},[49,394,395,400],{},[67,396,397],{},[24,398,399],{},"Content-Type",[67,401,402,403,34],{},"Always ",[24,404,405],{},"application\u002Fjson",[49,407,408,413],{},[67,409,410],{},[24,411,412],{},"X-Webhook-Id",[67,414,415],{},"The webhook's id.",[49,417,418,423],{},[67,419,420],{},[24,421,422],{},"X-Webhook-Event",[67,424,425,426,85],{},"The event key (e.g. ",[24,427,107],{},[49,429,430,435],{},[67,431,432],{},[24,433,434],{},"X-Webhook-Delivery",[67,436,437,438,441],{},"The unique delivery id (matches ",[24,439,440],{},"id"," in the body).",[49,443,444,449],{},[67,445,446],{},[24,447,448],{},"X-Webhook-Timestamp",[67,450,451],{},"ISO timestamp the event was emitted.",[49,453,454,459],{},[67,455,456],{},[24,457,458],{},"X-Webhook-Signature",[67,460,461,464],{},[24,462,463],{},"sha256=\u003Chex>"," HMAC of the raw body — only when a secret is set.",[36,466,468],{"id":467},"verifying-the-signature","Verifying the signature",[15,470,471,472,475,476,479,480,482],{},"Set a ",[19,473,474],{},"Secret"," on the webhook and every delivery is signed. Recompute the HMAC over the ",[19,477,478],{},"raw request body"," with your secret and compare it (constant-time) to the ",[24,481,458],{}," header.",[219,484,488],{"className":485,"code":486,"language":487,"meta":224,"style":224},"language-ts shiki shiki-themes github-light github-dark","import { createHmac, timingSafeEqual } from 'node:crypto'\n\nfunction verify(rawBody: string, header: string, secret: string): boolean {\n  const expected = 'sha256=' + createHmac('sha256', secret).update(rawBody, 'utf8').digest('hex')\n  const a = Buffer.from(header)\n  const b = Buffer.from(expected)\n  return a.length === b.length && timingSafeEqual(a, b)\n}\n","ts",[24,489,490,505,511,562,612,629,645,673],{"__ignoreMap":224},[228,491,492,496,499,502],{"class":230,"line":231},[228,493,495],{"class":494},"szBVR","import",[228,497,498],{"class":234}," { createHmac, timingSafeEqual } ",[228,500,501],{"class":494},"from",[228,503,504],{"class":248}," 'node:crypto'\n",[228,506,507],{"class":230,"line":238},[228,508,510],{"emptyLinePlaceholder":509},true,"\n",[228,512,513,516,520,523,527,530,533,535,538,540,542,544,547,549,551,554,556,559],{"class":230,"line":259},[228,514,515],{"class":494},"function",[228,517,519],{"class":518},"sScJk"," verify",[228,521,522],{"class":234},"(",[228,524,526],{"class":525},"s4XuR","rawBody",[228,528,529],{"class":494},":",[228,531,532],{"class":241}," string",[228,534,325],{"class":234},[228,536,537],{"class":525},"header",[228,539,529],{"class":494},[228,541,532],{"class":241},[228,543,325],{"class":234},[228,545,546],{"class":525},"secret",[228,548,529],{"class":494},[228,550,532],{"class":241},[228,552,553],{"class":234},")",[228,555,529],{"class":494},[228,557,558],{"class":241}," boolean",[228,560,561],{"class":234}," {\n",[228,563,564,567,570,573,576,579,582,584,587,590,593,596,599,601,604,606,609],{"class":230,"line":276},[228,565,566],{"class":494},"  const",[228,568,569],{"class":241}," expected",[228,571,572],{"class":494}," =",[228,574,575],{"class":248}," 'sha256='",[228,577,578],{"class":494}," +",[228,580,581],{"class":518}," createHmac",[228,583,522],{"class":234},[228,585,586],{"class":248},"'sha256'",[228,588,589],{"class":234},", secret).",[228,591,592],{"class":518},"update",[228,594,595],{"class":234},"(rawBody, ",[228,597,598],{"class":248},"'utf8'",[228,600,85],{"class":234},[228,602,603],{"class":518},"digest",[228,605,522],{"class":234},[228,607,608],{"class":248},"'hex'",[228,610,611],{"class":234},")\n",[228,613,614,616,619,621,624,626],{"class":230,"line":290},[228,615,566],{"class":494},[228,617,618],{"class":241}," a",[228,620,572],{"class":494},[228,622,623],{"class":234}," Buffer.",[228,625,501],{"class":518},[228,627,628],{"class":234},"(header)\n",[228,630,631,633,636,638,640,642],{"class":230,"line":303},[228,632,566],{"class":494},[228,634,635],{"class":241}," b",[228,637,572],{"class":494},[228,639,623],{"class":234},[228,641,501],{"class":518},[228,643,644],{"class":234},"(expected)\n",[228,646,647,650,653,656,659,662,664,667,670],{"class":230,"line":338},[228,648,649],{"class":494},"  return",[228,651,652],{"class":234}," a.",[228,654,655],{"class":241},"length",[228,657,658],{"class":494}," ===",[228,660,661],{"class":234}," b.",[228,663,655],{"class":241},[228,665,666],{"class":494}," &&",[228,668,669],{"class":518}," timingSafeEqual",[228,671,672],{"class":234},"(a, b)\n",[228,674,676],{"class":230,"line":675},8,[228,677,341],{"class":234},[15,679,680],{},"Reject any request whose signature does not match.",[36,682,684],{"id":683},"custom-headers","Custom headers",[15,686,687,688,691,692,325,694,697,698,701],{},"Add any number of ",[19,689,690],{},"custom headers"," to a webhook — for example a bearer token or a shared secret your receiver checks, or a routing hint. They are sent on every delivery. Reserved headers (",[24,693,399],{},[24,695,696],{},"User-Agent",", and the ",[24,699,700],{},"X-Webhook-*"," headers above) cannot be overridden.",[36,703,705],{"id":704},"delivery-behaviour","Delivery behaviour",[707,708,709,717,723],"ul",{},[710,711,712,713,716],"li",{},"Deliveries are ",[19,714,715],{},"best-effort and fire-and-forget",": a failing or slow receiver never fails the render\u002Fsave that triggered it.",[710,718,719,720,34],{},"Each request times out after ",[19,721,722],{},"10 seconds",[710,724,725,728,729,732],{},[19,726,727],{},"Only public URLs are allowed."," The Post URL must be a public ",[24,730,731],{},"https"," address (SSRF protection): private, loopback, link-local, and cloud-metadata targets are rejected at save time and re-checked at delivery time, and redirects are not followed.",[36,734,736],{"id":735},"delivery-history-resend","Delivery history & resend",[15,738,739,740,743],{},"Every attempt is logged. Open a webhook's ",[19,741,742],{},"history"," (the clock icon in Settings → Developers) to see its recent deliveries with:",[707,745,746,763,773],{},[710,747,748,751,752,325,755,758,759,762],{},[19,749,750],{},"Status"," — ",[24,753,754],{},"success",[24,756,757],{},"failed",", or ",[24,760,761],{},"blocked"," (rejected by the URL guard).",[710,764,765,768,769,772],{},[19,766,767],{},"Response code"," returned by your endpoint, and the ",[19,770,771],{},"duration"," of the request.",[710,774,775,778,779,782],{},[19,776,777],{},"When"," it fired, and the ",[19,780,781],{},"error"," message on failures (hover the timestamp).",[15,784,785,786,789,790,793],{},"Use ",[19,787,788],{},"Resend"," to replay a past delivery — it sends the same event and data again with a fresh delivery id and signature, so you can retry after fixing your endpoint. Delivery records are retained for ",[19,791,792],{},"3 months",", then removed automatically. Deleting a webhook also removes its history.",[707,795,796,803],{},[710,797,798,799,802],{},"Only ",[19,800,801],{},"enabled"," webhooks whose triggers include the event are delivered to.",[710,804,805],{},"Deliveries run out of the request's critical path, so the API response is not delayed.",[15,807,808,809,812],{},"Your endpoint should respond quickly with a ",[24,810,811],{},"2xx"," and do any heavy work asynchronously.",[36,814,816],{"id":815},"summary","Summary",[43,818,819,828],{},[46,820,821],{},[49,822,823,826],{},[52,824,825],{},"Aspect",[52,827,390],{},[62,829,830,838,846,854,862],{},[49,831,832,835],{},[67,833,834],{},"Direction",[67,836,837],{},"Outbound — you supply the URL.",[49,839,840,843],{},[67,841,842],{},"Trigger",[67,844,845],{},"Any subscribed event in your space.",[49,847,848,851],{},[67,849,850],{},"Auth",[67,852,853],{},"HMAC-SHA256 signature (optional secret) + optional custom headers.",[49,855,856,859],{},[67,857,858],{},"Retries",[67,860,861],{},"None yet; treat delivery as at-most-once.",[49,863,864,867],{},[67,865,866],{},"Impact on API",[67,868,869],{},"None; delivery is deferred and best-effort.",[871,872,873],"style",{},"html pre.shiki code .sVt8B, html code.shiki .sVt8B{--shiki-default:#24292E;--shiki-dark:#E1E4E8}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 pre.shiki code .sJ8bj, html code.shiki .sJ8bj{--shiki-default:#6A737D;--shiki-dark:#6A737D}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);}html pre.shiki code .szBVR, html code.shiki .szBVR{--shiki-default:#D73A49;--shiki-dark:#F97583}html pre.shiki code .sScJk, html code.shiki .sScJk{--shiki-default:#6F42C1;--shiki-dark:#B392F0}html pre.shiki code .s4XuR, html code.shiki .s4XuR{--shiki-default:#E36209;--shiki-dark:#FFAB70}",{"title":224,"searchDepth":238,"depth":238,"links":875},[876,877,880,881,882,883,884],{"id":21,"depth":238,"text":38},{"id":210,"depth":238,"text":211,"children":878},[879],{"id":377,"depth":259,"text":378},{"id":467,"depth":238,"text":468},{"id":683,"depth":238,"text":684},{"id":704,"depth":238,"text":705},{"id":735,"depth":238,"text":736},{"id":815,"depth":238,"text":816},"Subscribe a URL to space events — renders, brand changes, and content changes — with signed, header-customisable deliveries.","md",{"layout":888,"updatedAt":889},"docs","2026-07-08","\u002Fdocs\u002Fwebhooks",{"title":6,"description":885},"docs\u002Fwebhooks","a5VNy4kxCZCVVc-aXpSYTkNTitcYYjoA2BaTT28p-Pc",{"success":509,"routes":895,"total":1392,"generatedAt":1393,"canViewAllApiDocs":966},[896,941,953,1008,1065,1086,1107,1121,1136,1148,1160,1177,1205,1230,1249,1261,1272,1283,1292,1298,1316,1327,1342,1354,1367],{"path":897,"method":26,"summary":898,"description":899,"tags":900,"group":69,"requestBody":901,"responses":933,"actionName":940},"\u002Fapi\u002Fcode-to-image","Render code snippets as images","Render source code with syntax highlighting to PNG, WebP, or JPEG. No API token required.",[69],{"content":902},{"application\u002Fjson":903},{"schema":904},{"type":905,"required":906,"properties":907},"object",[24],{"code":908,"lang":911,"theme":913,"format":915,"width":921,"height":924,"quality":926,"showLineNumbers":928,"style":931},{"type":909,"description":910},"string","Source code to render",{"type":909,"description":912},"Language for highlighting (e.g. js, ts). Default: js",{"type":909,"description":914},"Shiki theme. Default: github-dark",{"type":909,"enum":916,"description":920},[917,918,919],"png","webp","jpeg","Output format. Default: png (lossless)",{"type":922,"description":923},"number","Optional width",{"type":922,"description":925},"Optional height",{"type":922,"description":927},"Optional quality",{"type":929,"description":930},"boolean","Show 1-based line numbers in a left gutter. Default: false",{"type":905,"description":932},"Optional style options",{"200":934,"400":936,"500":938},{"description":935},"Image (data URL or binary depending on format)",{"description":937},"Missing or invalid code",{"description":939},"Failed to generate code image","codeToImage",{"path":942,"method":26,"summary":943,"description":944,"tags":945,"group":946,"responses":947,"actionName":952},"\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.",[946],"Authentication",{"200":948,"429":950},{"description":949},"Demo token created",{"description":951},"Per-IP demo token quota reached","createDemoToken",{"path":954,"method":955,"summary":956,"description":957,"tags":958,"group":69,"parameters":959,"responses":1000,"actionName":1007},"\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).",[69],[960,964,973,977,983,987,991,995],{"in":961,"name":355,"required":509,"schema":962,"description":963},"path",{"type":909},"Page ID to render",{"in":965,"name":358,"required":966,"schema":967,"description":972},"query",false,{"type":909,"enum":968},[917,969,918,970,971],"svg","pdf","pptx","Output format. Default: png",{"in":965,"name":974,"required":966,"schema":975,"description":976},"draft",{"type":929},"If true, load from database instead of publish cache. Default: false",{"in":965,"name":978,"required":966,"schema":979,"description":982},"output",{"type":909,"enum":980},[223,981],"binary","Response shape: omit or json for metadata + file URL; binary for raw bytes",{"in":965,"name":984,"required":966,"schema":985,"description":986},"pageIds",{"type":909},"Comma-separated page IDs for merged PDF (format=pdf only)",{"in":965,"name":988,"required":966,"schema":989,"description":990},"gt",{"type":909},"GET render secret when Bearer is not used",{"in":965,"name":992,"required":966,"schema":993,"description":994},"scale",{"type":922,"minimum":231,"maximum":276},"Output resolution multiplier for png\u002Fwebp. Overrides the template's renderScale. Default 2.",{"in":965,"name":996,"required":966,"schema":997,"description":999},"quality",{"type":922,"minimum":231,"maximum":998},100,"WebP encode quality (webp only). Overrides the template's webpQuality. Default 90.",{"200":1001,"401":1003,"404":1005},{"description":1002},"Binary image\u002FPDF or application\u002Fjson with file metadata",{"description":1004},"Missing or invalid API token",{"description":1006},"Page or template not found","renderPage",{"path":1009,"method":26,"summary":1010,"description":1011,"tags":1012,"group":69,"requestBody":1013,"responses":1057,"actionName":1064},"\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.",[69],{"content":1014},{"application\u002Fjson":1015},{"schema":1016},{"type":905,"description":1017,"properties":1018},"For raster formats use pageId. For PDF use pageId (single) or pageIds (merged in order).",{"pageId":1019,"pageIds":1021,"tweaksPerPage":1025,"templateId":1028,"draft":1030,"format":1032,"tweaks":1036,"brandTweaks":1038,"emojiType":1040,"output":1042,"binary":1047,"renderType":1049,"scale":1054,"quality":1056},{"type":909,"description":1020},"Page ID to render (required for png\u002Fsvg\u002Fwebp; optional for pdf when pageIds is set)",{"type":1022,"items":1023,"description":1024},"array",{"type":909},"Multiple pages for merged PDF (format pdf only)",{"type":1022,"items":1026,"description":1027},{"type":905},"Per-page tweaks aligned with pageIds when rendering PDF",{"type":909,"description":1029},"Optional; when set, validated against the page's template (parallel fetch)",{"type":929,"description":1031},"If true, load page and template from database instead of publish cache. Default: false",{"type":909,"enum":1033,"description":1035},[917,969,918,970,971,1034],"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":905,"description":1037},"Variable overrides; keys may use dot paths for nested values. For Variable[] sources, use \"varId.nested.path\" when patching object values.",{"type":905,"description":1039},"Brand token overrides by dot path (e.g. logos.icon or brand.logos.icon). Merged into resolved brand tokens before render.",{"type":909,"description":1041},"e.g. twemoji, openmoji. Default from template",{"type":909,"enum":1043,"description":1046},[223,981,1044,1045],"image","raw","Response shape: omit or json for application\u002Fjson (default); binary, image, or raw for raw body",{"type":929,"description":1048},"If true, same as output binary (raw body)",{"type":909,"enum":1050,"description":1053},[1051,1052],"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":922,"minimum":231,"maximum":276,"description":1055},"Output resolution multiplier for png\u002Fwebp (logical layout unchanged, pixels multiplied). Overrides the template's renderScale. Default 2.",{"type":922,"minimum":231,"maximum":998,"description":999},{"200":1058,"400":1060,"401":1062,"404":1063},{"description":1059},"Default: application\u002Fjson with render metadata and file.url. With output binary: image\u002Fpng, image\u002Fsvg+xml, image\u002Fwebp, or application\u002Fpdf.",{"description":1061},"Invalid body (e.g. missing pageId)",{"description":1004},{"description":1006},"render",{"path":1066,"method":955,"summary":1067,"description":1068,"tags":1069,"parameters":1070,"responses":1080,"actionName":1085},"\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.",[69],[1071,1074,1077],{"in":965,"name":1072,"required":966,"description":1073},"templateId","Only logs for this template's pages",{"in":965,"name":1075,"required":966,"description":1076},"page","Page number",{"in":965,"name":1078,"required":966,"description":1079},"perPage","Items per page (default 50)",{"200":1081,"401":1083},{"description":1082},"JSON { list, count, pagesCount } of render log entries",{"description":1084},"Not logged in","listRenderLogs",{"path":1087,"method":955,"summary":1088,"description":1089,"tags":1090,"parameters":1092,"responses":1103,"actionName":1106},"\u002Fapi\u002Ftemplates\u002Fpublic","List public templates","List published community\u002Fgallery templates with their cached pages. No authentication required.",[1091],"Templates",[1093,1096,1099,1101],{"in":965,"name":1094,"required":966,"description":1095},"search","Search name + description (max 80 chars)",{"in":965,"name":1097,"required":966,"description":1098},"category","Category filter, or \"featured\" for the curated list",{"in":965,"name":1075,"required":966,"description":1100},"Page number (default 1)",{"in":965,"name":1078,"required":966,"description":1102},"Items per page (max 100)",{"200":1104},{"description":1105},"JSON { list, count, pagesCount } — templates include their published pages","listPublicTemplates",{"path":1108,"method":955,"summary":1109,"description":1110,"tags":1111,"parameters":1112,"responses":1115,"actionName":1120},"\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.",[1091],[1113],{"in":961,"name":440,"required":509,"description":1114},"Template ID",{"200":1116,"404":1118},{"description":1117},"JSON { doc } — the template including published pages",{"description":1119},"Template not found or not public","getPublicTemplateDoc",{"path":1122,"method":1123,"summary":1124,"description":1125,"tags":1126,"parameters":1127,"responses":1130,"actionName":1135},"\u002Fapi\u002Fv1\u002Fbrands\u002F:id","DELETE","Delete a brand","Soft-delete a brand by ID. Session-authenticated (dashboard login; owner\u002Fadmin\u002Feditor).",[90],[1128],{"in":961,"name":440,"required":509,"description":1129},"Brand ID",{"200":1131,"404":1133},{"description":1132},"JSON { success: true, id }",{"description":1134},"Brand not found in your space","deleteBrand",{"path":1122,"method":955,"summary":1137,"description":1138,"tags":1139,"parameters":1140,"responses":1142,"actionName":1147},"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).",[90],[1141],{"in":961,"name":440,"required":509,"description":1129},{"200":1143,"404":1145},{"description":1144},"JSON { doc } — the brand with its token sets",{"description":1146},"Not found or not accessible","getBrand",{"path":1122,"method":1149,"summary":1150,"description":1151,"tags":1152,"parameters":1153,"responses":1155,"actionName":1159},"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).",[90],[1154],{"in":961,"name":440,"required":509,"description":1129},{"200":1156,"404":1158},{"description":1157},"JSON { doc } — the updated brand",{"description":1134},"updateBrand",{"path":1161,"method":955,"summary":1162,"description":1163,"tags":1164,"parameters":1165,"responses":1171,"actionName":1176},"\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).",[90],[1166,1167,1168],{"in":965,"name":1075,"required":966,"description":1100},{"in":965,"name":1078,"required":966,"description":1079},{"in":965,"name":1169,"required":966,"description":1170},"public","\"true\" to list public brands without auth",{"200":1172,"401":1174},{"description":1173},"JSON { list, count, pagesCount } of brands",{"description":1175},"Not logged in (when public is not set)","listBrands",{"path":1161,"method":26,"summary":1178,"description":1179,"tags":1180,"requestBody":1181,"responses":1200,"actionName":1204},"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).",[90],{"content":1182},{"application\u002Fjson":1183},{"schema":1184},{"type":905,"required":1185,"properties":1187},[1186],"name",{"name":1188,"draftTokens":1190,"liveTokens":1192,"tokens":1194,"variants":1196,"extra":1198},{"type":909,"description":1189},"Brand name",{"type":905,"description":1191},"Token kit being edited (logos, colors, typography, …)",{"type":905,"description":1193},"Token kit used by published renders",{"type":905,"description":1195},"Resolved token set",{"type":905,"description":1197},"Named variations of the kit",{"type":905,"description":1199},"Free-form extras",{"200":1201,"401":1203},{"description":1202},"JSON { doc } — the created brand",{"description":1084},"createBrand",{"path":1206,"method":955,"summary":1207,"description":1208,"tags":1209,"group":127,"parameters":1210,"responses":1223,"actionName":1229},"\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.",[127],[1211,1214,1217,1220],{"in":961,"name":1212,"required":509,"description":1213},"collection","The collection's API name",{"in":961,"name":1215,"required":509,"description":1216},"slug","The entry slug",{"in":965,"name":1218,"required":966,"description":1219},"depth","Resolve reference fields to this depth (default 0)",{"in":965,"name":1221,"required":966,"description":1222},"variants","Comma-separated variant ids; returns personalization-resolved values",{"200":1224,"401":1226,"404":1227},{"description":1225},"JSON { doc } — the published entry",{"description":1004},{"description":1228},"Collection or entry not found","publicGetContentBySlug",{"path":1231,"method":955,"summary":1232,"description":1233,"tags":1234,"group":127,"parameters":1235,"responses":1242,"actionName":1248},"\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=).",[127],[1236,1237,1238,1240,1241],{"in":961,"name":1212,"required":509,"description":1213},{"in":965,"name":1075,"required":966,"description":1100},{"in":965,"name":1078,"required":966,"description":1239},"Items per page (default 20)",{"in":965,"name":1218,"required":966,"description":1219},{"in":965,"name":1221,"required":966,"description":1222},{"200":1243,"401":1245,"404":1246},{"description":1244},"JSON { list, count, pagesCount } of published entries",{"description":1004},{"description":1247},"Collection not found","publicListContent",{"path":1250,"method":1123,"summary":1251,"description":1252,"tags":1253,"responses":1255,"actionName":1260},"\u002Fapi\u002Fv1\u002Fshaders\u002F:id","Delete a shader","Permanently remove a shader from the current space.",[1254],"Shaders",{"200":1256,"404":1258},{"description":1257},"JSON { deleted: true }",{"description":1259},"No such shader","deleteShader",{"path":1250,"method":955,"summary":1262,"description":1263,"tags":1264,"responses":1265,"actionName":1271},"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.",[1254],{"200":1266,"404":1268,"410":1269},{"description":1267},"JSON { doc }",{"description":1259},{"description":1270},"Shader is quarantined or revoked","getShader",{"path":1250,"method":1149,"summary":1273,"description":1274,"tags":1275,"responses":1276,"actionName":1282},"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.",[1254],{"200":1277,"404":1279,"422":1280},{"description":1278},"JSON { doc, report }",{"description":1259},{"description":1281},"Rejected by vetting; the stored shader is unchanged","updateShader",{"path":1284,"method":26,"summary":1285,"description":1286,"tags":1287,"responses":1288,"actionName":1291},"\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.",[1254],{"200":1289,"404":1290},{"description":1267},{"description":1259},"setShaderStatus",{"path":1293,"method":26,"summary":1294,"description":1295,"tags":1296,"actionName":1297},"\u002Fapi\u002Fv1\u002Fshaders\u002F:id\u002Ftelemetry","Report a client watchdog trip","Called by a viewer whose frame watchdog disabled this shader. Enough independent trips ",[1254],"reportShaderTrip",{"path":1299,"method":955,"summary":1300,"description":1301,"tags":1302,"parameters":1303,"responses":1311,"actionName":1315},"\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.",[1254],[1304,1305,1306,1309],{"in":965,"name":1075,"required":966,"description":1100},{"in":965,"name":1078,"required":966,"description":1079},{"in":965,"name":1307,"required":966,"description":1308},"status","approved | quarantined | revoked",{"in":965,"name":1169,"required":966,"description":1310},"\"true\" to list public shaders without auth",{"200":1312,"401":1314},{"description":1313},"JSON { list, count, pagesCount }",{"description":1175},"listShaders",{"path":1299,"method":26,"summary":1317,"description":1318,"tags":1319,"responses":1320,"actionName":1326},"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.",[1254],{"200":1321,"401":1323,"422":1324},{"description":1322},"JSON { doc, report } — the stored shader and its vetting report",{"description":1084},{"description":1325},"Rejected by vetting; data.report explains which stage refused","createShader",{"path":1328,"method":1123,"summary":1329,"description":1330,"tags":1331,"parameters":1333,"responses":1336,"actionName":1341},"\u002Fapi\u002Fv1\u002Ftokens\u002Fapi-keys\u002F:id","Delete an API key","Revoke an API key immediately. Session-authenticated (dashboard login; owner\u002Fadmin).",[1332],"Tokens",[1334],{"in":961,"name":440,"required":509,"description":1335},"Token ID",{"200":1337,"404":1339},{"description":1338},"JSON { message } confirmation",{"description":1340},"Token not found in your space","deleteApiKey",{"path":1328,"method":1343,"summary":1344,"description":1345,"tags":1346,"parameters":1347,"responses":1349,"actionName":1353},"PATCH","Update an API key","Rename, change expiry, or adjust scopes of an API key. Session-authenticated (dashboard login; owner\u002Fadmin).",[1332],[1348],{"in":961,"name":440,"required":509,"description":1335},{"200":1350,"404":1352},{"description":1351},"JSON { doc } — the updated key",{"description":1340},"updateApiKey",{"path":1355,"method":955,"summary":1356,"description":1357,"tags":1358,"parameters":1359,"responses":1362,"actionName":1366},"\u002Fapi\u002Fv1\u002Ftokens\u002Fapi-keys\u002Findex","List API keys","List API keys for the current space. Session-authenticated (dashboard login; owner\u002Fadmin).",[1332],[1360,1361],{"in":965,"name":1075,"required":966,"description":1100},{"in":965,"name":1078,"required":966,"description":1239},{"200":1363,"401":1365},{"description":1364},"JSON { list, count, pagesCount } of API keys",{"description":1084},"listApiKeys",{"path":1355,"method":26,"summary":1368,"description":1369,"tags":1370,"requestBody":1371,"responses":1387,"actionName":1391},"Create an API key","Create a space-scoped API key. The plain token is returned once, on creation. Session-authenticated (dashboard login; owner\u002Fadmin).",[1332],{"content":1372},{"application\u002Fjson":1373},{"schema":1374},{"type":905,"required":1375,"properties":1376},[1186],{"name":1377,"expiresAt":1379,"neverExpires":1381,"shortToken":1383,"scopes":1385},{"type":909,"description":1378},"Key name (max 200 chars)",{"type":909,"description":1380},"ISO datetime expiry",{"type":929,"description":1382},"No expiry. Default: false",{"type":929,"description":1384},"Shorter ~96-bit token instead of ~256-bit. Default: false",{"type":905,"description":1386},"Optional restrictions: { mcpTools?: string[], apiEndpoints?: string[] }. Omit a list to allow all; [] denies all.",{"200":1388,"401":1390},{"description":1389},"JSON { doc } including the plain token (shown only once)",{"description":1084},"createApiKey",25,"2026-08-19T19:21:11.342Z",1787167272953]