[{"data":1,"prerenderedAt":904},["ShallowReactive",2],{"docs-\u002Fconfiguring-api-proxy":3},{"id":4,"title":5,"body":6,"description":897,"extension":898,"meta":899,"navigation":350,"path":900,"seo":901,"stem":902,"__hash__":903},"docs\u002Fdocs\u002Fconfiguring-api-proxy.md","Configuring API Proxy",{"type":7,"value":8,"toc":877},"minimark",[9,13,17,28,31,34,39,42,62,65,67,71,78,81,87,94,96,100,107,140,146,148,152,158,161,167,170,172,176,182,202,205,210,221,227,230,234,241,247,261,271,273,277,283,285,291,294,297,303,307,318,624,633,639,641,645,651,665,668,670,674,677,680,691,697,703,705,709,715,720,723,734,736,740,743,762,765,767,771,774,780,782,788,791,793,797,800,834,837,839,843,873],[10,11,5],"h1",{"id":12},"configuring-api-proxy",[14,15,16],"p",{},"Cachely can proxy read-only CMS API requests through:",[18,19,25],"pre",{"className":20,"code":22,"language":23,"meta":24},[21],"language-text","https:\u002F\u002Fyour-project.cmsassets.com\u002F~api\u002F...\n","text","",[26,27,22],"code",{"__ignoreMap":24},[14,29,30],{},"This guide walks through the project-level configuration needed to enable the API proxy, where read-only CMS API requests are proxied and parsed responses can already contain proxy-ready asset URLs.",[32,33],"hr",{},[35,36,38],"h2",{"id":37},"what-api-proxy-gives-you","What API proxy gives you",[14,40,41],{},"When API proxy is enabled for a project, Cachely can:",[43,44,45,53,56,59],"ul",{},[46,47,48,49,52],"li",{},"forward ",[26,50,51],{},"GET"," requests to your upstream CMS API",[46,54,55],{},"inject credentials server-side",[46,57,58],{},"cache API responses at the edge",[46,60,61],{},"optionally rewrite asset URLs inside JSON responses to your edge domain",[14,63,64],{},"This is the primary Cachely flow. Asset proxy can still be used independently, but API proxy with asset URL rewriting is the setup that gives you the most value.",[32,66],{},[35,68,70],{"id":69},"_1-set-the-api-origin","1. Set the API origin",[14,72,73,74,77],{},"Set ",[26,75,76],{},"apiOrigin"," to the upstream base URL of the CMS API you want to proxy.",[14,79,80],{},"Examples:",[18,82,85],{"className":83,"code":84,"language":23,"meta":24},[21],"https:\u002F\u002Fapi.cloudinary.com\u002Fv1_1\u002Fmy-cloud\nhttps:\u002F\u002Fcdn.contentful.com\u002Fspaces\u002Fabc123\nhttps:\u002F\u002Fapi.storyblok.com\u002Fv2\u002Fcdn\n",[26,86,84],{"__ignoreMap":24},[14,88,89,90,93],{},"Every proxied request strips the ",[26,91,92],{},"\u002F~api"," prefix and appends the remaining path to this origin.",[32,95],{},[35,97,99],{"id":98},"_2-choose-the-auth-mode","2. Choose the auth mode",[14,101,102,103,106],{},"Use ",[26,104,105],{},"apiAuthMode"," to control how Cachely injects credentials into upstream requests.",[43,108,109,118,126,134],{},[46,110,111,114,115],{},[26,112,113],{},"bearer"," — sends ",[26,116,117],{},"Bearer \u003Ctoken>",[46,119,120,114,123],{},[26,121,122],{},"basic",[26,124,125],{},"Basic \u003Ctoken>",[46,127,128,114,131],{},[26,129,130],{},"token",[26,132,133],{},"Token \u003Ctoken>",[46,135,136,139],{},[26,137,138],{},"none"," — sends no auth header",[14,141,142,143,145],{},"For example, Cloudinary Admin API requests typically use ",[26,144,122],{},".",[32,147],{},[35,149,151],{"id":150},"_3-set-the-token-header","3. Set the token header",[14,153,102,154,157],{},[26,155,156],{},"apiTokenHeader"," when your upstream CMS expects a specific header name.",[14,159,160],{},"Default:",[18,162,165],{"className":163,"code":164,"language":23,"meta":24},[21],"Authorization\n",[26,166,164],{"__ignoreMap":24},[14,168,169],{},"In most cases you can leave this as-is.",[32,171],{},[35,173,175],{"id":174},"_4-configure-api-cache-ttl","4. Configure API cache TTL",[14,177,102,178,181],{},[26,179,180],{},"apiCacheTTL"," to control how long API responses stay cached at the edge.",[43,183,184,191],{},[46,185,186,187,190],{},"default: ",[26,188,189],{},"60"," seconds",[46,192,193,194,197,198,201],{},"supported range: ",[26,195,196],{},"10"," seconds to ",[26,199,200],{},"31536000"," seconds (1 year)",[14,203,204],{},"Choose a lower TTL for frequently changing content and a higher TTL for read-heavy endpoints with stable responses. Long TTLs (hours, days, or weeks) are a first-class use case for CMS-backed content — the edge only refetches when you explicitly invalidate.",[206,207,209],"h3",{"id":208},"how-invalidation-works","How invalidation works",[14,211,212,213,216,217,220],{},"Every cached API response is keyed by an internal ",[26,214,215],{},"apiCacheVersion"," counter. Bumping that counter re-keys all cached entries in one shot — the next request for each URL is a ",[26,218,219],{},"MISS"," and refetches from upstream. You bump it by calling:",[18,222,225],{"className":223,"code":224,"language":23,"meta":24},[21],"POST \u002Fapi\u002Ftenants\u002F{slug}\u002Frefresh-cache\nBody: { \"type\": \"api\" }\n",[26,226,224],{"__ignoreMap":24},[14,228,229],{},"That's what makes long TTLs safe: you are not waiting for expiry, you are invalidating on publish.",[206,231,233],{"id":232},"browser-vs-edge-ttl","Browser vs. edge TTL",[14,235,236,237,240],{},"Cacheable API responses are served with a split ",[26,238,239],{},"Cache-Control",":",[18,242,245],{"className":243,"code":244,"language":23,"meta":24},[21],"Cache-Control: public, s-maxage=\u003CapiCacheTTL>, max-age=60\n",[26,246,244],{"__ignoreMap":24},[43,248,249,255],{},[46,250,251,254],{},[26,252,253],{},"s-maxage"," drives the Cloudflare shared cache — full TTL, up to 1 year.",[46,256,257,260],{},[26,258,259],{},"max-age"," is intentionally capped at 60 seconds for the browser.",[14,262,263,264,267,268,270],{},"The version bump re-keys the edge cache instantly, but the public ",[26,265,266],{},"\u002F~api\u002F..."," URL does not change, so browsers can only pick up new content as their own cache expires. Keeping the browser ",[26,269,259],{}," short (≤ 60s) means an invalidation reaches end users within a minute even for year-long edge TTLs.",[32,272],{},[35,274,276],{"id":275},"_5-configure-preview-bypass","5. Configure preview bypass",[14,278,102,279,282],{},[26,280,281],{},"previewBypassParam"," to bypass API cache for preview flows.",[14,284,160],{},[18,286,289],{"className":287,"code":288,"language":23,"meta":24},[21],"preview\n",[26,290,288],{"__ignoreMap":24},[14,292,293],{},"If the proxied request includes that param, Cachely skips the API cache and fetches the upstream CMS API directly.",[14,295,296],{},"Example:",[18,298,301],{"className":299,"code":300,"language":23,"meta":24},[21],"https:\u002F\u002Fyour-project.cmsassets.com\u002F~api\u002Fstories\u002Fhome?preview=1\n",[26,302,300],{"__ignoreMap":24},[206,304,306],{"id":305},"using-bypass-from-your-app-code","Using bypass from your app code",[14,308,309,310,313,314,317],{},"If you use ",[26,311,312],{},"createCmsAssetsFetch"," from ",[26,315,316],{},"@synchronized-studio\u002Fcmsassets-core",", you can wrap the fetch function to append the bypass param automatically when preview or fresh-fetch mode is active:",[18,319,323],{"className":320,"code":321,"language":322,"meta":24,"style":24},"language-ts shiki shiki-themes github-dark","import { createCmsAssetsFetch } from '@synchronized-studio\u002Fcmsassets-core'\n\nconst baseFetch = createCmsAssetsFetch({ tenant: 'my-site', provider: 'prismic' })\n\n\u002F\u002F Wrap with a bypass signal — evaluated per request\nfunction withCacheBypass(baseFetch, shouldBypass) {\n  return function (input, init) {\n    if (!shouldBypass()) return baseFetch(input, init)\n    const url = typeof input === 'string' ? input : input.url\n    const parsed = new URL(url)\n    if (!parsed.searchParams.has('preview')) {\n      parsed.searchParams.set('preview', '1')\n    }\n    return baseFetch(parsed.toString(), init)\n  }\n}\n\nconst cmsFetch = withCacheBypass(baseFetch, () => isPreviewActive)\n","ts",[26,324,325,345,352,384,389,396,421,443,467,500,519,542,563,569,586,592,598,603],{"__ignoreMap":24},[326,327,330,334,338,341],"span",{"class":328,"line":329},"line",1,[326,331,333],{"class":332},"snl16","import",[326,335,337],{"class":336},"s95oV"," { createCmsAssetsFetch } ",[326,339,340],{"class":332},"from",[326,342,344],{"class":343},"sU2Wk"," '@synchronized-studio\u002Fcmsassets-core'\n",[326,346,348],{"class":328,"line":347},2,[326,349,351],{"emptyLinePlaceholder":350},true,"\n",[326,353,355,358,362,365,369,372,375,378,381],{"class":328,"line":354},3,[326,356,357],{"class":332},"const",[326,359,361],{"class":360},"sDLfK"," baseFetch",[326,363,364],{"class":332}," =",[326,366,368],{"class":367},"svObZ"," createCmsAssetsFetch",[326,370,371],{"class":336},"({ tenant: ",[326,373,374],{"class":343},"'my-site'",[326,376,377],{"class":336},", provider: ",[326,379,380],{"class":343},"'prismic'",[326,382,383],{"class":336}," })\n",[326,385,387],{"class":328,"line":386},4,[326,388,351],{"emptyLinePlaceholder":350},[326,390,392],{"class":328,"line":391},5,[326,393,395],{"class":394},"sAwPA","\u002F\u002F Wrap with a bypass signal — evaluated per request\n",[326,397,399,402,405,408,412,415,418],{"class":328,"line":398},6,[326,400,401],{"class":332},"function",[326,403,404],{"class":367}," withCacheBypass",[326,406,407],{"class":336},"(",[326,409,411],{"class":410},"s9osk","baseFetch",[326,413,414],{"class":336},", ",[326,416,417],{"class":410},"shouldBypass",[326,419,420],{"class":336},") {\n",[326,422,424,427,430,433,436,438,441],{"class":328,"line":423},7,[326,425,426],{"class":332},"  return",[326,428,429],{"class":332}," function",[326,431,432],{"class":336}," (",[326,434,435],{"class":410},"input",[326,437,414],{"class":336},[326,439,440],{"class":410},"init",[326,442,420],{"class":336},[326,444,446,449,451,454,456,459,462,464],{"class":328,"line":445},8,[326,447,448],{"class":332},"    if",[326,450,432],{"class":336},[326,452,453],{"class":332},"!",[326,455,417],{"class":367},[326,457,458],{"class":336},"()) ",[326,460,461],{"class":332},"return",[326,463,361],{"class":367},[326,465,466],{"class":336},"(input, init)\n",[326,468,470,473,476,478,481,484,487,490,493,495,497],{"class":328,"line":469},9,[326,471,472],{"class":332},"    const",[326,474,475],{"class":360}," url",[326,477,364],{"class":332},[326,479,480],{"class":332}," typeof",[326,482,483],{"class":336}," input ",[326,485,486],{"class":332},"===",[326,488,489],{"class":343}," 'string'",[326,491,492],{"class":332}," ?",[326,494,483],{"class":336},[326,496,240],{"class":332},[326,498,499],{"class":336}," input.url\n",[326,501,503,505,508,510,513,516],{"class":328,"line":502},10,[326,504,472],{"class":332},[326,506,507],{"class":360}," parsed",[326,509,364],{"class":332},[326,511,512],{"class":332}," new",[326,514,515],{"class":367}," URL",[326,517,518],{"class":336},"(url)\n",[326,520,522,524,526,528,531,534,536,539],{"class":328,"line":521},11,[326,523,448],{"class":332},[326,525,432],{"class":336},[326,527,453],{"class":332},[326,529,530],{"class":336},"parsed.searchParams.",[326,532,533],{"class":367},"has",[326,535,407],{"class":336},[326,537,538],{"class":343},"'preview'",[326,540,541],{"class":336},")) {\n",[326,543,545,548,551,553,555,557,560],{"class":328,"line":544},12,[326,546,547],{"class":336},"      parsed.searchParams.",[326,549,550],{"class":367},"set",[326,552,407],{"class":336},[326,554,538],{"class":343},[326,556,414],{"class":336},[326,558,559],{"class":343},"'1'",[326,561,562],{"class":336},")\n",[326,564,566],{"class":328,"line":565},13,[326,567,568],{"class":336},"    }\n",[326,570,572,575,577,580,583],{"class":328,"line":571},14,[326,573,574],{"class":332},"    return",[326,576,361],{"class":367},[326,578,579],{"class":336},"(parsed.",[326,581,582],{"class":367},"toString",[326,584,585],{"class":336},"(), init)\n",[326,587,589],{"class":328,"line":588},15,[326,590,591],{"class":336},"  }\n",[326,593,595],{"class":328,"line":594},16,[326,596,597],{"class":336},"}\n",[326,599,601],{"class":328,"line":600},17,[326,602,351],{"emptyLinePlaceholder":350},[326,604,606,608,611,613,615,618,621],{"class":328,"line":605},18,[326,607,357],{"class":332},[326,609,610],{"class":360}," cmsFetch",[326,612,364],{"class":332},[326,614,404],{"class":367},[326,616,617],{"class":336},"(baseFetch, () ",[326,619,620],{"class":332},"=>",[326,622,623],{"class":336}," isPreviewActive)\n",[14,625,626,627,632],{},"See the ",[628,629,631],"a",{"href":630},"\u002Fdocs\u002Fprismic#preview--fresh-fetch-bypass","Prismic integration guide"," for a complete Nuxt example.",[14,634,635,636,638],{},"Preview bypass only affects API proxy routes (",[26,637,92],{},"). Asset proxy requests are not affected.",[32,640],{},[35,642,644],{"id":643},"_6-decide-whether-to-rewrite-asset-urls","6. Decide whether to rewrite asset URLs",[14,646,102,647,650],{},[26,648,649],{},"transformApiUrls"," to control whether JSON API responses should have CMS asset URLs rewritten to your project's edge domain.",[43,652,653,659],{},[46,654,655,658],{},[26,656,657],{},"true"," — parsed response with rewritten asset URLs",[46,660,661,664],{},[26,662,663],{},"false"," — keep original upstream asset URLs",[14,666,667],{},"This setting is useful when you want API responses to already contain proxy-ready asset URLs before they reach your app.",[32,669],{},[35,671,673],{"id":672},"_7-save-the-token","7. Save the token",[14,675,676],{},"Store the CMS API token using the write-only token endpoint or the admin UI.",[14,678,679],{},"Important details:",[43,681,682,685,688],{},[46,683,684],{},"tokens are stored encrypted",[46,686,687],{},"tokens are never returned to the client",[46,689,690],{},"tokens are injected only when the worker needs to call the upstream API",[14,692,693,694,696],{},"For Cloudinary ",[26,695,122],{}," auth, the token value should be:",[18,698,701],{"className":699,"code":700,"language":23,"meta":24},[21],"btoa(\"api_key:api_secret\")\n",[26,702,700],{"__ignoreMap":24},[32,704],{},[35,706,708],{"id":707},"_8-test-the-proxied-url","8. Test the proxied URL",[14,710,711,712,714],{},"After configuration, send a ",[26,713,51],{}," request through your project:",[18,716,718],{"className":717,"code":22,"language":23,"meta":24},[21],[26,719,22],{"__ignoreMap":24},[14,721,722],{},"You should verify that the request:",[43,724,725,728,731],{},[46,726,727],{},"reaches the correct upstream path",[46,729,730],{},"authenticates successfully",[46,732,733],{},"returns the expected content",[32,735],{},[35,737,739],{"id":738},"_9-check-cache-and-parsing-headers","9. Check cache and parsing headers",[14,741,742],{},"Inspect the response headers:",[43,744,745,756],{},[46,746,747,414,750,752,753],{},[26,748,749],{},"X-Cache: HIT",[26,751,219],{},", or ",[26,754,755],{},"BYPASS",[46,757,758,761],{},[26,759,760],{},"X-Parsed: true"," when JSON URL rewriting is enabled",[14,763,764],{},"These headers tell you whether the response came from API cache and whether the body was parsed for asset URL rewriting.",[32,766],{},[35,768,770],{"id":769},"_10-use-raw-mode-when-needed","10. Use raw mode when needed",[14,772,773],{},"If you want the proxied upstream response without JSON asset URL rewriting, add:",[18,775,778],{"className":776,"code":777,"language":23,"meta":24},[21],"?parsed=false\n",[26,779,777],{"__ignoreMap":24},[14,781,296],{},[18,783,786],{"className":784,"code":785,"language":23,"meta":24},[21],"https:\u002F\u002Fyour-project.cmsassets.com\u002F~api\u002Fspaces\u002Fabc\u002Fentries?parsed=false\n",[26,787,785],{"__ignoreMap":24},[14,789,790],{},"This is helpful when one consumer needs raw CMS output while another wants proxy-ready URLs.",[32,792],{},[35,794,796],{"id":795},"summary","Summary",[14,798,799],{},"The recommended activation flow looks like this:",[801,802,803,806,812,815,821],"ol",{},[46,804,805],{},"create a project",[46,807,808,809,811],{},"add ",[26,810,76],{},", auth mode, and token",[46,813,814],{},"keep parsed responses enabled",[46,816,817,818,820],{},"decide whether ",[26,819,649],{}," should stay enabled",[46,822,823,824,826,827,830,831],{},"test ",[26,825,92],{}," and verify ",[26,828,829],{},"X-Cache"," \u002F ",[26,832,833],{},"X-Parsed",[14,835,836],{},"That gives you one edge domain for both proxied CMS responses and asset delivery. If you later decide you only want media delivery, you can still use the asset proxy on its own.",[32,838],{},[35,840,842],{"id":841},"next-steps","Next steps",[43,844,845,852,859],{},[46,846,847,851],{},[628,848,850],{"href":849},"\u002Fdocs\u002Fapi-proxy-overview","API Proxy Overview"," — Understand when to use each proxy mode",[46,853,854,858],{},[628,855,857],{"href":856},"\u002Fdocs\u002Fhow-it-works","How It Works"," — Review request flow and cache behavior",[46,860,861,865,866,414,869,872],{},[628,862,864],{"href":863},"\u002Fdocs\u002Fapi","Admin API"," — Full reference for ",[26,867,868],{},"api-config",[26,870,871],{},"api-token",", and cache refresh endpoints",[874,875,876],"style",{},"html pre.shiki code .snl16, html code.shiki .snl16{--shiki-default:#F97583}html pre.shiki code .s95oV, html code.shiki .s95oV{--shiki-default:#E1E4E8}html pre.shiki code .sU2Wk, html code.shiki .sU2Wk{--shiki-default:#9ECBFF}html pre.shiki code .sDLfK, html code.shiki .sDLfK{--shiki-default:#79B8FF}html pre.shiki code .svObZ, html code.shiki .svObZ{--shiki-default:#B392F0}html pre.shiki code .sAwPA, html code.shiki .sAwPA{--shiki-default:#6A737D}html pre.shiki code .s9osk, html code.shiki .s9osk{--shiki-default:#FFAB70}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);}",{"title":24,"searchDepth":347,"depth":347,"links":878},[879,880,881,882,883,887,890,891,892,893,894,895,896],{"id":37,"depth":347,"text":38},{"id":69,"depth":347,"text":70},{"id":98,"depth":347,"text":99},{"id":150,"depth":347,"text":151},{"id":174,"depth":347,"text":175,"children":884},[885,886],{"id":208,"depth":354,"text":209},{"id":232,"depth":354,"text":233},{"id":275,"depth":347,"text":276,"children":888},[889],{"id":305,"depth":354,"text":306},{"id":643,"depth":347,"text":644},{"id":672,"depth":347,"text":673},{"id":707,"depth":347,"text":708},{"id":738,"depth":347,"text":739},{"id":769,"depth":347,"text":770},{"id":795,"depth":347,"text":796},{"id":841,"depth":347,"text":842},"Step-by-step guide to setting up the Cachely API proxy — configure your origin URL, inject API tokens, set cache TTL, and enable automatic asset URL rewriting.","md",{},"\u002Fdocs\u002Fconfiguring-api-proxy",{"title":5,"description":897},"docs\u002Fconfiguring-api-proxy","rtdMkOyZTKX2ybDIeHTkN6tNILKCsSom8cmAmObFELU",1777579477591]