Kalpana Docs
Getting started

Modifications

How jobs and batch rows name layers and fill them with text, images and visibility.

A job, and each row of a batch, carries modifications: one flat object that maps a layer to the value it should have. Whatever you leave out keeps the page's own value.

{
  "Headline": "Weekend offer",
  "Photo": "shoe.png",
  "Badge": { "visible": false },
  "Subline": null
}

Keys

A key names a layer on the page being rendered. Take layer names and ids from Get a template summary: in pages[].nodes, each key is a layer's id and name is its name.

KeyFills
HeadlineThe layer called Headline. Names are matched without regard to case.
headlineThe same layer, by its id, if that is its id. An id always works, even when two layers share a name.
k7fq2m8a@HeadlineThe layer called Headline on page k7fq2m8a only.
k7fq2m8a#2@HeadlineIn a video (a flow), the same layer on the second time that page is shown.

Template, page and flow ids are opaque text. New ones are short, such as k7fq2m8a; older ones are UUIDs. Take them from the API and pass them back as they are.

Several pages

A job renders one page, so its plain keys name that page's layers. A key of the form <pageId>@<layer> is accepted only for the job's own page; a key that names another page is refused, because a job is one page.

A batch renders each row on every page it names (rows by pages). A plain key fills every named page that has a layer of that name, which is how one headline fills a feed post and a story at once. A <pageId>@<layer> key fills that layer on that page only and wins over a plain key:

{
  "Headline": "Weekend offer",
  "p3rtv9we@Headline": "Weekend offer, in stories"
}

A plain key that no named page has is refused, so a typo never passes silently. A layer that exists but is hidden on a page is accepted and has no effect there.

Videos

A video (a flow) joins pages, and a page may be shown more than once. Plain keys fill every page that has the layer. <pageId>@<layer> fills that layer on every visit of the page, and <pageId>#2@<layer> only on its second visit (#3 for the third, and so on). The most specific key wins: #2@ over @ over a plain key.

{
  "Price": "₹499",
  "k7fq2m8a@Headline": "Weekend offer",
  "k7fq2m8a#2@Headline": "Last chance"
}

A visit the video does not have, such as #3 for a page shown twice, is refused.

Values

Text

A string.

{ "Headline": "Weekend offer" }

A text layer that mixes styles keeps its styles. Wrap each run in the style's tag, s1, s2 and so on, in the order the design defines them:

{ "Price": "<s1>₹8,999</s1> <s2>₹12,999</s2>" }

Text without tags renders in the first style. A tag for a style the layer does not have is refused, and so are tags on a layer with a single style.

Image

An asset id, or the file name of an asset in the workspace (matched without regard to case):

{ "Photo": "0b0f5a3e-5b1c-4d65-9a5e-3f7d2f2f6c11" }
{ "Photo": "shoe.png" }

To frame the image, send an object:

{
  "Photo": {
    "asset": "shoe.png",
    "fit": "cover",
    "zoom": 1.2,
    "panX": 0.1,
    "panY": -0.05
  }
}
FieldDescription
assetAn asset id or file name. Leave it out to re-frame the page's own image without replacing it.
fitcover (fill the box and crop), contain (fit inside it) or stretch. Fill, Fit and Stretch are accepted too.
zoomA number from 0.2 to 4. 1 keeps the fit as it is.
panX, panYMove the image by a fraction of the box, from -1 to 1.
visiblefalse hides the layer.

Find an asset with List assets, or add one with Upload an asset or Upload from a URL. A file name that matches no asset, or matches more than one, is refused with asset_not_found or asset_ambiguous.

Visibility

Hide a text or image layer with { "visible": false }. A text layer can be changed and shown or hidden together:

{
  "Badge": { "visible": false },
  "Subline": { "text": "Free delivery", "visible": true }
}

Keep the page's value

null keeps the value the page, or the job, already has. It is how you leave a layer alone in one row of many, or clear an earlier change when updating a job.

{ "Subline": null }

Colours and other shape layers cannot be set through the API yet. A key for one is refused with bad_value.

What is refused

Every problem across every job or row is collected and returned together in one 400, so you fix a request in one pass. Each entry in data.issues has a field (the key), a code and a message, plus job (the item's index) for jobs or row for batch rows.

codeMeaning
unknown_layerNo layer has that name or id on the page.
ambiguous_layerTwo layers on the page share the name. The message lists their ids; use one.
unknown_pageA <pageId>@ key names a page the request does not render.
unknown_visitA #n visit the video does not have, or a #n key on something that is not a video.
type_mismatchA value of the wrong kind for the layer, such as text for an image.
bad_valueA malformed value: an unknown field, a zoom out of range, the same layer given twice, or an engine node_type object.
asset_not_found, asset_ambiguousAn image reference that matches no asset, or several.

The same layer given twice, for example Headline and headline, is refused. Send each layer once.

Limits

A job request carries at most 10 jobs and a batch at most 1,000 rows. A request body is at most 4 MiB; a larger one is refused with 413 and Request exceeds 4 MiB..

Was this page helpful?

Updated 9 Nov 2026

On this page