AI text, images and translation
Let AI write a layer's text, make its image or translate every text layer while a template renders. The keys, options, limits, costs and errors.
A text or image layer can be filled by AI when the template renders. You send a prompt, and JamFrame writes the text or makes the picture, then renders the file. You can also translate all the text of a render into another language. This page covers the API side. To set up AI layers in the editor, see AI layers.
Before you start
AI works on layers that have a key (a dynamic field), such as headline or photo. A layer can get its
prompt in two ways:
- In the editor, in the layer’s AI section. Then a normal render fills it, and you don’t need to send anything extra.
- In the request, with a
.promptkey. This works on any text or image layer with a key, even one with no AI set up.
The layer’s own text or image is its saved fallback. It shows wherever AI doesn’t run.
Send a prompt with a render
This request writes the headline with AI, makes the photo with AI, and translates the result into Spanish:
curl https://api.jamframe.com/v1/render \
-H "Authorization: Bearer $JAMFRAME_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"templateId": "YOUR_TEMPLATE_ID",
"modifications": {
"product": "Cold brew",
"headline.prompt": "Write a 6-word headline about {{product}}",
"headline.tone": "playful",
"photo.prompt": "A glass of {{product}} on a marble table, morning light",
"photo.style": "photo"
},
"translate": true,
"lang": "es",
"ai": { "onError": "fallback" }
}'const res = await fetch("https://api.jamframe.com/v1/render", {
method: "POST",
headers: {
Authorization: `Bearer ${process.env.JAMFRAME_API_KEY}`,
"Content-Type": "application/json",
},
body: JSON.stringify({
templateId: "YOUR_TEMPLATE_ID",
modifications: {
product: "Cold brew",
"headline.prompt": "Write a 6-word headline about {{product}}",
"headline.tone": "playful",
"photo.prompt": "A glass of {{product}} on a marble table, morning light",
"photo.style": "photo",
},
translate: true,
lang: "es",
ai: { onError: "fallback" },
}),
});
const { data, warnings } = await res.json();
console.log(data.content, data.aiCredits, warnings);import os
import requests
res = requests.post(
"https://api.jamframe.com/v1/render",
headers={"Authorization": f"Bearer {os.environ['JAMFRAME_API_KEY']}"},
json={
"templateId": "YOUR_TEMPLATE_ID",
"modifications": {
"product": "Cold brew",
"headline.prompt": "Write a 6-word headline about {{product}}",
"headline.tone": "playful",
"photo.prompt": "A glass of {{product}} on a marble table, morning light",
"photo.style": "photo",
},
"translate": True,
"lang": "es",
"ai": {"onError": "fallback"},
},
)
body = res.json()
print(body["data"]["content"], body["data"].get("aiCredits"))The answer is a normal render answer, plus aiCredits: the AI credits this render used.
{
"data": {
"content": "https://cdn.jamframe.com/renders/…/1d2e3f4a.png?Expires=…",
"expiresAt": "2026-11-14T12:05:00.000Z",
"type": "url",
"format": "png",
"pages": [1],
"credits": 1,
"renderId": "clx8n0q1r0009abcd1234efgh",
"responseTime": 6240,
"aiCredits": 6
}
}
For every other render option, see Render images and PDFs.
AI keys
Add these keys to modifications. Replace headline and photo with your own layer keys.
| Key | Layers | What it does |
|---|---|---|
headline.prompt |
Text and image | What to write or draw. Up to 2,000 characters. "" turns the layer’s AI off, so it shows its saved fallback. |
headline.tone |
Text | The tone of voice, such as friendly or formal. Up to 60 characters. |
headline.maxWords |
Text | At most this many words, from 1 to 300. Longer answers are cut. |
photo.style |
Image | The look, such as photo or flat illustration. Up to 120 characters. |
photo.reference |
Image | The http or https link of an image to edit, instead of making a new one. |
headline |
Text and image | A plain value skips the AI. The layer shows your value as it is. |
.tone, .maxWords, .style and .reference only work on a layer that has a prompt, from the editor or
from .prompt.
To change one page only, put the page first, like any key: [email protected]. See
Modifications.
Values in prompts
A prompt can use {{name}} variables. JamFrame fills them before it calls the AI:
- From the values you send, such as
"product": "Cold brew", or else the template’s own value for that variable. - If there is none, from the text of a text layer whose key is
name. - If neither has a value, the variable becomes empty and the answer has a warning.
You can send a value that only a prompt uses, such as product above. It is not reported as an unknown key.
Once its variables are filled, a prompt can be at most 3,000 characters.
AI images
The picture is made to fit the layer’s box. JamFrame picks the closest of these shapes: 1:1, 4:5, 5:4,
3:4, 4:3, 2:3, 3:2, 9:16, 16:9 or 21:9. The picture fills the box and is cropped at the edges if
needed. With Smart Resize, every size uses the same picture.
Translate a render
Send "translate": true with lang, a language tag such as es, fr, pt-BR or zh-Hant. You
need both: one without the other is a 400 VALIDATION_ERROR.
JamFrame translates the final text of every visible text layer, after your values and the AI text are in.
These stay as they are: variables without a value, links, email addresses, @handles, #hashtags and
numbers such as times, dates and prices.
If a translation drops or changes one of those, JamFrame keeps that text in the original language, adds a warning, and doesn’t charge for it.
When the AI fails
ai.onError says what happens when an AI call fails:
| Value | What happens |
|---|---|
fail (default) |
The render fails with the AI’s error code. Nothing is charged. |
fallback |
The render goes on. AI layers show their saved fallback, and nothing is translated. Results JamFrame already has from earlier renders are still used. The answer has a warning, and no AI credits are charged. |
Use fallback when a file with the saved text is better than no file at all.
Limits per render
These count every page and every size of one render together:
| Limit | Value |
|---|---|
| Different text prompts | 50 |
| Different AI images | 10 |
| Text to translate | 50,000 characters |
| Prompt length | 2,000 characters as written, 3,000 once variables are filled |
Over a limit, the render is refused with 400 VALIDATION_ERROR before anything runs, and nothing is charged.
Where AI runs
| Render | AI runs? |
|---|---|
POST /v1/render, with or without "async": true |
Yes |
| Test renders in the app | Yes |
| Workflow runs | Yes |
| Signed URLs, dynamic URLs and forms | Never |
Signed URLs, dynamic URLs and forms are public, so they never spend your AI credits. AI layers there show
their saved fallback, and AI keys such as headline.prompt come back as unknown keys in warnings.
Cost and caching
AI uses AI credits, which are separate from render credits. The render itself still costs its normal render credits. For what each kind of AI work costs, see What AI features cost. The words of all the text prompts in one render are counted together.
So the example above costs 1 (headline) + 4 (photo) + 1 (translation) = 6 AI credits, plus 1 render credit.
- AI credits are charged once per render, and only when the render succeeds. A failed render costs nothing.
- Every page and every size of one render share the same AI results.
- JamFrame keeps each result for 30 days in your workspace. The same prompt with the same settings gives
the same result, for free.
aiCreditsis then0. - To get a new result, change the prompt. For an edited image, change the
referencelink.
aiCredits is in the answer only for renders with AI layers or translate. For how many AI credits your plan
has, see Credits.
Errors
A render with AI can fail with one of these codes. Nothing is charged. With "ai": { "onError": "fallback" },
each of them renders the saved fallback instead, except a 400 for a passed limit or a bad key value.
| Status | error |
What to do |
|---|---|---|
400 |
VALIDATION_ERROR |
A limit was passed, a key has a bad value, or the reference image couldn’t be downloaded. Read message. |
402 |
AI_CREDITS_EXCEEDED |
Your AI credits for this period are used up. detail shows what’s left and when the period ends. |
422 |
AI_CONTENT_REFUSED |
The AI provider refused the prompt or the result under its content policy. Change the prompt. |
422 |
AI_BAD_REQUEST |
The AI provider couldn’t use this input, such as an image it can’t read. |
429 |
AI_RATE_LIMITED |
The AI provider is busy. Wait a moment and try again. |
502 |
AI_BAD_OUTPUT |
The AI didn’t give a usable result. Try again. |
502 |
AI_UPSTREAM_ERROR |
The AI provider failed. Try again. |
503 |
AI_UNAVAILABLE |
AI is off right now. Try later, or use fallback. |
504 |
AI_TIMEOUT |
The AI didn’t answer in time. Try again. |
See Errors for every other code.
Related
- Set up AI layers in the editor: AI layers
- Every render option: Render images and PDFs
- How AI credits work: Credits
Last updated
Still stuck?
Email [email protected] and a real person will reply. Tell us the template you were using and what you expected to happen.