Site Media
List site images, upload files, and capture product screenshots from public URLs.Updated 2d ago
Required scope: content:read 200 OK url is the canonical unsigned reference — persist this in page content. displayUrl is signed for the current token holder and changes over time; use it only to preview or download right now, not to embed in MDX.GET /api/v1/sites/{siteId}/media?cursor=0&limit=24 Authorization: Bearer av_live_…
Required scope: content:write 201 Created Then PUT the raw bytes with exactly the returned headers:POST /api/v1/sites/{siteId}/media/upload Authorization: Bearer av_live_… Content-Type: application/json { "contentType": "image/png", "size": 482133 }
Once the PUT succeeds, embed the returned publicUrl (canonical delivery path) in page MDX or metadata:curl -X PUT -H 'Content-Type: image/png' \ --data-binary @cover.png '…upload.url…'
Aveiro signs that path when a page is rendered — visitors on a live site get a standing grant; members previewing a draft get a short-lived grant only when they have site access. The delivery route re-checks site liveness on every read (not whether the storage key belongs to that site), which is what lets gallery templates keep working: cloning copies content and media references, not the underlying files. Unpublishing revokes visitor access. Legacy absolute Supabase URLs stored before this change are still recognised on read.<Media src="/api/media/site-media/SITE_ID/1754900000000-ab12cd.png?k=s.224eeebe-974f-4cfa-96ce-75fb5166c7b0.voSKxMzNi7OqQDeTMfj2e4o_g2EEGvtk" alt="Launch cover" />
GET /api/media/<storage-key>[?k=<delivery-grant>][?t=<share-token>]
No bearer token — authorization is carried in the URL or, as a last resort, the caller's session cookie.
Required scope: content:write 200 OK featured=1 narrows to the curated gallery (recommended for pickers). The response lists metadata only — the server resolves styleId when you queue the render. An unknown id returns 404 NOT_FOUND rather than silently falling back to the default look.GET /api/v1/sites/{siteId}/media/screenshot-styles?featured=1&limit=24 Authorization: Bearer av_live_…
Required scope: content:write Pass estimateOnly: true to price the render without starting or charging anything. A still costs 10 AI credits (flat — cheaper than a mockup video). Credits are debited when the render is queued and refunded automatically if it fails. 200 OK (estimate) Start the render by omitting estimateOnly or setting it to false. Look options (all optional — compose over each other):POST /api/v1/sites/{siteId}/media/screenshot Authorization: Bearer av_live_… Content-Type: application/json { "url": "https://www.example.com/pricing", "estimateOnly": true }
202 Accepted Poll until the image exists:{ "url": "https://www.example.com/pricing", "styleId": "preset_abc123", "theme": "dark", "framing": 1.1, "chrome": "light" }
Required scope: content:write 200 OK while rendering 200 OK when done Read warnings before embedding. A page that bounced to a login form renders perfectly — the image is real, but it is a picture of a login screen. warnings is separate from error: the render succeeded. Embed imageUrl in page MDX or metadata:GET /api/v1/sites/{siteId}/media/screenshot/{renderId} Authorization: Bearer av_live_…
Constraints<Media src="https://…/site-media/SITE_ID/1754900000000-ab12cd.png" alt="Pricing page on desktop" />
Required scope: content:write 201 Created Give loginUrl to a person who can sign in. The link expires in about an hour. When interactive is false, the hosted browser is unavailable on this deployment and the page may ask for credentials by hand instead. No credits charged — nothing is rendered. After they confirm sign-in, retry POST …/media/screenshot with recapture: true on the same URL.POST /api/v1/sites/{siteId}/media/screenshot-login Authorization: Bearer av_live_… Content-Type: application/json { "url": "https://app.example.com/dashboard" }