retention_expired
HTTP 410. The render you asked for exists, and it is returned in full in details.render —
but its file has passed its retention period, so no URL is signed for it. The file is deleted
and cannot be restored.
Only GET /v1/renders/:id (and the MCP get_render tool) answers this.
When it happens
Section titled “When it happens”Every render is stamped with an expires_at when it is made, from the account’s plan at that
moment: 7 days on Free and the keyless trial, 30 days on Solo and Starter, 90 days on
Growth and Scale. That deadline never moves afterwards — changing plan later does not shorten or
lengthen the retention of renders already made.
Until expires_at, GET /v1/renders/:id re-signs a URL to the file as often as you like, for free.
From the moment it passes:
GET /v1/renders/:idanswers410 retention_expiredinstead of signing a URL;GET /v1/rendersstill lists the render, withurl: null;- the render is no longer a cache hit, so an identical
POST /v1/renderrenders again; - a daily sweep deletes the stored file, normally within a day, and records the time in
file_deleted_at. Until the sweep reaches it,file_deleted_atisnull— but the file is already no longer served; - the same sweep deletes the
dataandoptionsthe render was made from. A failed render, which never had a file, loses its payload at its ownexpires_attoo, and itserrorkeeps only itstype.
The render record is kept: its id, template version, status, format, page count, size and cost stay on your account. Nothing from the payload does, so we can’t send it back to you.
{ "error": { "type": "retention_expired", "message": "The file for render `rnd_7hq2m4x8k1bv` passed its retention on 2026-09-28T14:07:02.551Z (7 days, this account's plan when it was made) and has been deleted, with the data and options it was made from. The render record is kept. To have the file again, render it again: the same template version, data and options make the same document, billed as a new render.", "docs_url": "https://galleyrender.com/docs/errors/retention_expired", "details": { "render": { "object": "render", "id": "rnd_7hq2m4x8k1bv", "status": "succeeded", "template": "invoice@1", "format": "pdf", "engine": "chromium", "cached": false, "url": null, "expires_at": "2026-09-28T14:07:02.551Z", "page_count": 1, "billable_units": 1, "byte_size": 27578, "content_type": "application/pdf", "created_at": "2026-09-21T14:07:02.551Z", "completed_at": "2026-09-21T14:07:04.112Z", "error": null, "webhook_status": null, "webhook_attempts": 0, "file_deleted_at": "2026-09-29T09:12:40.018Z" }, "expired_at": "2026-09-28T14:07:02.551Z", "file_deleted_at": "2026-09-29T09:12:40.018Z", "retention_days": 7, "next_step": "POST /v1/render with template \"invoice@1\", format \"pdf\" and the same data and options as the original request. It is a new, billed render; nothing about this one can be restored.", "rerender": { "method": "POST", "path": "/v1/render", "template": "invoice@1", "format": "pdf" } } }}What to do
Section titled “What to do”Do not retry the same request. The file will not come back.
- Render it again, if you still need the document. Send
POST /v1/renderwithdetails.rerender.template— the pinnedname@version, so the template is exactly the one used — the sameformat, and the samedataandoptionsyou sent the first time, from your own records (ours were deleted with the file). Renders are deterministic, so it is the same document. It is billed as a new render. - Keep your own copy next time. If a document has to outlive your plan’s retention, download it while the URL works and store it yourself. A plan with longer retention keeps files longer, but only for renders made after the change.
Related
Section titled “Related”- Caching — a signed URL expiring versus a file’s retention ending
- Security and data retention — exactly what is kept and for how long
GET /v1/renders/:id— where this comes from