Render image

7 min readOctober 17, 2025

This endpoint allows you to render images and PDF files based on a template created in Template Editor and your properties.

POST Endpoint

https://get.renderform.io/api/v2/render

Looking for the v1 endpoint? Want to render a video?

Sample request

curl --request POST \
     --url https://get.renderform.io/api/v2/render \
     --header 'X-API-KEY: <API_KEY>' \
     --header 'Content-Type: application/json' \
     --data '{
            "template": "<TEMPLATE_ID>",
            "data": {
              "my-text-component-id.color": "#eeeeee",
              "my-text-component-id.text": "Hello {John}!",
              "my-image-component-id.src": "https://my-blog.com/my-image.jpg"
            }
        }'

Request body

  • template (required) - template identifier
  • data (optional) - values for the template properties
  • fileName (optional) - custom file name for generated image
  • webhookUrl (optional) - send response to the given URL as a POST request
  • metadata (optional) - any key-value object can be used as metadata container
  • version (optional) - used as cache differentiator, if you want to force re-rendering of the template
  • cache (optional) - set to false to skip the render cache and always render a fresh file
  • width (optional) - width of the generated image
  • height (optional) - height of the generated image
  • waitTime (optional) - time in milliseconds to wait before rendering, useful for HTML templates
  • outputFormat (optional) - file format of the result: jpeg, png, webp, pdf, or mp4 / webm for video templates

Custom dimensions

You can specify the width and height of the generated image by providing the width and height properties in the request body. Output image will be cropped to the specified dimensions where the starting point is the top left corner.

curl --request POST \
     --url https://get.renderform.io/api/v2/render \
     --header 'X-API-KEY
      --header 'Content-Type: application/json' \
      --data '{
          "template": "<TEMPLATE_ID>",
          "data": {
            "my-text-component-id.text": "Hello {John}!",
            "my-image-component-id.src": "https://my-blog.com/my-image.jpg"
          },
          "width": 800,
          "height": 600
      }'

Successful response

Successful response always returns 200 status code, requestId, and href property with url to the rendered result.

{
  "requestId": "febbd34c-cadf-43e6-926c-5942016aea4e",
  "href": "https://cdn.renderform.io/.../febbd34c-cadf-43e6-926c-5942016aea4e.jpg"
}

Error response

Unsuccessful response always returns 400 status code, an error message with details about the error in msg property and status with the HTTP status code.

{
  "msg": "Template not found",
  "status": 400
}

Sample request with metadata

Metadata field allows you to store any JSON object with the generated image.

curl --request POST \
     --url https://get.renderform.io/api/v2/render \
     --header 'X-API-KEY: <API_KEY>' \
     --header 'Content-Type: application/json' \
     --data '{
        "template": "<TEMPLATE_ID>",
        "data": {
          "my-text-component-id.color": "#eeeeee",
          "my-text-component-id.text": "Hello {John}!",
          "my-image-component-id.src": "https://my-blog.com/my-image.jpg"
        },
        "metadata": {
            "userId": "12345",
            "userName": "John Doe",
            "my-custom-key": "Hello World!"
        }
    }'

Sample request for HTML template

HTML template can be rendered using the same endpoint as an image. The only difference is that you skip the Component ID part as HTML templates doesn't have any components.

curl --request POST \
     --url https://get.renderform.io/api/v2/render \
     --header 'X-API-KEY: <API_KEY>' \
     --header 'Content-Type: application/json' \
     --data '{
        "template": "<TEMPLATE_ID>",
        "waitTime": 2000, //optional, time in milliseconds to wait before rendering
        "data": {
          "my-property": "#eeeeee",
          "my-text": "Hello {John}!",
          "my-image": "https://my-blog.com/my-image.jpg"
        }
    }'

Sample request with webhook execution

webhookUrl can be used to send the response to the given URL as a POST request after the image or PDF is rendered.

curl --request POST \
     --url https://get.renderform.io/api/v2/render \
     --header 'X-API-KEY: <API_KEY>' \
     --header 'Content-Type: application/json' \
     --data-raw '{
        "template": "<TEMPLATE_ID>",
        "webhookUrl": "https://my-service.com/webhook-receiver"
        "data": {
          "my-property": "#eeeeee",
          "my-text": "Hello {John}!",
          "my-image": "https://my-blog.com/my-image.jpg"
        }
    }'

RenderForm will respond immediately with requestId and a link where the rendered image will be saved.

{
    "requestId": "febbd34c-cadf-43e6-926c-5942016aea4e"
    "href": "https://cdn.renderform.io/8af2cacf-a328-4a8f-a4a7-fc6419b5b805/results/febbd34c-cadf-43e6-926c-5942016aea4e.jpg"
}

After a successful render, RenderForm will send a request to the given webhookUrl with requestId, href and request which has been sent to render the image.

{
    "requestId": "febbd34c-cadf-43e6-926c-5942016aea4e"
    "href": "https://cdn.renderform.io/8af2cacf-a328-4a8f-a4a7-fc6419b5b805/results/febbd34c-cadf-43e6-926c-5942016aea4e.jpg"
    "request": {
      //your request
    }
}

You can also configure a global webhook in the settings that will be triggered for every render request.

Render cache

Rendering the exact same thing twice returns the file that was already produced, instead of rendering it again. A cached response comes back in milliseconds and costs no credits:

{
    "requestId": "febbd34c-cadf-43e6-926c-5942016aea4e",
    "href": "https://cdn.renderform.io/8af2cacf-a328-4a8f-a4a7-fc6419b5b805/results/febbd34c-cadf-43e6-926c-5942016aea4e.jpg",
    "cached": true
}

Two requests are "the same" when everything that affects the produced file is the same: the template and its current version, your data, and the output settings (outputFormat, width, height, fileName, waitTime, and so on). Fields that only describe how you want to be notified or how the request should be grouped do not split the cache - webhookUrl, metadata and batchName can differ freely and you will still get the cached file. A webhookUrl is still called for a cached render, so webhook-based workflows keep working unchanged.

Editing the template invalidates its cached renders immediately. Entries otherwise expire after 7 days.

To force a fresh render - for example when your template pulls in content that changes on its own - send "cache": false, or change the version field:

curl --request POST \
     --url https://get.renderform.io/api/v2/render \
     --header 'X-API-KEY: <API_KEY>' \
     --header 'Content-Type: application/json' \
     --data '{
            "template": "<TEMPLATE_ID>",
            "cache": false,
            "data": {
              "my-text-component-id.text": "Hello!"
            }
        }'

A request sent with "cache": false is not stored either, so a template that renders differently every time never ends up serving a stale file to anyone else.

GET Endpoint

https://get.renderform.io/img/TEMPLATE_ID.jpg?componentId.property=value&apiKey=API_KEY

Use Query String notation in order to provide changes.

Sample request

https://get.renderform.io/img/TEMPLATE_ID.jpg?title.text=Hello!&avatar.src=example.com/me.jpg&apiKey=MY_API_KEY

Please note that only the first element is separated with ? (question mark) and all other changes must be separated with & (ampersand).