This is the first successful POST /api/v1/render — not a second homepage. Create an API key, send a template id and optional layer overrides, wait up to 60 seconds, download the file. 25 images are free; no card.
Overview
Every product team needs generated images at some point: Open Graph cards for blog posts, product banners for thousands of SKUs, certificates, ad creatives for A/B tests, personalized email headers. You have three options — design them by hand in Figma or Canva (doesn’t scale past a few images), run a headless browser like Puppeteer (high maintenance and expensive), or use a purpose-built image generation API.
jsontoimg is the third option, stripped to its core job: JSON in, image out. You design a template once, send JSON data, and get back a rendered PNG, JPG, WebP, AVIF, or PDF, at any volume.
This tutorial gets you from zero to your first rendered image in about five minutes. By the end you’ll have:
- A simple template defined in JSON
- Your first API call with
curl - Working examples in Node.js and Python
- A batch job generating multiple images in one request
No prior image-generation experience needed. If you know what a POST request is, you’re ready.
What “JSON to Image” Actually Means
The core idea is a three-part pipeline:
Design a template (once)
→ Send JSON data (every time)
→ Get an image back (instantly)
A template is a design with placeholders — dynamic text, images, and colors you control through the API. Your data is plain JSON that fills those placeholders. The render is the image that comes out.
The power is in the separation: you design the visual once, then any system that can send JSON — a CMS, a database, a spreadsheet, a webhook — can produce branded images without touching a design tool. This is the same pattern every serious template-based image API uses: Bannerbear sends a modifications array against a template (Bannerbear API Quick Start), Placid sends layers against a template_uuid (Placid REST API docs), and Pixelixe describes it as “one JSON request, one rendered output, unlimited reuse” (Pixelixe JSON to Image API). jsontoimg follows the same convention, so if you’ve used any of them, the mental model transfers immediately.
Before You Start
You need two things:
- A jsontoimg account and API key — grab your key from the dashboard. It’s a bearer token; keep it server-side and never in client code.
- A way to make HTTP requests —
curlworks for testing. For real integrations, Node.js 18+ (nativefetch) or Python 3 withrequestsare covered below.
Step 1: Design Your First Template
Templates are JSON documents that describe the canvas: dimensions, background, and layers. Here’s a minimal branded card — a 1200×630 social share image with a gradient background, a headline, and a subtitle:
{
"width": 1200,
"height": 630,
"background": {
"type": "gradient",
"colors": ["#1a1a2e", "#16213e", "#0f3460"]
},
"layers": [
{
"type": "text",
"name": "headline",
"text": "Your headline goes here",
"font": { "size": 72, "weight": "bold", "color": "#ffffff" },
"position": { "x": 80, "y": 200 },
"width": 1040,
"align": "left"
},
{
"type": "text",
"name": "subtitle",
"text": "Your subtitle goes here",
"font": { "size": 36, "color": "#a0aec0" },
"position": { "x": 80, "y": 330 },
"width": 1040,
"align": "left"
}
]
}
A few things to note:
nameis the layer’s ID — you’ll reference it in every API call. Keep it stable:headline,subtitle,logo,price.textis the default value. The API overrides it per request, but a sensible default makes the template testable in the editor.- Text styling — size, weight, color, alignment, and wrapping are all first-class properties. You can also add image layers (for logos and photos) and shape layers (for badges and dividers).
Once saved, the template gets a template ID that you’ll use in all render calls.
Step 2: Make Your First API Call
With the template saved, generating an image is a single POST to the render endpoint:
POST https://app.jsontoimg.com/api/v1/render
Here’s the same request with curl:
curl -X POST "https://app.jsontoimg.com/api/v1/render?wait=60" \
-H "Authorization: Bearer $JSONTOIMG_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"template": "social-share-card",
"format": "png",
"layers": {
"headline": { "text": "Launching the New Dashboard" },
"subtitle": { "text": "Real-time analytics for your team" }
}
}'
The response is small and predictable:
{
"id": "rnd_a1b2c3",
"status": "done",
"format": "png",
"assetUrl": "https://app.jsontoimg.com/api/v1/renders/rnd_a1b2c3/asset?sig=..."
}
The image_url is the finished PNG, ready to host, serve, or upload anywhere. You’re done — that’s the whole first call.
Node.js
const JSONTOIMG_API_KEY = process.env.JSONTOIMG_API_KEY;
async function renderImage() {
const response = await fetch('https://app.jsontoimg.com/api/v1/render?wait=60', {
method: 'POST',
headers: {
'Authorization': `Bearer ${JSONTOIMG_API_KEY}`,
'Content-Type': 'application/json'
},
body: JSON.stringify({
template: 'social-share-card',
format: 'png',
layers: {
headline: { text: 'Launching the New Dashboard' },
subtitle: { text: 'Real-time analytics for your team' }
}
})
});
const data = await response.json();
console.log(data.assetUrl);
}
renderImage();
Python
import os
import requests
API_KEY = os.environ['JSONTOIMG_API_KEY']
response = requests.post(
'https://app.jsontoimg.com/api/v1/render',
headers={
'Authorization': f'Bearer {API_KEY}',
'Content-Type': 'application/json'
},
json={
'template': 'social-share-card',
'format': 'png',
'layers': {
'headline': { 'text': 'Launching the New Dashboard' },
'subtitle': { 'text': 'Real-time analytics for your team' }
}
}
)
print(response.json()['assetUrl'])
Step 3: Sync vs Async vs Webhooks
Rendering a single image is fast — usually a second or two — so the synchronous call above is all you need for most cases. But at volume you’ll want the async patterns that production integrations use. Here’s how the three modes compare:
| Mode | How it works | Best for |
|---|---|---|
| Synchronous | Connection stays open; image_url returned in the response |
Simple renders, low volume, Lambda/edge functions |
| Async + polling | Response returns job_id and status: "queued"; you poll a status endpoint |
Large or complex renders where you don’t want to hold the connection |
| Webhook | Pass webhook_url; jsontoimg POSTs the finished image to your endpoint |
High-volume batch pipelines, event-driven systems |
For polling, the response looks like this:
{
"status": "queued",
"job_id": "job_8f3k2m"
}
Then you poll until the job completes:
curl -X GET "https://app.jsontoimg.com/api/v1/renders/rnd_8f3k2m" \
-H "Authorization: Bearer $JSONTOIMG_API_KEY"
A common production pattern is exponential backoff — poll at 1s, 2s, 4s, 8s — rather than hammering the endpoint every second (Wireflow’s developer guide covers exactly this trade-off). And for anything beyond a few seconds of processing, webhooks are the standard recommendation: your server gets notified when the job completes instead of polling at all (Apiframe’s 2026 API roundup). Bannerbear and Placid offer the same dual pattern — poll a GET endpoint or receive a webhook POST (Bannerbear help, Placid docs).
Step 4: Generate Your First Batch
Single renders are nice; batches are where the API earns its keep. Send an array of renders in one request:
const response = await fetch('https://app.jsontoimg.com/api/v1/renders/batch', {
method: 'POST',
headers: {
'Authorization': `Bearer ${JSONTOIMG_API_KEY}`,
'Content-Type': 'application/json'
},
body: JSON.stringify({
jobs: [
{
template: 'social-share-card',
format: 'png',
layers: {
headline: { text: 'Post 1: The Ultimate Guide' },
subtitle: { text: 'Everything you need to know' }
}
},
{
template: 'social-share-card',
format: 'png',
layers: {
headline: { text: 'Post 2: Case Study' },
subtitle: { text: 'How one team scaled to 10K images' }
}
}
]
})
});
const results = await response.json();
// GET /api/v1/renders/batches/{id}; each done job has assetUrl
One template, hundreds of variations, one request. This is the workflow behind the big use cases on the site:
- Auto-generate Open Graph images at scale
- Product banners for thousands of SKUs
- Certificate generation
- Social media post automation
If you’re evaluating whether template-based rendering is the right pattern for your stack at all, the Abyssale comparison of template-based image APIs is a good industry overview — and the jsontoimg vs Bannerbear and jsontoimg vs Placid pages cover where the trade-offs land.
Common Mistakes and How to Fix Them
| Error / symptom | Likely cause | Fix |
|---|---|---|
401 Unauthorized |
Wrong or missing API key | Confirm Authorization: Bearer ; never hardcode keys in client code |
404 template not found |
Typo in template |
Copy the ID from the dashboard exactly |
| Render succeeds but text is unchanged | name doesn’t match a layer |
The modification name must equal a layer name in the template |
| Text clipped or overflowing | Font too large for the layer width | Check font.size against the layer width and align settings |
| Slow responses on big batches | Many heavy renders in one call | Use the batch endpoint with a webhook_url and process asynchronously |
| Rate limit errors | Too many requests per second | Add backoff; the async/webhook path is more forgiving at volume |
Next Steps
You’ve made your first call. The natural next step is to wire this into a real workflow:
- Read the use case guides — OG images, email hero images, event tickets show the full pipelines.
- Build something — the product banner generator walkthrough takes the batch pattern above and points it at a real product catalog.
- Compare options — if you’re still deciding between providers, the comparison series covers the honest trade-offs.
And if you’re curious about the technical story behind why a JSON-driven API beats a headless browser, check out Why I Built a JSON-to-Image API Instead of Using Puppeteer (coming soon) — spoiler: it’s the cost and the ops burden.
Key Takeaways
- JSON in, image out — a template + a JSON payload is all you need to generate branded images at scale
- Design once, render forever — templates separate the visual design from the data, so any system that speaks JSON becomes an image generator
- The API is one POST —
template+layers→assetUrl; the same convention as Bannerbear, Placid, and Pixelixe - Pick the right mode — synchronous for simple renders, polling for long jobs, webhooks for production pipelines
- Batch is where scale happens — one request, hundreds of images
- First render in ~5 minutes — template →
curl→ done
FAQ
What do I need before my first render?
An account, an API key, and one template with its changing layers named. Every account starts with 25 free API images and no card, so you can get through a first call before deciding anything.
What does the minimal JSON to image request look like?
A POST /api/v1/render with the template ID and an object of layer names to values. Layers you do not mention keep the defaults you set in the editor.
Why is my render returning 422?
Almost always a layer name that does not exist in the template — a typo or a layer renamed in the editor. The API rejects unknown keys instead of quietly rendering an image with a missing field.
When should I move from single renders to the batch endpoint?
As soon as you are rendering a list rather than one image. POST /api/v1/renders/batch takes up to 50 jobs per request and can report back by webhook.
Do failed calls use up my free images?
No. Credits are spent on successful renders only, and designing in the editor with watermarked previews does not touch them at all.
Related Resources
- Auto-Generate Open Graph Images at Scale — use case guide
- Product Banners for Thousands of SKUs — batch workflow
- Building a JSON-to-Image Converter: Turn Data into Shareable Visuals — a worked example on the blog
- jsontoimg vs Bannerbear — comparison
- Bannerbear API Quick Start — reference for the industry-standard pattern
- Placid REST API docs — another take on template-based rendering
Next: docs, named layers, pricing.
Zoom out: How JSON-to-Image Conversion Works maps the whole template, named-layer, and render-job architecture.