Skip to content
JamFrame
Docs menu

List templates and renders

Find your templates and the keys each one takes, and look up past renders with their files, status and credits. The four read-only list and get calls.

Four calls let your code see what is in the workspace of your API key: its templates, the keys each template takes, and the renders it made. They are free and cost no credits. In the API, templates are called designs.

Call What it gives you
GET /v1/designs Your templates, or the ready-made templates of the template library
GET /v1/designs/{id} One template, with its keys, pages and saved sizes
GET /v1/renders Your renders, newest first, with your credits for this period
GET /v1/renders/{id} One render

List templates

curl "https://api.jamframe.com/v1/designs?q=coffee&limit=10" \
  -H "Authorization: Bearer $JAMFRAME_API_KEY"
const res = await fetch("https://api.jamframe.com/v1/designs?q=coffee&limit=10", {
  headers: { Authorization: `Bearer ${process.env.JAMFRAME_API_KEY}` },
});
const { designs, pagination } = await res.json();
import os
import requests

res = requests.get(
    "https://api.jamframe.com/v1/designs",
    headers={"Authorization": f"Bearer {os.environ['JAMFRAME_API_KEY']}"},
    params={"q": "coffee", "limit": 10},
)
designs = res.json()["designs"]
Query What it does
source workspace (default): your own templates. library: the template library, which any workspace can render by id.
q Only templates whose name contains this text, ignoring case. Up to 100 characters.
limit How many to return, from 1 to 100. Default: 25.
cursor The nextCursor of the page before, to get the next page.

Templates come newest first:

{
  "designs": [
    {
      "id": "clx8m2k3p0002abcd1234efgh",
      "name": "Coffee tips carousel",
      "orientation": "square",
      "pages": 3,
      "createdAt": "2026-11-01T09:12:44.000Z",
      "updatedAt": "2026-11-05T16:03:10.000Z"
    }
  ],
  "pagination": { "nextCursor": null, "hasMore": false }
}

orientation is square, portrait or landscape, from the size of the first page. pages is the number of pages.

Get every page

When hasMore is true, call again with cursor set to nextCursor:

async function allDesigns() {
  const all = [];
  let cursor = null;
  do {
    const url = new URL("https://api.jamframe.com/v1/designs");
    url.searchParams.set("limit", "100");
    if (cursor) url.searchParams.set("cursor", cursor);
    const res = await fetch(url, {
      headers: { Authorization: `Bearer ${process.env.JAMFRAME_API_KEY}` },
    });
    const { designs, pagination } = await res.json();
    all.push(...designs);
    cursor = pagination.hasMore ? pagination.nextCursor : null;
  } while (cursor);
  return all;
}

GET /v1/renders pages the same way.

Get one template and its keys

GET /v1/designs/{id} works for your own templates and for templates of the template library. It lists every key a render can set. The answer looks like this (some fields left out):

{
  "design": {
    "id": "clx8m2k3p0002abcd1234efgh",
    "name": "Coffee tips carousel",
    "orientation": "square",
    "pages": 3,
    "createdAt": "2026-11-01T09:12:44.000Z",
    "updatedAt": "2026-11-05T16:03:10.000Z",
    "parameters": [
      { "key": "title", "type": "text", "pages": [1, 2, 3], "example": "5 ways to brew better coffee" },
      { "key": "photo", "type": "image", "pages": [1], "example": "https://example.com/images/beans.jpg" },
      { "key": "brand", "type": "variable", "pages": [1, 3], "example": "Acme Coffee" },
      {
        "key": "tagline",
        "type": "text",
        "pages": [3],
        "example": "Fresh coffee, every morning",
        "prompt": "Write a 6-word tagline about {{brand}}"
      }
    ],
    "sizes": [
      { "id": "story", "name": "Story / Reel", "width": 1080, "height": 1920 }
    ]
  }
}

Each item of parameters is one key you can send in modifications:

Field What it is
key The name to send, such as title.
type What the key changes. See the table below.
pages The pages the key appears on, numbered from 1.
example The value saved in the template now.
prompt Only for AI layers: the layer’s prompt. example is then its saved fallback. See AI text, images and translation.
type What it changes Send
text A text layer New text
image An image layer An image link
qr A QR code The text or link to encode
shape A shape A fill color
variable A variable inside text, such as {{name}} The text to put in

sizes lists the sizes saved in the template’s Resize tab. Send an id as response.size to render that size. See Smart Resize.

A template that doesn’t exist, or belongs to another workspace, answers 404 NOT_FOUND.

List renders

GET /v1/renders lists every render of the workspace, newest first: renders from the API, test renders in the app, dynamic URLs, signed URLs, forms and workflows. Failed renders are listed too.

Query What it does
status succeeded or failed. Any other value is a 400 VALIDATION_ERROR.
designId Only renders of this template.
limit How many to return, from 1 to 100. Default: 25.
cursor The nextCursor of the page before.
curl "https://api.jamframe.com/v1/renders?status=succeeded&limit=5" \
  -H "Authorization: Bearer $JAMFRAME_API_KEY"
{
  "renders": [
    {
      "id": "clx8n0q1r0005abcd1234efgh",
      "createdAt": "2026-11-08T14:21:05.000Z",
      "designId": "clx8m2k3p0002abcd1234efgh",
      "designName": "Coffee tips carousel",
      "source": "api",
      "format": "jpeg",
      "pages": 2,
      "credits": 2,
      "status": "succeeded",
      "durationMs": 4210,
      "outputs": [
        { "url": "https://cdn.jamframe.com/renders/…-p1.jpg?Expires=…", "page": 1, "expiresAt": "2026-11-09T09:05:00.000Z" },
        { "url": "https://cdn.jamframe.com/renders/…-p2.jpg?Expires=…", "page": 2, "expiresAt": "2026-11-09T09:05:00.000Z" }
      ],
      "error": null,
      "cached": false
    }
  ],
  "pagination": { "nextCursor": "clx8n0q1r0005abcd1234efgh", "hasMore": true },
  "totals": {
    "periodStart": "2026-11-01T00:00:00.000Z",
    "periodEnd": "2026-12-01T00:00:00.000Z",
    "creditsUsed": 342,
    "creditsQuota": 1000,
    "creditsRemaining": 658,
    "workspaceCreditsUsed": 120
  }
}
Field What it is
designId, designName The template. Both are null if the template was deleted later.
source Where the render came from: api, editor (a test render in the app), dynamic-url, signed-url, form or workflow.
credits Render credits used. Failed renders cost nothing.
outputs The files, one per page, as links that work for 5 minutes. Empty for failed renders and for renders with response.type: "base64".
error Why a failed render failed, or null.
cached true when a dynamic or signed URL was served from the cache, at no cost.

totals shows your organization’s render credits for this billing period: creditsUsed, creditsQuota and creditsRemaining (both null when there is no limit), and workspaceCreditsUsed, this workspace’s share. So you can show how many credits are left without another call.

Get one render

GET /v1/renders/{id} returns one render as {"render": {…}}, with the same fields as a list item. Use it to look up the renderId from a render answer, a render job, or a render.completed webhook. A render of another workspace answers 404 NOT_FOUND.

The links in outputs are new each time you call, and each works for 5 minutes (expiresAt). Download the file soon, or call again for a fresh link. Files are deleted after 7 to 31 days, depending on where the render came from (8 days for API renders), so links to older renders no longer work. See How long files last. For a link that never expires, use a dynamic URL.

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.