[{"data":1,"prerenderedAt":1043},["ShallowReactive",2],{"docs-\u002Fapi\u002Ftenants":3},{"id":4,"title":5,"body":6,"description":1035,"extension":1036,"meta":1037,"navigation":1038,"path":1039,"seo":1040,"stem":1041,"__hash__":1042},"docs\u002Fdocs\u002Fapi\u002Ftenants.md","Tenants API",{"type":7,"value":8,"toc":1003},"minimark",[9,13,17,25,57,63,103,109,136,142,163,169,199,205,233,239,264,270,297,303,330,336,359,365,391,397,424,430,456,462,489,495,538,544,589,595,634,640,666,672,697,703,734,740,770,776,804,810,844,850,885,891,925,931,964,970],[10,11,5],"h1",{"id":12},"tenants-api",[14,15,16],"p",{},"All endpoints below use the same docs format and reference Zod\u002FTS shapes from server code.",[18,19,21],"h3",{"id":20},"get-apitenants",[22,23,24],"code",{},"GET \u002Fapi\u002Ftenants",[26,27,28,32,35,38,45,52],"ul",{},[29,30,31],"li",{},"Purpose: List tenants for the authenticated user.",[29,33,34],{},"Auth: Clerk session.",[29,36,37],{},"Request shape: none.",[29,39,40,41,44],{},"Response shape: ",[22,42,43],{},"{ total, tenants[] }",".",[29,46,47,48,51],{},"Key errors: ",[22,49,50],{},"401"," unauthorized.",[29,53,54,55,44],{},"Example: ",[22,56,24],{},[18,58,60],{"id":59},"post-apitenants",[22,61,62],{},"POST \u002Fapi\u002Ftenants",[26,64,65,68,70,73,78,92],{},[29,66,67],{},"Purpose: Create a new tenant.",[29,69,34],{},[29,71,72],{},"Request shape: Slug + CMS configuration + optional cache\u002Fdomain fields.",[29,74,40,75,44],{},[22,76,77],{},"{ ok, key, proxyBase }",[29,79,47,80,83,84,87,88,91],{},[22,81,82],{},"403"," plan limit, ",[22,85,86],{},"409"," slug already used, ",[22,89,90],{},"400"," validation.",[29,93,94,95,98,99,102],{},"Example: Body with ",[22,96,97],{},"slug",", ",[22,100,101],{},"cms",", and provider-specific fields.",[18,104,106],{"id":105},"get-apitenantsslug-availability",[22,107,108],{},"GET \u002Fapi\u002Ftenants\u002Fslug-availability",[26,110,111,114,116,121,126,131],{},[29,112,113],{},"Purpose: Check whether a slug is available.",[29,115,34],{},[29,117,118,119,44],{},"Request shape: Query ",[22,120,97],{},[29,122,40,123,44],{},[22,124,125],{},"{ slug, available }",[29,127,47,128,130],{},[22,129,90],{}," invalid slug.",[29,132,54,133,44],{},[22,134,135],{},"GET \u002Fapi\u002Ftenants\u002Fslug-availability?slug=my-project",[18,137,139],{"id":138},"get-apitenantsusage",[22,140,141],{},"GET \u002Fapi\u002Ftenants\u002Fusage",[26,143,144,147,149,152,155,159],{},[29,145,146],{},"Purpose: Aggregate usage across all user tenants.",[29,148,34],{},[29,150,151],{},"Request shape: Optional period query.",[29,153,154],{},"Response shape: Per-tenant list\u002Faggregates.",[29,156,47,157,44],{},[22,158,50],{},[29,160,54,161,44],{},[22,162,141],{},[18,164,166],{"id":165},"get-apitenantsslug",[22,167,168],{},"GET \u002Fapi\u002Ftenants\u002F{slug}",[26,170,171,174,177,183,188,194],{},[29,172,173],{},"Purpose: Read configuration for a single tenant.",[29,175,176],{},"Auth: Clerk session + tenant access.",[29,178,179,180,44],{},"Request shape: Path ",[22,181,182],{},"{slug}",[29,184,40,185,44],{},[22,186,187],{},"{ key, value }",[29,189,47,190,193],{},[22,191,192],{},"404"," tenant not found.",[29,195,54,196,44],{},[22,197,198],{},"GET \u002Fapi\u002Ftenants\u002Facme",[18,200,202],{"id":201},"put-apitenantsslug",[22,203,204],{},"PUT \u002Fapi\u002Ftenants\u002F{slug}",[26,206,207,210,212,215,220,227],{},[29,208,209],{},"Purpose: Update tenant configuration (partial update).",[29,211,176],{},[29,213,214],{},"Request shape: Body with changed fields (Zod validation).",[29,216,217,218,44],{},"Response shape: Updated ",[22,219,187],{},[29,221,47,222,224,225,193],{},[22,223,90],{}," invalid body, ",[22,226,192],{},[29,228,229,230,44],{},"Example: Body ",[22,231,232],{},"{ cacheTTL, websiteDomain }",[18,234,236],{"id":235},"delete-apitenantsslug",[22,237,238],{},"DELETE \u002Fapi\u002Ftenants\u002F{slug}",[26,240,241,244,246,250,255,259],{},[29,242,243],{},"Purpose: Delete a tenant and related configuration.",[29,245,176],{},[29,247,179,248,44],{},[22,249,182],{},[29,251,40,252,44],{},[22,253,254],{},"{ ok, key }",[29,256,47,257,193],{},[22,258,192],{},[29,260,54,261,44],{},[22,262,263],{},"DELETE \u002Fapi\u002Ftenants\u002Facme",[18,265,267],{"id":266},"get-apitenantssluganalytics",[22,268,269],{},"GET \u002Fapi\u002Ftenants\u002F{slug}\u002Fanalytics",[26,271,272,275,277,282,285,292],{},[29,273,274],{},"Purpose: Return tenant analytics overview.",[29,276,176],{},[29,278,179,279,281],{},[22,280,182],{}," + optional period query.",[29,283,284],{},"Response shape: Analytics object for dashboards.",[29,286,47,287,98,289,291],{},[22,288,192],{},[22,290,90],{}," invalid period.",[29,293,54,294,44],{},[22,295,296],{},"GET \u002Fapi\u002Ftenants\u002Facme\u002Fanalytics",[18,298,300],{"id":299},"get-apitenantsslugbandwidth-daily",[22,301,302],{},"GET \u002Fapi\u002Ftenants\u002F{slug}\u002Fbandwidth-daily",[26,304,305,308,310,315,318,325],{},[29,306,307],{},"Purpose: Daily bandwidth breakdown for a tenant.",[29,309,176],{},[29,311,179,312,314],{},[22,313,182],{}," + optional range query.",[29,316,317],{},"Response shape: Daily usage points.",[29,319,47,320,322,323,44],{},[22,321,90],{}," invalid range, ",[22,324,192],{},[29,326,54,327,44],{},[22,328,329],{},"GET \u002Fapi\u002Ftenants\u002Facme\u002Fbandwidth-daily",[18,331,333],{"id":332},"get-apitenantsslugdomains",[22,334,335],{},"GET \u002Fapi\u002Ftenants\u002F{slug}\u002Fdomains",[26,337,338,341,343,347,350,354],{},[29,339,340],{},"Purpose: List custom domain records for a tenant.",[29,342,176],{},[29,344,179,345,44],{},[22,346,182],{},[29,348,349],{},"Response shape: Domain list with statuses.",[29,351,47,352,44],{},[22,353,192],{},[29,355,54,356,44],{},[22,357,358],{},"GET \u002Fapi\u002Ftenants\u002Facme\u002Fdomains",[18,360,362],{"id":361},"post-apitenantsslugdomains",[22,363,364],{},"POST \u002Fapi\u002Ftenants\u002F{slug}\u002Fdomains",[26,366,367,370,372,375,378,386],{},[29,368,369],{},"Purpose: Add a custom domain to a tenant.",[29,371,176],{},[29,373,374],{},"Request shape: Body with hostname field.",[29,376,377],{},"Response shape: Created domain record.",[29,379,47,380,382,383,385],{},[22,381,90],{}," invalid hostname, ",[22,384,86],{}," already exists.",[29,387,229,388,44],{},[22,389,390],{},"{ hostname: \\\"cdn.acme.com\\\" }",[18,392,394],{"id":393},"delete-apitenantsslugdomains",[22,395,396],{},"DELETE \u002Fapi\u002Ftenants\u002F{slug}\u002Fdomains",[26,398,399,402,404,409,414,419],{},[29,400,401],{},"Purpose: Remove a custom domain from a tenant.",[29,403,176],{},[29,405,179,406,408],{},[22,407,182],{}," + body\u002Fquery identifying the domain to remove.",[29,410,40,411,44],{},[22,412,413],{},"{ ok }",[29,415,47,416,418],{},[22,417,192],{}," domain not found.",[29,420,54,421,44],{},[22,422,423],{},"DELETE \u002Fapi\u002Ftenants\u002Facme\u002Fdomains",[18,425,427],{"id":426},"post-apitenantsslugdomainsverify",[22,428,429],{},"POST \u002Fapi\u002Ftenants\u002F{slug}\u002Fdomains\u002Fverify",[26,431,432,435,437,442,445,451],{},[29,433,434],{},"Purpose: Trigger\u002Fcheck custom domain DNS verification.",[29,436,176],{},[29,438,179,439,441],{},[22,440,182],{}," + domain identifier.",[29,443,444],{},"Response shape: Domain verification status.",[29,446,47,447,98,449,44],{},[22,448,90],{},[22,450,192],{},[29,452,54,453,44],{},[22,454,455],{},"POST \u002Fapi\u002Ftenants\u002Facme\u002Fdomains\u002Fverify",[18,457,459],{"id":458},"get-apitenantssluglogs",[22,460,461],{},"GET \u002Fapi\u002Ftenants\u002F{slug}\u002Flogs",[26,463,464,467,469,474,477,484],{},[29,465,466],{},"Purpose: Tenant-level request log view.",[29,468,176],{},[29,470,179,471,473],{},[22,472,182],{}," + pagination\u002Ffilter query.",[29,475,476],{},"Response shape: Log entries + pagination metadata.",[29,478,47,479,481,482,44],{},[22,480,90],{}," invalid query, ",[22,483,192],{},[29,485,54,486,44],{},[22,487,488],{},"GET \u002Fapi\u002Ftenants\u002Facme\u002Flogs",[18,490,492],{"id":491},"get-apitenantsslugaudit-events",[22,493,494],{},"GET \u002Fapi\u002Ftenants\u002F{slug}\u002Faudit-events",[26,496,497,500,503,520,525,533],{},[29,498,499],{},"Purpose: Tenant audit history (membership, role, configuration, and other sensitive changes). Master admins are also granted access via the standard tenant access override.",[29,501,502],{},"Auth: Clerk session + tenant membership (viewer+).",[29,504,179,505,507,508,511,512,515,516,519],{},[22,506,182],{}," + optional query ",[22,509,510],{},"limit"," (1..200, default 50) and ",[22,513,514],{},"beforeId"," (keyset pagination — fetch entries with ",[22,517,518],{},"id \u003C beforeId",").",[29,521,40,522,44],{},[22,523,524],{},"{ events[], hasMore }",[29,526,47,527,98,529,98,531,193],{},[22,528,50],{},[22,530,82],{},[22,532,192],{},[29,534,54,535,44],{},[22,536,537],{},"GET \u002Fapi\u002Ftenants\u002Facme\u002Faudit-events?limit=50&beforeId=1234",[18,539,541],{"id":540},"post-apitenantsslugrefresh-cache",[22,542,543],{},"POST \u002Fapi\u002Ftenants\u002F{slug}\u002Frefresh-cache",[26,545,546,549,552,571,576,584],{},[29,547,548],{},"Purpose: Increment cache versions and force new cache keys.",[29,550,551],{},"Auth: Clerk session + tenant access (editor+).",[29,553,554,555,558,559,98,562,98,565,98,568,519],{},"Request shape: Body with ",[22,556,557],{},"type"," (",[22,560,561],{},"api",[22,563,564],{},"assets",[22,566,567],{},"html",[22,569,570],{},"all",[29,572,40,573,44],{},[22,574,575],{},"{ ok, versions: { apiCacheVersion, assetCacheVersion, htmlCacheVersion } }",[29,577,47,578,580,581,583],{},[22,579,90],{}," invalid type, ",[22,582,82],{}," insufficient role.",[29,585,229,586,44],{},[22,587,588],{},"{ type: \\\"html\\\" }",[18,590,592],{"id":591},"post-apitenantsslugwebhook",[22,593,594],{},"POST \u002Fapi\u002Ftenants\u002F{slug}\u002Fwebhook",[26,596,597,600,607,613,618,629],{},[29,598,599],{},"Purpose: External webhook endpoint for CMS publish notifications (e.g. Webflow site_publish). Bumps htmlCacheVersion so the edge Worker fetches fresh HTML on the next request.",[29,601,602,603,606],{},"Auth: Per-tenant URL-embedded secret (",[22,604,605],{},"?secret=","). No Clerk session required.",[29,608,118,609,612],{},[22,610,611],{},"secret",". Body is ignored (compatible with any CMS webhook payload).",[29,614,40,615,44],{},[22,616,617],{},"{ ok, htmlCacheVersion }",[29,619,47,620,622,623,625,626,628],{},[22,621,50],{}," missing or invalid secret, ",[22,624,82],{}," webhook not configured, ",[22,627,192],{}," unknown project.",[29,630,54,631,44],{},[22,632,633],{},"POST \u002Fapi\u002Ftenants\u002Facme\u002Fwebhook?secret=abc123...",[18,635,637],{"id":636},"post-apitenantsslugwebhook-secret",[22,638,639],{},"POST \u002Fapi\u002Ftenants\u002F{slug}\u002Fwebhook-secret",[26,641,642,645,647,649,654,661],{},[29,643,644],{},"Purpose: Generate a webhook secret for the tenant (idempotent — returns existing secret if already generated).",[29,646,551],{},[29,648,37],{},[29,650,40,651,44],{},[22,652,653],{},"{ secret }",[29,655,47,656,658,659,193],{},[22,657,82],{}," insufficient role, ",[22,660,192],{},[29,662,54,663,44],{},[22,664,665],{},"POST \u002Fapi\u002Ftenants\u002Facme\u002Fwebhook-secret",[18,667,669],{"id":668},"put-apitenantsslugwebhook-secret",[22,670,671],{},"PUT \u002Fapi\u002Ftenants\u002F{slug}\u002Fwebhook-secret",[26,673,674,677,680,682,686,692],{},[29,675,676],{},"Purpose: Rotate the webhook secret. The old secret becomes invalid immediately.",[29,678,679],{},"Auth: Clerk session + tenant access (admin+).",[29,681,37],{},[29,683,40,684,44],{},[22,685,653],{},[29,687,47,688,658,690,193],{},[22,689,82],{},[22,691,192],{},[29,693,54,694,44],{},[22,695,696],{},"PUT \u002Fapi\u002Ftenants\u002Facme\u002Fwebhook-secret",[18,698,700],{"id":699},"put-apitenantsslugapi-config",[22,701,702],{},"PUT \u002Fapi\u002Ftenants\u002F{slug}\u002Fapi-config",[26,704,705,708,710,716,719,726],{},[29,706,707],{},"Purpose: Save API proxy configuration without token.",[29,709,176],{},[29,711,554,712,715],{},[22,713,714],{},"apiOrigin",", auth mode, TTL, and preview\u002Fcache options.",[29,717,718],{},"Response shape: Saved API config.",[29,720,47,721,723,724,44],{},[22,722,90],{}," validation, ",[22,725,192],{},[29,727,94,728,730,731,44],{},[22,729,714],{}," and ",[22,732,733],{},"apiAuthMode",[18,735,737],{"id":736},"put-apitenantsslugapi-token",[22,738,739],{},"PUT \u002Fapi\u002Ftenants\u002F{slug}\u002Fapi-token",[26,741,742,745,747,753,758,765],{},[29,743,744],{},"Purpose: Write-only save of encrypted API token.",[29,746,176],{},[29,748,749,750,44],{},"Request shape: Body ",[22,751,752],{},"{ token }",[29,754,40,755,44],{},[22,756,757],{},"{ ok, updatedAt }",[29,759,47,760,762,763,44],{},[22,761,90],{}," token missing, ",[22,764,192],{},[29,766,229,767,44],{},[22,768,769],{},"{ token: \\\"***\\\" }",[18,771,773],{"id":772},"get-apitenantsslugusage",[22,774,775],{},"GET \u002Fapi\u002Ftenants\u002F{slug}\u002Fusage",[26,777,778,781,783,788,793,799],{},[29,779,780],{},"Purpose: Usage overview for a single tenant.",[29,782,176],{},[29,784,179,785,787],{},[22,786,182],{}," + optional period.",[29,789,40,790,44],{},[22,791,792],{},"{ current, previous, period }",[29,794,47,795,98,797,291],{},[22,796,192],{},[22,798,90],{},[29,800,54,801,44],{},[22,802,803],{},"GET \u002Fapi\u002Ftenants\u002Facme\u002Fusage",[18,805,807],{"id":806},"get-apitenantsslugmembers",[22,808,809],{},"GET \u002Fapi\u002Ftenants\u002F{slug}\u002Fmembers",[26,811,812,815,817,821,831,839],{},[29,813,814],{},"Purpose: List all members for a tenant. Pending invites (with PII) are only included for admins and owners.",[29,816,502],{},[29,818,179,819,44],{},[22,820,182],{},[29,822,40,823,826,827,830],{},[22,824,825],{},"{ members[], invites[] }",". ",[22,828,829],{},"invites"," is empty for non-admin callers.",[29,832,47,833,98,835,98,837,193],{},[22,834,50],{},[22,836,82],{},[22,838,192],{},[29,840,54,841,44],{},[22,842,843],{},"GET \u002Fapi\u002Ftenants\u002Facme\u002Fmembers",[18,845,847],{"id":846},"post-apitenantsslugmembersinvite",[22,848,849],{},"POST \u002Fapi\u002Ftenants\u002F{slug}\u002Fmembers\u002Finvite",[26,851,852,855,858,866,871,880],{},[29,853,854],{},"Purpose: Create or refresh an invite for a new member. Requires admin role. Admins cannot assign the owner role.",[29,856,857],{},"Auth: Clerk session + tenant admin+.",[29,859,179,860,862,863,44],{},[22,861,182],{}," + body ",[22,864,865],{},"{ email: string, role: \"viewer\"|\"editor\"|\"admin\"|\"owner\" }",[29,867,40,868,44],{},[22,869,870],{},"{ id, email, role, token, expiresAt, createdAt, emailSent }",[29,872,47,873,723,875,877,878,193],{},[22,874,90],{},[22,876,82],{}," insufficient privileges or role escalation, ",[22,879,192],{},[29,881,229,882,44],{},[22,883,884],{},"{ email: \"user@example.com\", role: \"editor\" }",[18,886,888],{"id":887},"post-apitenantsslugmembersremove",[22,889,890],{},"POST \u002Fapi\u002Ftenants\u002F{slug}\u002Fmembers\u002Fremove",[26,892,893,896,898,905,910,920],{},[29,894,895],{},"Purpose: Remove a member from the tenant. Cannot remove yourself, the last owner, or someone with equal\u002Fhigher privileges (unless owner).",[29,897,857],{},[29,899,179,900,862,902,44],{},[22,901,182],{},[22,903,904],{},"{ userId: string }",[29,906,40,907,44],{},[22,908,909],{},"{ ok, userId }",[29,911,47,912,723,914,916,917,919],{},[22,913,90],{},[22,915,82],{}," self-removal or privilege check, ",[22,918,192],{}," member not found.",[29,921,229,922,44],{},[22,923,924],{},"{ userId: \"user_123\" }",[18,926,928],{"id":927},"post-apitenantsslugmembersrevoke-invite",[22,929,930],{},"POST \u002Fapi\u002Ftenants\u002F{slug}\u002Fmembers\u002Frevoke-invite",[26,932,933,936,938,945,950,959],{},[29,934,935],{},"Purpose: Revoke a pending invite by its ID.",[29,937,857],{},[29,939,179,940,862,942,44],{},[22,941,182],{},[22,943,944],{},"{ inviteId: number }",[29,946,40,947,44],{},[22,948,949],{},"{ ok, inviteId }",[29,951,47,952,723,954,98,956,958],{},[22,953,90],{},[22,955,82],{},[22,957,192],{}," invite not found or already revoked.",[29,960,229,961,44],{},[22,962,963],{},"{ inviteId: 42 }",[18,965,967],{"id":966},"post-apitenantsslugmembersupdate-role",[22,968,969],{},"POST \u002Fapi\u002Ftenants\u002F{slug}\u002Fmembers\u002Fupdate-role",[26,971,972,975,977,984,989,998],{},[29,973,974],{},"Purpose: Change a member's role. Cannot change your own role, assign owner (unless caller is owner), or act on members with equal\u002Fhigher privileges.",[29,976,857],{},[29,978,179,979,862,981,44],{},[22,980,182],{},[22,982,983],{},"{ userId: string, role: \"viewer\"|\"editor\"|\"admin\"|\"owner\" }",[29,985,40,986,44],{},[22,987,988],{},"{ userId, role, updatedAt }",[29,990,47,991,723,993,995,996,919],{},[22,992,90],{},[22,994,82],{}," privilege checks, ",[22,997,192],{},[29,999,229,1000,44],{},[22,1001,1002],{},"{ userId: \"user_123\", role: \"admin\" }",{"title":1004,"searchDepth":1005,"depth":1005,"links":1006},"",2,[1007,1009,1010,1011,1012,1013,1014,1015,1016,1017,1018,1019,1020,1021,1022,1023,1024,1025,1026,1027,1028,1029,1030,1031,1032,1033,1034],{"id":20,"depth":1008,"text":24},3,{"id":59,"depth":1008,"text":62},{"id":105,"depth":1008,"text":108},{"id":138,"depth":1008,"text":141},{"id":165,"depth":1008,"text":168},{"id":201,"depth":1008,"text":204},{"id":235,"depth":1008,"text":238},{"id":266,"depth":1008,"text":269},{"id":299,"depth":1008,"text":302},{"id":332,"depth":1008,"text":335},{"id":361,"depth":1008,"text":364},{"id":393,"depth":1008,"text":396},{"id":426,"depth":1008,"text":429},{"id":458,"depth":1008,"text":461},{"id":491,"depth":1008,"text":494},{"id":540,"depth":1008,"text":543},{"id":591,"depth":1008,"text":594},{"id":636,"depth":1008,"text":639},{"id":668,"depth":1008,"text":671},{"id":699,"depth":1008,"text":702},{"id":736,"depth":1008,"text":739},{"id":772,"depth":1008,"text":775},{"id":806,"depth":1008,"text":809},{"id":846,"depth":1008,"text":849},{"id":887,"depth":1008,"text":890},{"id":927,"depth":1008,"text":930},{"id":966,"depth":1008,"text":969},"Tenant lifecycle, configuration, domains, cache, and tenant-level analytics.","md",{},true,"\u002Fdocs\u002Fapi\u002Ftenants",{"title":5,"description":1035},"docs\u002Fapi\u002Ftenants","6unza6eS9T4GxXrNPPqJqWPuLMTn4tmIgcyd4VT8s6o",1777579477592]