Skip to content
JamFrame
Docs menu

API overview

What the JamFrame REST API does, its base URL, how to sign requests with an API key, and the three calls that take you from a template to a finished file.

The JamFrame API makes images and PDFs from your templates, from your own code. You send a template id and the values to fill in. You get back a link to each finished file.

Anything you can render in the app, you can render with the API: single images, carousels, PDFs and other sizes of the same design.

Base URL

Every request goes to this address:

https://api.jamframe.com/v1

Requests and answers are JSON. Send Content-Type: application/json with every request that has a body. A request body can be up to 5 MB. Times are in UTC, written like 2026-11-14T09:30:00.000Z.

Authentication

Every request needs an API key in the Authorization header:

Authorization: Bearer jf_live_…

You create keys on the API Keys page in the app. A key works in one workspace, so you never send a workspace id. Keep keys on your server and out of web pages. See API keys.

Your first request

This request lists the templates in your workspace. It’s free, so it’s a good way to check that your key works.

curl "https://api.jamframe.com/v1/designs?limit=5" \
  -H "Authorization: Bearer $JAMFRAME_API_KEY"
const res = await fetch("https://api.jamframe.com/v1/designs?limit=5", {
  headers: { Authorization: `Bearer ${process.env.JAMFRAME_API_KEY}` },
});
const { designs } = await res.json();
for (const design of designs) console.log(design.id, design.name);
import os
import requests

res = requests.get(
    "https://api.jamframe.com/v1/designs",
    headers={"Authorization": f"Bearer {os.environ['JAMFRAME_API_KEY']}"},
    params={"limit": 5},
)
for design in res.json()["designs"]:
    print(design["id"], design["name"])

The answer lists your templates, 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 }
}

The API calls templates “designs”. A template’s id is the templateId you render with.

From template to file in three calls

  1. Find the template. GET /v1/designs lists the templates in your workspace. Add q=coffee to search by name, or source=library to list the ready-made library templates instead.

  2. See what you can change. GET /v1/designs/{id} returns the template’s parameters. Each one has the key you send, its type, the pages it’s on, and its current value as example:

    {
      "design": {
        "id": "clx8m2k3p0002abcd1234efgh",
        "name": "Coffee tips carousel",
        "pages": 3,
        "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" }
        ],
        "sizes": []
      }
    }
  3. Render. POST /v1/render with the templateId and the values in modifications:

    curl https://api.jamframe.com/v1/render \
      -H "Authorization: Bearer $JAMFRAME_API_KEY" \
      -H "Content-Type: application/json" \
      -d '{
        "templateId": "clx8m2k3p0002abcd1234efgh",
        "modifications": { "title": "Grind just before brewing" },
        "response": { "format": "png" }
      }'

    The answer has a link to each image in data.content. See Render images and PDFs for every option.

Pagination

List endpoints, such as GET /v1/designs and GET /v1/renders, return one page of items at a time.

Query parameter What it does
limit How many items per page, from 1 to 100. The default is 25. A larger number counts as 100.
cursor Where the page starts. Leave it out for the first page. For the next page, send the nextCursor of the last answer.

Each answer has a pagination object. hasMore is true when there are more pages. nextCursor is null on the last page.

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();
  for (const design of designs) console.log(design.id, design.name);
  cursor = pagination.nextCursor;
} while (cursor);

Errors, limits and credits

  • Errors. Every answer that isn’t a 2xx has the same shape: {"error": "CODE", "message": "…"}. See Errors.
  • Rate limits. Your organization can send a set number of requests per minute, depending on your plan. Too many get a 429. See Rate limits.
  • Credits. Each image, or each page of a PDF, costs one render credit. Failed renders are free, and so is reading templates and renders. See Credits.

The API guides

Guide What it covers
API keys Create, test, rotate and revoke keys
Render images and PDFs POST /v1/render: formats, carousels, PDFs, links and limits
Modification keys How to change text, images and styles, page by page
Async renders Render in the background, then poll a job or get a callback
Smart Resize Render one template at other sizes, one or many per call
Signed URLs Public links that render an image when someone opens them
AI at render time Let AI write text, make images or translate while rendering
Generate a template with AI Design a new template from a text prompt
Background removal Cut a picture out on a transparent background
Templates and renders List templates and library templates, and read your render log
Workflows Start workflow runs and read their results
Webhooks Get told when templates change or background renders finish
Errors Error codes and what to do about them
Rate limits How many requests you can send, and how to slow down

Every endpoint, field and error code is in the API reference (opens in a new tab).

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.