---
title: "Save over the latest version of a template"
method: PUT
path: "/presets/{id}/current"
---

# Save over the latest version of a template

`PUT /presets/{id}/current`

## Request

- Base URL: `https://rendry.io/api/v1`
- URL: `https://rendry.io/api/v1/presets/{id}/current`
- Auth: one of:
  - HTTP bearer
  - HTTP bearer
  - HTTP bearer
  - HTTP bearer

Edits the newest version in place instead of creating another one. Does not consume a template slot. The body MUST name `id`, the version the client believes is the latest (the `id` of the GET /presets row or of GET /presets/{id}); without it the door answers 400, and when that version is no longer the latest it answers 409 preset_changed_elsewhere and writes nothing — somebody saved from another tab, an agent or the API in between, and silently writing over their work is the one thing this door refuses to do.

## Path parameters

- `id` string, required

## Headers

- `X-Rendry-Account` string

## Request body

- object: Full preset DSL, as in POST /presets, plus the version id
  - `sample_rows` object: Sample rows of repeat groups and tables, drawn until a render passes real rows
  - `derived` object[]: Colours FROM a photo: [{"name": "hero", "from": "<image layer id>"}]; then $hero.bg | .support | .accent | .on | .0..5 as any colour
  - `name` string, required
  - `description` string
  - `canvas` Canvas, required
    - `width` integer
    - `height` integer
    - `background_color` string
    - `output_format` string
    - `quality` integer
    - `max_width` integer
    - `finish_profile` string: Optional whole-canvas finish applied once after composition using the profile-specific paint policy. Use an exact id from the finish_profiles field returned by GET /capabilities; that runtime catalog also declares compatible formats and minimum dimensions.
  - `layers` object[], required
  - `modifications` object: Sources of the template's variables: the sample (default) value of each {name} when dynamic_data does not supply one — or, with a mode in variable_modes, the template or formula that computes it.
  - `variable_modes` object: How each modifications source is read (grammar and limits: GET /capabilities nested_variables). Missing, null or {} means every source is text, literal. template: {name} inserts that variable's value, {{ and }} print one brace. formula: exact decimal arithmetic (+ - * /, unary signs, parentheses, round(x[, decimals]), min(a,b,...), max(a,b,...), abs(x)) over numbers and {name}; additive grammar 3 adds count({items}) and sum({items},{amount}) over the effective whole rows source. Aggregate brace arguments are source/field handles, not variable edges. Empty count/sum is zero; every needed sum cell must be decimal, with a private one-based row/field refusal before charge. Unused, hidden and overridden aggregates read nothing; table and aggregate sources share the fetch cache/budget. Aggregate-dependent visible_if inside link_dest/follows refuses before reads; a literal controller override is allowed; a terminating result prints in full, a repeating one is rounded to nested_variables.projection_digits significant digits. A mode needs a source under the same name; page and pages are engine facts and take no mode; row.* names take none. A save refuses a schema problem (VariableDiagnosticCode invalid_mode, invalid_name, reserved_name, unsupported_row_scope, source_limit) and writes nothing; a definition that does not resolve from the saved values is saved and named in warnings, and a render refuses it before any charge unless dynamic_data supplies a literal for it. dynamic_data is always literal: a supplied value replaces the definition of that name for the call and is never parsed as a template or a formula. What a caller sends and what the template computes is told apart by InputDescriptor.
  - `palettes` object: Colours a field takes from data: {"tier": {"gold": "#C9A227", "default": "#444444"}}. A colour field then refers to one by the variable that chooses it — "fill_color": "{tier}" reads dynamic_data.tier, and inside a repeat the row's own tier field. An unknown value takes "default"; a palette without one refuses the render and names the values it admits.
  - `variable_formats` object, nullable: Sparse name -> display format beside modifications and variable_modes. A name needs a source in modifications and cannot be page, pages or row.*. Applied after source evaluation and also to caller overrides; formulas consume raw exact values while templates insert formatted text. Invalid schema refuses save; invalid data refuses dry run and render before any charge, without echoing values. update_preset patches: absent or {} keeps; name:null removes; top-level null clears. Whole preset and document saves replace the map.
  - `id` string, required: The version being written over — the latest version's id as the client read it
  - `preset_group_id` string: The template; when present it must match the path id

## Response `200`

Saved over the latest version

- PresetWriteResult: The reply of POST /presets and PUT /presets/{id}/current. preset_id and preset_group_id carry the SAME value — the template's group id, which every render, patch, share and delete-group door takes; version_id is the row this write produced (what GET /presets rows show as `id`).
  - `preset_id` string, required: The template's group id (equal to preset_group_id)
  - `preset_group_id` string, required
  - `version_id` string, required: The version written: the id GET /presets rows show
  - `status` 'created' | 'updated', required
  - `autofixes` string[]: Fields renamed on the way in (e.g. font_size read as size) — send the canonical names from now on
  - `warnings` string[]: What will look broken in the output; fix before rendering

## Other responses

- `400`: `id` missing ("id of the version being updated is required"), an unknown field or invalid DSL
- `409`: The version named by `id` is no longer the latest: nothing was written

---

[API](https://skmtc.dev/rendry/apis/rendry-api.md) · [All operations](https://skmtc.dev/rendry/apis/rendry-api/llms.txt) · [OpenAPI document](https://skmtc.dev/rendry/apis/rendry-api/revisions/c4fb572c26c9?raw)
