Skip to main content
Every diagram you store in Just Flow It can be rendered to an image. There are two ways to get one:

On-demand image endpoint

GET /v1/diagrams/{id}/image — render any saved diagram to PNG or SVG, in light or dark theme, at any time.

image_url from a generation

When a POST /v1/diagrams/generate job reaches status: "succeeded", the resulting Generation carries an image_url rendered with the theme/format you requested.

When to use which

Use the image endpoint when…

You already have a diagram id and want its picture — for example to display an existing diagram, re-theme it (light ↔ dark), or switch format (PNG ↔ SVG). It does not call the AI model and does not count against your generation quota.

Use image_url when…

You just generated a brand-new diagram and want the rendered image that matches the theme/format you asked for, without a second round trip. It is only present once the generation has status: "succeeded".
Both paths render the same saved diagram. If you need a different theme or format than the one a generation produced, call the image endpoint on the new diagram’s id — no need to regenerate.

Get an image on demand

GET /v1/diagrams/{id}/image
Renders the saved diagram to an image on demand. Requires the diagrams:read scope.
id
string
required
The UUID of the diagram to render.
theme
string
default:"light"
Color theme of the rendered image. One of light or dark.
format
string
default:"png"
Image format. One of png or svg.

Request

curl -L "https://justflow.it/api/v1/diagrams/d290f1ee-6c54-4b01-90e6-d701748f0851/image?theme=dark&format=png" \
  -H "Authorization: Bearer jfi_sk_live_..." \
  -o diagram.png

Response

200 OK
image
The rendered diagram image (or a link to it), in the requested theme and format. The response carries the standard X-Request-Id and RateLimit-* headers.
The image endpoint never calls the AI model and does not consume your monthly generation quota. It is still subject to the per-key burst limit (120 requests / 60s).

Errors

A diagram id that doesn’t exist (or isn’t visible to your key) returns not_found_error / resource_not_found.
{
  "error": {
    "type": "not_found_error",
    "code": "resource_not_found",
    "message": "Diagram not found."
  },
  "request_id": "req_8f2c1a9b"
}
An unsupported theme or format value returns invalid_request_error / invalid_parameter, with param naming the offending query parameter.
{
  "error": {
    "type": "invalid_request_error",
    "code": "invalid_parameter",
    "message": "format must be one of: png, svg.",
    "param": "format"
  },
  "request_id": "req_3d77e0a4"
}
A key without the diagrams:read scope returns permission_error / insufficient_scope.
{
  "error": {
    "type": "permission_error",
    "code": "insufficient_scope",
    "message": "This key is missing the required scope: diagrams:read."
  },
  "request_id": "req_a1b2c3d4"
}

image_url from a generation

When you create a diagram from natural language with POST /v1/diagrams/generate, the job runs asynchronously. You poll GET /v1/generations/{id} until it finishes. On success, the Generation object includes both the saved diagram and an image_url rendered with the theme and format you requested at generation time.
1

Start the generation

POST /v1/diagrams/generate with your prompt (and optional theme, format, name, folder_id) returns 202 Accepted with status: "queued" and a Location header pointing at the generation.
2

Poll until succeeded

GET /v1/generations/{id} until status is succeeded (or failed). Honor the Retry-After hint between polls.
3

Read image_url

On success, image_url is populated alongside the created diagram.
A succeeded generation looks like this:
{
  "object": "generation",
  "id": "gen_5f9a2b3c4d",
  "status": "succeeded",
  "diagram": {
    "object": "diagram",
    "id": "d290f1ee-6c54-4b01-90e6-d701748f0851",
    "name": "Customer onboarding",
    "folder_id": null,
    "organization_id": null,
    "created_by": "a1b2c3d4-0000-0000-0000-000000000000",
    "created_at": "2026-06-07T12:00:05Z",
    "updated_at": "2026-06-07T12:00:05Z"
  },
  "image_url": "/api/v1/diagrams/d290f1ee-6c54-4b01-90e6-d701748f0851/image?theme=light&format=png",
  "error": null,
  "created_at": "2026-06-07T12:00:00Z"
}
image_url
string | null
The rendered image for the generated diagram, in the theme/format requested on the generate call. null until the job reaches status: "succeeded". It is a path relative to the API base (https://justflow.it) — prepend the base to fetch it, e.g. https://justflow.it{image_url}.
Don’t read image_url (or diagram) before the job succeeds — both are null while status is queued or processing, and on failed you’ll instead find details in error.

Embedding the image

Because API keys are server-side only (no CORS, never exposed in a browser), don’t point an <img src> directly at the endpoint with a key attached. Instead, fetch the bytes on your server and serve or store them yourself.
import { writeFile } from "node:fs/promises";

async function fetchDiagramImage(id, { theme = "light", format = "png" } = {}) {
  const url = new URL(`https://justflow.it/api/v1/diagrams/${id}/image`);
  url.searchParams.set("theme", theme);
  url.searchParams.set("format", format);

  const res = await fetch(url, {
    headers: { Authorization: "Bearer jfi_sk_live_..." },
  });
  if (!res.ok) throw new Error(`Image request failed: ${res.status}`);

  return Buffer.from(await res.arrayBuffer());
}

const png = await fetchDiagramImage("d290f1ee-6c54-4b01-90e6-d701748f0851", {
  theme: "dark",
});
await writeFile("onboarding.png", png);
// Now serve onboarding.png from your own CDN / static host and embed it:
//   <img src="/assets/onboarding.png" alt="Customer onboarding" />
Pick svg when you want crisp scaling or to inline the markup into a page; pick png when you need a flat raster for email, slides, or thumbnails.