Batches
Check rows, stage a batch with its credit cost, run it, follow it and collect the files.
validate_batch
Checks rows against what the batch would render (pages, every page of some templates, or a flow's video) before anything is saved. It reports every problem by row and field, and shows each row as the server understood it on each page, so a misread value shows before any credits are spent. It runs the same checks as create_batch, and also returns the jobs the batch would make and their creditCost.
A batch renders exactly one of:
pages: page ids (fromget_template_inputs, and from any templates). Each row renders once per page.templates: template ids. Each row renders once on every page of each template, in page order.flow: one flow, a video joining some of its template's pages. Each row renders as that video, with a video output format.
Each of rows (1 to 1,000) is an object with its own modifications and output. templateId, pageIds, flowIds, columns, defaults, and a batch-level outputFormat or stillTime are no longer accepted, and a request that sends one is refused.
modifications key a layer by its name (case-insensitive) or its id, the key that get_template_inputs gives, and take plain values:
- Text layer: a string (
"Diwali Sale"), or{ text, visible }. When the layer has several styles (stylesinget_template_inputs), mark runs with their tags:"<s1>Big</s1> <s2>sale on</s2> <s1>shoes</s1>". A style can repeat, in any order, and the server turns each run into a span in that style. Untagged text iss1, except whitespace between runs, which keeps the run before it. Tags do not nest;\<s1>is a literal<s1>. - Image layer: a string (an asset id, the image's file name with or without its extension, or a designer image key), or
{ asset, fit, zoom, panX, panY, visible }.fitiscover(the default: fills the slot and crops),contain(shows the whole image) orstretch;fillandfitare accepted ascoverandcontain.zoomis 0.2 to 4, about the slot's centre, where 1 is none.panXandpanYare -1 to 1, a fraction of the slot's width or height; positive moves the image right or down. Leaving outassetkeeps the template's image and only re-frames it. - Hide a layer:
{ "visible": false }. - One page: with several pages, a plain key fills every page that has the layer, and a key no page has is refused. Write
<pageId>@<layer>to fill only that page, such ask7fq2m8a@Headline. - A page visited twice in a video:
<pageId>#2@<layer>fills a page's second visit. null: leaves the layer at the page's own value. Layers left out ofmodificationskeep it too.
output is { format, fileName, stillTime }, and every field is optional (the format is png when omitted):
format:png,jpegorwebprender an image.mp4orgifrender the whole motion as a video. Video needs an animated template (isAnimated) and costs credits by its length and size. A flow needs a video format.fileName: the file's name, without extension, up to 200 characters.stillTime: for an image of an animated page, the second of the motion to show, from 0 to 600. Omit it to use the page's own still time, else the last frame. Refused with a video format.
A row for a three-page carousel, with a page key, an image object and a null:
{
"pages": ["k7fq2m8a", "p3x9d1we", "h5n8c4ty"],
"rows": [
{
"modifications": {
"Headline": "Diwali Sale",
"Product photo": { "asset": "kurta-red.jpg", "fit": "contain", "zoom": 1.2, "panY": -0.1 },
"p3x9d1we@Headline": "Up to 40% off",
"Brand logo": null
},
"output": { "format": "png", "fileName": "diwali-red-kurta" }
}
]
}A video row, where the second time the flow visits a page it shows different copy and one layer is hidden:
{
"flow": "r2m6v0qb",
"rows": [
{
"modifications": {
"Headline": "Festive Offer",
"k7fq2m8a#2@Headline": { "text": "Last 3 days", "visible": true },
"Badge": { "visible": false }
},
"output": { "format": "mp4", "fileName": "festive-offer-video" }
}
]
}When two layers share a name, rows that use that name are refused with ambiguous_layer and both ids. The agent fills each layer by id and tells the user, who can rename one of them in Kalpana.
-
Annotations:
readOnlyHint: true,destructiveHint: false,idempotentHint: true,openWorldHint: false -
Input Parameters (exactly one of
pages,templatesandflow):Parameter Type Required Description pagesstring[]One of these 1 to 20 page ids, from any templates. templatesstring[]One of these 1 to 20 template ids; every page of each. flowstringOne of these One flow id, rendered as a video. rowsArray<{ modifications, output? }>Yes 1 to 1,000 rows. modificationsdefaults to{};outputis{ format, fileName, stillTime }. -
Output Schema:
{ valid: boolean; rowCount: number; validRows: number; invalidRows: number; jobCount: number; // Jobs the batch makes: one per row per page creditCost: number; // Credits those jobs spend when they render issues: Array<{ row: number; // Zero-based position in rows field: string; // The modifications key the problem is in code?: string; // For example "unknown_layer", "ambiguous_layer", "bad_value", "type_mismatch", "asset_not_found" message: string; }>; rows: Array<{ // Each row as the server understood it, on each page row: number; pages: Array<{ page: string; // The page, or the flow for a video modifications: Record<string, unknown>; // By layer: text as strings, images as { asset: <id>, name: <file name>, fit?, ... } }>; }>; warnings?: string[]; // Not errors: pass these on to the user, such as a flow longer than a video renders }
An answer with issues, for a row that names a layer the page does not have and an image the workspace cannot find:
{
"valid": false,
"rowCount": 2,
"validRows": 1,
"invalidRows": 1,
"jobCount": 2,
"creditCost": 2,
"issues": [
{ "row": 1, "field": "Hedline", "code": "unknown_layer", "message": "No layer named \"Hedline\" on page k7fq2m8a." },
{ "row": 1, "field": "Product photo", "code": "asset_not_found", "message": "No image \"kurta-green.jpg\" in this workspace." }
],
"rows": [
{
"row": 0,
"pages": [
{
"page": "k7fq2m8a",
"modifications": {
"Headline": "Diwali Sale",
"Product photo": { "asset": "5f0c2a8e-3b1d-4c6a-9e7f-2d84a1b6c0e3", "name": "kurta-red.jpg" }
}
}
]
}
]
}create_batch
Saves a new draft batch with one pending job per row for each page (from pages, or every page of templates), or one video per row for a flow. Does not spend credits or start rendering. Every call makes a separate batch, so repeating a call duplicates it, and one invalid row rejects the whole request with nothing saved. Rows are checked as in validate_batch.
create_batch calculates the exact credit cost required to run the batch. The agent must present this number to the user before calling run_batch.
-
Annotations:
readOnlyHint: false,destructiveHint: false,idempotentHint: false,openWorldHint: false -
Input Parameters (exactly one of
pages,templatesandflow):Parameter Type Required Description namestringYes Batch name shown in Kalpana and used in output file names, 1 to 200 characters. pagesstring[]One of these 1 to 20 page ids, from any templates. templatesstring[]One of these 1 to 20 template ids; every page of each. flowstringOne of these One flow id, rendered as a video. rowsArray<{ modifications, output? }>Yes 1 to 1,000 rows, as in validate_batch. -
Output Schema:
{ id: string; // Created batch UUID status: string; // "draft" until run_batch rowCount: number; // Rows given jobCount: number; // Jobs created: one per row per page creditCost: number; // Exact number of credits required to run }
run_batch
Dispatches rendering jobs for a pending batch. Consumes credits from the workspace's organization. A draft batch is published when it runs; if the run fails, it stays a draft. When the balance is too low nothing is queued and the error says there are not enough credits. An archived batch is refused, and a batch with a pending job on a deleted template returns Template not found and queues nothing. Jobs reset to pending by update_batch or update_job render on the next call.
-
Annotations:
readOnlyHint: false,destructiveHint: true,idempotentHint: true,openWorldHint: false -
Input Parameters:
Parameter Type Required Description batchIdstringYes UUID returned by create_batch.webhooksbooleanNo Whether the run sends batch.completedandjob.completedto the workspace's webhook endpoints. Omit to keep the batch's setting, which is on. -
Output Schema:
{ message: string; dispatched: number; // Number of jobs queued for rendering failed: number; // Number of jobs that failed dispatch }
get_batch
Returns a batch's progress and its job counts. A batch has one job per row and page, so 10 rows on 3 pages is 30 jobs.
-
Annotations:
readOnlyHint: true,destructiveHint: false,idempotentHint: true,openWorldHint: false -
Input Parameters:
Parameter Type Required Description batchIdstringYes UUID of the batch. -
Output Schema:
{ id: string; workspaceId: string; name: string; createdAt: string; jobs: { // one job per row and page total: number; succeeded: number; // rendered, with a file failed: number; processing: number; cancelled: number; pending: number; // waiting for run_batch }; status: "pending" | "processing" | "completed" | "partial" | "failed" | "cancelled"; }statusisprocessingwhile any job renders andpendingwhile jobs wait forrun_batch. Once every job has finished it iscompletedwhen all rendered,partialwhen some rendered and others failed or were cancelled,failedwhen none rendered and at least one failed, andcancelledwhen none rendered, none failed and at least one was cancelled. The counts carry the detail.
list_batches
Returns a paginated list of recent batches in the connected workspace. total counts every match, so it also answers how many batches exist.
-
Annotations:
readOnlyHint: true,destructiveHint: false,idempotentHint: true,openWorldHint: false -
Input Parameters:
Parameter Type Required Default Description searchstringNo — Optional search filter for batch name. templateIdstringNo — Optional template filter. pagenumberNo 1Page number. limitnumberNo 10Items per page (capped at 20). -
Output Schema:
{ items: Array<{ id: string; workspaceId: string; name: string; createdAt: string; jobs: { // one job per row and page total: number; succeeded: number; // rendered, with a file failed: number; processing: number; cancelled: number; pending: number; // waiting for run_batch }; status: "pending" | "processing" | "completed" | "partial" | "failed" | "cancelled"; }>; total: number; page: number; limit: number; }
get_batch_jobs
Lists a batch's jobs in row order, each row's pages together, one page of results at a time. Each job is shown as in Single jobs, with its modifications (the values it renders, by layer), status, render error and file. A job is editable while it is pending and has no file; processing, rendered and failed jobs cannot change. These job ids and values are the input for update_batch and update_job.
-
Annotations:
readOnlyHint: true,destructiveHint: false,idempotentHint: true,openWorldHint: false -
Input Parameters:
Parameter Type Required Default Description batchIdstringYes — UUID of the batch. pagenumberNo 1Page number. A page past the end is empty. limitnumberNo 10Jobs per page (capped at 20). -
Output Schema:
{ jobs: Array<Job>; // As in Single jobs total: number; page: number; limit: number; }
get_batch_outputs
Fetches download URLs for completed creative renders. Download links are pre-signed and short-lived.
-
Annotations:
readOnlyHint: true,destructiveHint: false,idempotentHint: true,openWorldHint: false -
Input Parameters:
Parameter Type Required Default Description batchIdstringYes — UUID of the completed batch. pagenumberNo 1Page number. limitnumberNo 10Items per page (capped at 20). -
Output Schema:
{ items: Array<{ id: string; // Job UUID rowIndex?: number; // The job's row in the batch, from 0; one row's pages and flows share it flowId?: string | null; // The flow this job renders, if any status: "pending" | "processing" | "success" | "failed" | "cancelled"; outputKind: "image" | "video"; outputFormat: "png" | "jpeg" | "webp" | "mp4" | "gif"; contentType: string | null; downloadUrl: string | null; // Pre-signed download link }>; page: number; limit: number; }
update_batch
Renames a batch and changes, adds or removes its pending jobs in one request. It works on any batch that is not archived, but only pending jobs change: processing, rendered and failed jobs are refused. update merges each listed job's modifications over its own (a key given again replaces it, null clears it back to the page's value) and replaces the output fields given; unlisted jobs are untouched. add creates new jobs from rows on pages, templates or a flow, as create_batch does, so repeating a request with add duplicates them. remove deletes pending jobs permanently. Nothing renders until run_batch, and adding or removing jobs changes what it costs.
Needs templates:read and batches:create.
-
Annotations:
readOnlyHint: false,destructiveHint: true,idempotentHint: false,openWorldHint: false -
Input Parameters:
Parameter Type Required Description batchIdstringYes UUID of the batch. namestringNo New batch name, 1 to 200 characters. updateArray<{ job, modifications?, output? }>No Pending jobs to change, up to 1,000. jobis the id fromget_batch_jobs;modificationsholds only the layers to change;outputholds only the output fields to change.add{ pages | templates | flow, rows }No New rows, with the same target and rows as create_batch.removestring[]No Ids of pending jobs to delete permanently, up to 1,000. -
Output Schema:
{ id: string; added: number; updated: number; removed: number; }
Rename a batch, correct one job's headline, clear a logo back to the page's value, switch another job to a webp and drop a job:
{
"batchId": "6b0e7c1a-52d4-4f0b-8a39-1c7d9e2f4a65",
"name": "Diwali sale, kurtas",
"update": [
{
"job": "0d3f9a7e-8b21-4c5d-a6e4-93b1c27f5d08",
"modifications": { "Headline": "Diwali Sale, 40% off", "Brand logo": null }
},
{ "job": "9a4c1e6b-37d2-4f80-b5a9-6e0d8c3f1b72", "output": { "format": "webp" } }
],
"remove": ["c18e5d02-4a7b-49f3-8e6d-2b9f0a7c3e41"]
}update_job
Changes one pending job that has no file yet, in a batch or on its own. modifications merge over the job's own (a key given again replaces it, null clears it back to the page's value) and output fields replace the job's, so repeating the same request gives the same result. Failed, processing and rendered jobs are refused. Switching the format to mp4 or gif makes it a video job, which needs an animated page and costs credits by its length and size. Does not render. For several jobs at once, or to add and remove jobs, use update_batch.
-
Annotations:
readOnlyHint: false,destructiveHint: true,idempotentHint: true,openWorldHint: false -
Input Parameters:
Parameter Type Required Description jobIdstringYes UUID of the pending job. modificationsobjectNo Only the layers to change, keyed and valued as in validate_batch;nullclears one.output{ format?, fileName?, stillTime? }No Only the output fields to change. -
Output Schema: the job.
cancel_batch
Stops a batch: every job still pending or processing becomes cancelled. A cancelled job is final and is not charged; a render already under way may finish, but its result is discarded. Jobs that already rendered keep their output and their charge. Cancelled jobs cannot be resumed: to render them again, create a new batch with those rows. get_batch shows the cancelled count, and repeating the call cancels nothing more.
Needs batches:create on the connection and renders:create in the user's workspace role.
-
Annotations:
readOnlyHint: false,destructiveHint: true,idempotentHint: true,openWorldHint: false -
Input Parameters:
Parameter Type Required Description batchIdstringYes Batch ID returned by create_batchorlist_batches. -
Output Schema:
{ cancelled: number; // Jobs this call cancelled; 0 when they had all finished stoppedMessages: number; // Queued renders removed before they started }
Cancelling cannot be undone. Agents confirm with the user before calling cancel_batch or cancel_job.
cancel_job
Stops one job that is pending or processing: it becomes cancelled, final and not charged; a render already under way may finish, but its result is discarded. A job that already finished is left as it is. Other jobs in its batch keep rendering; cancel_batch stops them all.
Needs batches:create on the connection and renders:create in the user's workspace role.
-
Annotations:
readOnlyHint: false,destructiveHint: true,idempotentHint: true,openWorldHint: false -
Input Parameters:
Parameter Type Required Description jobIdstringYes Job ID from get_batch_jobs. -
Output Schema:
{ cancelled: number; // 1 when this call cancelled the job; 0 when it had already finished stoppedMessages: number; // Queued renders removed before they started }
Updated 10 Nov 2026