Update Layers

Add, duplicate, replace, edit, delete or restack layers on a template's pages, including saved animation timing

Updated

PATCH
/v1/studio/templates/{templateId}/update-layers
curl -X PATCH "https://api.orshot.com/v1/studio/templates/<TEMPLATE_ID>/update-layers" \
  -H "Authorization: Bearer <ORSHOT_API_KEY>" \
  -H "Content-Type: application/json" \
  -d '{
    "operations": [],
    "base_updated_at": "<BASE_UPDATED_AT>",
    "embed_user_id": "<EMBED_USER_ID>"
  }'

Change individual layers of a template without re-sending the design: add a layer, copy one, replace one, edit any of its fields (including saved animation timing and motion, which Update Template Modifications can only apply per render), delete it, or change its stacking order. Only pages whose content changed get a new thumbnail and animated preview; every other page keeps the one that already matches it.

Which update endpoint?#

You want to changeUse
Name, tags, canvas size, or the entire design at onceUpdate Template
Pages: add, duplicate, replace, edit settings, delete, reorderUpdate Pages
Layers on a page: add, replace, edit (incl. saved animation timing), delete, restackUpdate Layers (this page)
Values of existing dynamic layers: text, images, colors, style, positionUpdate Template Modifications

Endpoint#

Endpoint
https://api.orshot.com/v1/studio/templates/:templateId/update-layers

Query Parameters#

ParameterTypeRequiredDefaultDescription
includeThumbnailsBooleanNofalseWhen true, the response waits for the new thumbnails of the changed pages. Otherwise they are generated in the background.
includeVideoThumbnailsBooleanNofalseWhen true and at most 2 changed pages are animated, the response waits for their animated previews. Otherwise they are generated in the background.

Request Examples#

JavaScript
// Store new entrance timing on a layer (by element id or parameter id)
await fetch("https://api.orshot.com/v1/studio/templates/12345/update-layers", {
  method: "PATCH",
  headers: {
    "Content-Type": "application/json",
    Authorization: "Bearer <ORSHOT_API_KEY>",
  },
  body: JSON.stringify({
    operations: [
      {
        op: "update",
        parameter_id: "headline",
        page_id: "a1b2c3d4-5e6f-7890-abcd-ef1234567890", // or page: 1
        set: {
          transitions: { enter: { type: "slideInUp", duration: 0.6 }, showAt: 1.2 },
          style: { color: "#FFFFFF" }
        }
      }
    ]
  }),
});
JavaScript
// Add a logo on page 2 above the background, move a badge to the top, delete a sticker
await fetch("https://api.orshot.com/v1/studio/templates/12345/update-layers", {
  method: "PATCH",
  headers: {
    "Content-Type": "application/json",
    Authorization: "Bearer <ORSHOT_API_KEY>",
  },
  body: JSON.stringify({
    operations: [
      {
        op: "add",
        page: 2, // or page_id: "b2c3d4e5-6f78-9012-bcde-f23456789012"
        element: { type: "image", content: "https://cdn.example.com/logo.png", x: 40, y: 40, width: 160, height: 60 },
        position: { above: "bg-shape" }
      },
      { op: "move", element_id: "badge", position: "top" },
      { op: "delete", element_id: "sticker-3" }
    ]
  }),
});
JSON
{
  "success": true,
  "changed": true,
  "template": {
    "id": 12345,
    "name": "Spring Sale Carousel",
    "updated_at": "2026-10-02T09:20:11.042Z",
    "pages": [
      { "page": 1, "page_id": "a1b2c3d4-...", "name": "Cover" },
      { "page": 2, "page_id": "b2c3d4e5-...", "name": "Offer" }
    ]
  },
  "results": [
    { "index": 0, "op": "add", "status": "applied", "page": 2, "page_id": "b2c3d4e5-...", "element_id": "7f6e5d4c-..." },
    { "index": 1, "op": "move", "status": "applied", "page": 2, "page_id": "b2c3d4e5-...", "element_id": "badge" },
    { "index": 2, "op": "delete", "status": "applied", "page": 2, "page_id": "b2c3d4e5-...", "element_id": "sticker-3" }
  ]
}
JSON
{
  "error": "operations[0] (update): 2 layers have parameterId \"cta\" (on pages 2, 3). Add \"page_id\" or \"page\" to pick one, or target it by element_id. Nothing was saved.",
  "code": "ambiguous_layer",
  "details": [
    { "index": 0, "op": "update", "code": "ambiguous_layer", "error": "2 layers have parameterId \"cta\" (…)" }
  ]
}

Rate Limits#

This endpoint shares the Enterprise limit of 30 requests per minute per API key with the other template endpoints.

URL Parameters#

ParameterTypeRequiredDescription
templateIdIntegerYesThe ID of the template to update

Request Body#

ParameterTypeRequiredDescription
operationsArrayYes1 to 50 layer operations, applied in order. See Operations.
base_updated_atStringNoThe template's updated_at from your last read. If the template changed since, nothing is written and you get 409. Without it, operations apply to the latest version.
embed_user_idStringNoAssign the template to an embed user, same as Update Template Modifications.

Operations#

Every operation has an op. Operations on an existing layer name it with parameter_id (a dynamic layer, as listed in the modifications of Get Studio Template) or element_id (any layer: returned in results by your own add and duplicate operations, and readable in the full design by first-party clients such as the Orshot MCP server). Add page_id or page to search one page only; it is required when the same id appears on several pages, and for add.

Page number or page id#

Anywhere an operation names a page, send either one:

FieldTypeWhat it is
page_idStringThe page's id. It never changes, so it keeps pointing at the same page after pages are added, deleted or reordered. Read it from Get Studio Template or from template.pages in any response of this endpoint.
pageIntegerThe page number, starting at 1. Simple for a one-off edit, but it changes when pages are added, deleted or moved.

If you send both, they must point at the same page, otherwise the request is refused with page_target_mismatch.

opFieldsWhat it does
addpage_id or page, element (layer object), position (optional)Adds a layer, on top by default. A missing id is generated.
duplicatelayer target, position (optional, default just above the original)Copies the layer with a new id.
replacelayer target, elementReplaces the whole layer. It keeps its id.
updatelayer target, set (object)Changes any layer fields: content, style, position, dimensions (these three merge, so { "style": { "color": "#F00" } } keeps other styles), transitions, motion, parameterId, opacity, … A null value removes the field. Flat x, y, width, height are accepted and only change what you send.
deletelayer targetDeletes the layer.
movelayer target, positionChanges the stacking order.

position is "top", "bottom", { "above": "<layer id>" } or { "below": "<layer id>" }, relative to layers on the same page. Only the moved layer changes; other layers keep their zIndex.

Layer objects use the same shape as the elements in pages_data (see Anatomy of a Template); type is one of text, image, element, shape, video, waveform. Layer operations never change page numbers.

Response Fields#

FieldTypeDescription
successBooleantrue when the request was valid
changedBooleanfalse when the operations changed nothing. Nothing is written and the version does not move.
template.idIntegerTemplate ID
template.nameStringTemplate name
template.updated_atStringThe new version. Send it as base_updated_at on your next write.
template.pagesArrayEvery page: page (number), page_id, name
template.thumbnailsObjectOnly with ?includeThumbnails=true: the new thumbnails of the changed pages
resultsArrayOne entry per operation: index, op, status (applied or unchanged), page, page_id, element_id, parameter_id when the layer has one, and source_element_id for duplicate
warningsArrayOnly when present: non-blocking notes, such as unknown motion keys

Errors#

Every error explains what to change. A 400 means nothing was saved: operations are all-or-nothing.

StatuscodeWhen
400operations_required, operations_empty, too_many_operationsoperations is missing, empty, or longer than 50
400unknown_op, invalid_operation, use_element_fieldAn operation isn't an object with a known op, or sends the layer as layer instead of element
400layer_target_required, layer_not_found, ambiguous_layer, layer_target_mismatchThe target layer is missing, doesn't exist, matches several layers, or element_id and parameter_id disagree
400page_target_required, page_not_found, invalid_page, invalid_page_id, page_target_mismatchThe page given doesn't exist, or add has no page
400invalid_layer_object, duplicate_layer_id, layer_id_mismatchThe layer object is malformed, its id is taken on that page, or it doesn't match the layer it replaces
400set_required, field_not_settableupdate has no set, or tries to change id
400position_required, invalid_positionmove without a valid position, or a position that names a layer on another page
400allow_reindex_not_applicableallow_reindex was sent; it only applies to Update Pages
400invalid_motionThe operations introduce a structural motion error
400template_too_large, no_pagesThe design would exceed 10 MB, or the template has no pages yet
403The API key, plan or trial access doesn't include this endpoint
404The template isn't in your workspace
409base_updated_at is stale: fetch the template again and redo the operations on that version
423An approval flow locks the template; see Approvals
Was this page helpful?

Ready to automate?

Start rendering images, PDFs and videos from your templates in under 2 minutes. Free plan, no credit card.

Get your API key
  • Image, PDF and video generation via API
  • Visual editor with AI and smart layouts
  • Zapier, Make, MCP and 50+ integrations
  • White-label embed for your own app
  • 100 free credits a month, no credit card required