DocumentationStudioRender PDFs with the API

Render PDFs with the API

The render batch API turns many existing Smartform records into PDFs without holding a connection open. You send the list, get a batch number back at once, check the progress, and download the result when it is ready. It is the same background generation that Generate pdf uses in Studio.

Every host on this page follows the environment you pick here.

The calls need a client with the api.external scope, as described in Authentication, and records that already exist. Create them first with dialog/json, as in Environments and languages in the API. The render batch calls are described here only: they are not listed in the API reference.


How it works

Use Create a batch when you have up to 20 documents. Use Open a batch when you have more. A batch holds up to 500 documents.


Create a batch

Send the records to render. Each one is a dialogDefinitionId, the id of the Smartform, and a dialogValuesId, the id of the record.

curl --location 'https://api.smartforms.metaforce.net/render/batches' --header 'Content-Type: application/json' --header 'Authorization: Bearer <your_token>' --header 'Idempotency-Key: <a_new_key_for_each_batch>' --data '{
"documents": [
  { "dialogDefinitionId": "653689ddc3332022ee018626", "dialogValuesId": "6697afe9b039be06934828bc" },
  { "dialogDefinitionId": "653689ddc3332022ee018626", "dialogValuesId": "6697afe9b039be06934828bd" }
],
"assembly": "Merged"
}'

The answer is 202 Accepted with the number of the batch:

{ "batchId": "9f2c4a7e51b3" }
FieldWhat it does
documents1 to 20 records. Each needs both ids.
assemblyHow the result is delivered. Single is the default and needs exactly one document. Merged gives one PDF with all documents. Zipped gives one zip file with one PDF for each document.
Idempotency-Key headerOptional. Send the same key again after a timeout and you get the same batchId back, without a second batch. Use a new key for each new batch.

The documents are rendered from the records as they are now, with the rules that hide fields applied.


Check the progress

curl --location 'https://api.smartforms.metaforce.net/render/batches/9f2c4a7e51b3' --header 'Authorization: Bearer <your_token>'
{
  "batchId": "9f2c4a7e51b3",
  "status": "Processing",
  "total": 2,
  "completed": 1,
  "failed": 0,
  "pending": 1,
  "createdAt": "2026-10-01T08:15:02+00:00",
  "completedAt": null
}
statusMeaning
OpenThe batch is still being filled. It does not finish until you seal it.
ProcessingSome documents are still being rendered.
CompletedEvery document was rendered.
CompletedWithFailuresThe batch is over and some documents failed.
CancelledThe batch was stopped.

Ask every few seconds until pending is 0 and status is no longer Processing.

To see each document, read the jobs of the batch:

curl --location 'https://api.smartforms.metaforce.net/render/batches/9f2c4a7e51b3/jobs' --header 'Authorization: Bearer <your_token>'

The answer is a list with one entry for each document, in the order you sent them. An entry has jobId, batchIndex (from 0), status, errorMessage for a failed document, and downloadable, which is true when the PDF is ready. A job status is Queued, Processing, Retrying, Completed, DeadLettered for a document that failed, or Cancelled. One job is read with GET /render/jobs/{jobId}.


Download the result

CallReturns
GET /render/jobs/{jobId}/resultThe PDF of one document.
GET /render/batches/{batchId}/resultThe whole batch, as you asked for in assembly: the one PDF for Single, one merged PDF for Merged, a zip with document-1.pdf, document-2.pdf and so on for Zipped. Documents are in the order you sent them.
curl --location 'https://api.smartforms.metaforce.net/render/batches/9f2c4a7e51b3/result' --header 'Authorization: Bearer <your_token>' --output result.pdf
  • The batch result answers 409 Conflict while documents are still being rendered, and while a batch is open.
  • If some documents failed, a Merged or Zipped result holds only the documents that worked. Do not rely on the file alone. The headers X-Batch-Total, X-Batch-Completed and X-Batch-Failed give the counts, and the jobs list shows which documents failed.
  • If no document worked, the result answers 409 Conflict.

Large jobs

When you have more than 20 documents, open a batch, add the documents in chunks of up to 20, and seal it.

  1. POST /render/batches/open with { "assembly": "Merged" }. The default is Merged, and Zipped is the other choice. Single is refused. The answer is the batchId.
  2. POST /render/batches/{batchId}/documents with { "documents": [ ... ] }, as many times as you need. The answer says how many documents were added and the new total. The optional Idempotency-Key header works here too.
  3. POST /render/batches/{batchId}/seal when the last chunk is added. The answer is the batch status. Sealing again does nothing.

An open batch never finishes. Seal it even when you think you are done, then check the progress as above.


Limits and errors

LimitValue
Documents in one request20
Documents in one batch500
Single with more than one document400 Bad Request
AnswerWhen
400 Bad RequestNo documents, more than 20, a document without both ids, a record that does not exist or belongs to another company, more than 500 documents in the batch, or Single where it is not allowed. The body has an error text.
401 UnauthorizedNo token, or an invalid token.
403 ForbiddenThe client does not have the api.external scope or is not linked to a company.
404 Not FoundThe batch or job does not exist, or belongs to another company.
409 ConflictA document is added to a batch that is sealed, or a result is asked for before it is ready.