curl --request POST \
--url https://api.parallellabs.app/api/v0/canvas/templates/render \
--header 'Content-Type: application/json' \
--header 'X-API-Key: <api-key>' \
--data '
{
"companyId": "<string>",
"templateId": "<string>",
"slots": {},
"format": "<string>",
"width": 123,
"height": 123,
"brandKitId": "<string>",
"photoUrl": "<string>"
}
'import requests
url = "https://api.parallellabs.app/api/v0/canvas/templates/render"
payload = {
"companyId": "<string>",
"templateId": "<string>",
"slots": {},
"format": "<string>",
"width": 123,
"height": 123,
"brandKitId": "<string>",
"photoUrl": "<string>"
}
headers = {
"X-API-Key": "<api-key>",
"Content-Type": "application/json"
}
response = requests.post(url, json=payload, headers=headers)
print(response.text)const options = {
method: 'POST',
headers: {'X-API-Key': '<api-key>', 'Content-Type': 'application/json'},
body: JSON.stringify({
companyId: '<string>',
templateId: '<string>',
slots: {},
format: '<string>',
width: 123,
height: 123,
brandKitId: '<string>',
photoUrl: '<string>'
})
};
fetch('https://api.parallellabs.app/api/v0/canvas/templates/render', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));<?php
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_URL => "https://api.parallellabs.app/api/v0/canvas/templates/render",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "POST",
CURLOPT_POSTFIELDS => json_encode([
'companyId' => '<string>',
'templateId' => '<string>',
'slots' => [
],
'format' => '<string>',
'width' => 123,
'height' => 123,
'brandKitId' => '<string>',
'photoUrl' => '<string>'
]),
CURLOPT_HTTPHEADER => [
"Content-Type: application/json",
"X-API-Key: <api-key>"
],
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}package main
import (
"fmt"
"strings"
"net/http"
"io"
)
func main() {
url := "https://api.parallellabs.app/api/v0/canvas/templates/render"
payload := strings.NewReader("{\n \"companyId\": \"<string>\",\n \"templateId\": \"<string>\",\n \"slots\": {},\n \"format\": \"<string>\",\n \"width\": 123,\n \"height\": 123,\n \"brandKitId\": \"<string>\",\n \"photoUrl\": \"<string>\"\n}")
req, _ := http.NewRequest("POST", url, payload)
req.Header.Add("X-API-Key", "<api-key>")
req.Header.Add("Content-Type", "application/json")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}HttpResponse<String> response = Unirest.post("https://api.parallellabs.app/api/v0/canvas/templates/render")
.header("X-API-Key", "<api-key>")
.header("Content-Type", "application/json")
.body("{\n \"companyId\": \"<string>\",\n \"templateId\": \"<string>\",\n \"slots\": {},\n \"format\": \"<string>\",\n \"width\": 123,\n \"height\": 123,\n \"brandKitId\": \"<string>\",\n \"photoUrl\": \"<string>\"\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.parallellabs.app/api/v0/canvas/templates/render")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Post.new(url)
request["X-API-Key"] = '<api-key>'
request["Content-Type"] = 'application/json'
request.body = "{\n \"companyId\": \"<string>\",\n \"templateId\": \"<string>\",\n \"slots\": {},\n \"format\": \"<string>\",\n \"width\": 123,\n \"height\": 123,\n \"brandKitId\": \"<string>\",\n \"photoUrl\": \"<string>\"\n}"
response = http.request(request)
puts response.read_body{
"imageId": "<string>",
"videoId": "<string>",
"url": "<string>",
"width": 123,
"height": 123,
"duration": 123
}{
"error": "<string>"
}{
"error": "<string>"
}{
"error": "<string>"
}Render a locked canvas template to a PNG.
Renders a locked canvas template filled with your slot text and returns a permanent public PNG URL. The layout, type sizing, margins and contrast are fixed by the template, so the result always fits its format. Costs 0.1 credits per call. List templates and their slots with GET /api/v0/canvas/templates.
curl --request POST \
--url https://api.parallellabs.app/api/v0/canvas/templates/render \
--header 'Content-Type: application/json' \
--header 'X-API-Key: <api-key>' \
--data '
{
"companyId": "<string>",
"templateId": "<string>",
"slots": {},
"format": "<string>",
"width": 123,
"height": 123,
"brandKitId": "<string>",
"photoUrl": "<string>"
}
'import requests
url = "https://api.parallellabs.app/api/v0/canvas/templates/render"
payload = {
"companyId": "<string>",
"templateId": "<string>",
"slots": {},
"format": "<string>",
"width": 123,
"height": 123,
"brandKitId": "<string>",
"photoUrl": "<string>"
}
headers = {
"X-API-Key": "<api-key>",
"Content-Type": "application/json"
}
response = requests.post(url, json=payload, headers=headers)
print(response.text)const options = {
method: 'POST',
headers: {'X-API-Key': '<api-key>', 'Content-Type': 'application/json'},
body: JSON.stringify({
companyId: '<string>',
templateId: '<string>',
slots: {},
format: '<string>',
width: 123,
height: 123,
brandKitId: '<string>',
photoUrl: '<string>'
})
};
fetch('https://api.parallellabs.app/api/v0/canvas/templates/render', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));<?php
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_URL => "https://api.parallellabs.app/api/v0/canvas/templates/render",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "POST",
CURLOPT_POSTFIELDS => json_encode([
'companyId' => '<string>',
'templateId' => '<string>',
'slots' => [
],
'format' => '<string>',
'width' => 123,
'height' => 123,
'brandKitId' => '<string>',
'photoUrl' => '<string>'
]),
CURLOPT_HTTPHEADER => [
"Content-Type: application/json",
"X-API-Key: <api-key>"
],
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}package main
import (
"fmt"
"strings"
"net/http"
"io"
)
func main() {
url := "https://api.parallellabs.app/api/v0/canvas/templates/render"
payload := strings.NewReader("{\n \"companyId\": \"<string>\",\n \"templateId\": \"<string>\",\n \"slots\": {},\n \"format\": \"<string>\",\n \"width\": 123,\n \"height\": 123,\n \"brandKitId\": \"<string>\",\n \"photoUrl\": \"<string>\"\n}")
req, _ := http.NewRequest("POST", url, payload)
req.Header.Add("X-API-Key", "<api-key>")
req.Header.Add("Content-Type", "application/json")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}HttpResponse<String> response = Unirest.post("https://api.parallellabs.app/api/v0/canvas/templates/render")
.header("X-API-Key", "<api-key>")
.header("Content-Type", "application/json")
.body("{\n \"companyId\": \"<string>\",\n \"templateId\": \"<string>\",\n \"slots\": {},\n \"format\": \"<string>\",\n \"width\": 123,\n \"height\": 123,\n \"brandKitId\": \"<string>\",\n \"photoUrl\": \"<string>\"\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.parallellabs.app/api/v0/canvas/templates/render")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Post.new(url)
request["X-API-Key"] = '<api-key>'
request["Content-Type"] = 'application/json'
request.body = "{\n \"companyId\": \"<string>\",\n \"templateId\": \"<string>\",\n \"slots\": {},\n \"format\": \"<string>\",\n \"width\": 123,\n \"height\": 123,\n \"brandKitId\": \"<string>\",\n \"photoUrl\": \"<string>\"\n}"
response = http.request(request)
puts response.read_body{
"imageId": "<string>",
"videoId": "<string>",
"url": "<string>",
"width": 123,
"height": 123,
"duration": 123
}{
"error": "<string>"
}{
"error": "<string>"
}{
"error": "<string>"
}Authorizations
Company API key - scoped to a specific company. Generate from the Integrations page in your dashboard.
Body
Template and slot text to render
Company ID whose credits are billed for the call
Template ID from GET /api/v0/canvas/templates
Slot text keyed by slot name, e.g. {"headline": "...", "supporting": "..."}. Required slots must be present; text over a slot's word limit is cut.
Named canvas format (same values as POST /api/v0/canvas, e.g. 'square', 'portrait', 'story', 'landscape'); default 'portrait'. Ignored when width/height are given.
Custom width in px (200-2160); requires height
Custom height in px (200-2160); requires width
Brand kit whose color palette and logo style the template; defaults to the company's default brand kit
Public https image URL for the template's photo zone (e.g. a stock search fullUrl); every template uses one, and without it the zone shows a brand pattern
Response
The rendered canvas with its public image URL
Rendered canvas
ID of the saved image (still canvases only)
ID of the saved video (animated canvases only)
Permanent public URL of the rendered PNG, or of the recorded MP4 when animated
Rendered width in px
Rendered height in px
Video length in seconds (animated canvases only)

