BannerGen

Social media images from templates in well under a second. Base URL: https://api.bannergen.com. Machine-readable spec: /v1/openapi.json.

Quick start

Send your key as Authorization: Bearer big_…. One successful render costs 1 credit; failed renders are free.

curl -X POST https://api.bannergen.com/v1/renders \
  -H "Authorization: Bearer $BANNERGEN_API_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: post-2026-10-28-01" \
  -d '{"template":"quote-card","format":"square","params":{"quote":"Simplicity is not the absence of clutter, it is the presence of clarity."}}'
const res = await fetch("https://api.bannergen.com/v1/renders", {
  method: "POST",
  headers: {
    Authorization: `Bearer ${process.env.BANNERGEN_API_KEY}`,
    "Content-Type": "application/json",
    "Idempotency-Key": crypto.randomUUID(),
  },
  body: JSON.stringify({
    "template": "quote-card",
    "format": "square",
    "params": {
      "quote": "Simplicity is not the absence of clutter, it is the presence of clarity."
    }
  }),
});
const image = await res.json();
if (!res.ok) throw new Error(`${image.code}: ${image.message}`);
console.log(image.url);
import os, uuid, requests

res = requests.post(
    "https://api.bannergen.com/v1/renders",
    headers={
        "Authorization": f"Bearer {os.environ['BANNERGEN_API_KEY']}",
        "Idempotency-Key": str(uuid.uuid4()),
    },
    json={
      "template": "quote-card",
      "format": "square",
      "params": {
        "quote": "Simplicity is not the absence of clutter, it is the presence of clarity."
      }
    },
    timeout=30,
)
image = res.json()
res.raise_for_status()
print(image["url"])

Response 201:

{
  "id": "8f0c2a4e-3b51-4d0e-9a57-0d6a3f1b2c9e",
  "url": "https://api.bannergen.com/i/8f0c2a4e-3b51-4d0e-9a57-0d6a3f1b2c9e.png",
  "template": "quote-card",
  "format": "square",
  "width": 1080,
  "height": 1080,
  "output_format": "png",
  "bytes": 184211,
  "created_at": "2026-10-28T12:00:00.000Z"
}

The url is public and unguessable: hot-link it, post it, or download it.

Endpoints

MethodPathWhat it does
GET/v1/templatesAll templates with their formats. No key needed.
GET/v1/templates/{id}One template: JSON Schema of its params and an example. No key needed.
POST/v1/rendersRender one image synchronously. Body: template, format (default square), params, output_format (png).
POST/v1/batchesStart a batch of up to 1000 images. Answers 202 right away; see Batches.
GET/v1/batches/{id}Batch status and every image: url or error.
GET/v1/accountPlan, credits left and when they reset.

Batches

One template, many rows: rows is a list of params objects, defaults holds params shared by every row (a row's own value wins; a blank value — null, "" or missing — takes the default). Send format for one format or formats to render every row in each. Up to 1000 images per batch (rows × formats); 300 images take well under 3 minutes.

curl -X POST https://api.bannergen.com/v1/batches \
  -H "Authorization: Bearer $BANNERGEN_API_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: weekly-quotes-2026-44" \
  -d '{"template":"quote-card","formats":["square","story"],"defaults":{"theme":"dark","handle":"@acme"},"rows":[{"quote":"Ship it.","author":"Ada"},{"quote":"Make it simple."}]}'

# Poll until "status" is "completed"
curl https://api.bannergen.com/v1/batches/$BATCH_ID -H "Authorization: Bearer $BANNERGEN_API_KEY"

Every row is checked up front. A row with bad params does not fail the batch: its images are marked failed right away with the reason, and cost nothing. The valid images reserve a credit each when the batch is created (402 if there are not enough); an image that fails while rendering gets its credit back. So a batch costs exactly the number of images that succeeded.

status goes queued → processing → completed. GET /v1/batches/{id} lists items in request order, each with row_index, format and either url or error:

{
  "id": "3c9a7e10-5f2b-4c61-8d2e-91b0f4a6c7d3",
  "status": "completed",
  "template": "quote-card",
  "formats": [
    "square",
    "story"
  ],
  "total": 4,
  "succeeded": 3,
  "failed": 1,
  "pending": 0,
  "created_at": "2026-10-28T12:00:00.000Z",
  "completed_at": "2026-10-28T12:00:04.000Z",
  "items": [
    {
      "row_index": 0,
      "format": "square",
      "status": "succeeded",
      "id": "5d1e…",
      "url": "https://api.bannergen.com/i/5d1e….png",
      "width": 1080,
      "height": 1080,
      "bytes": 171204
    },
    {
      "row_index": 0,
      "format": "story",
      "status": "succeeded",
      "id": "a07c…",
      "url": "https://api.bannergen.com/i/a07c….png",
      "width": 1080,
      "height": 1920,
      "bytes": 236118
    },
    {
      "row_index": 1,
      "format": "square",
      "status": "succeeded",
      "id": "e4b2…",
      "url": "https://api.bannergen.com/i/e4b2….png",
      "width": 1080,
      "height": 1080,
      "bytes": 158377
    },
    {
      "row_index": 1,
      "format": "story",
      "status": "failed",
      "error": {
        "code": "image_load_failed",
        "message": "Could not load image for \"logo_url\": HTTP 404",
        "param": "logo_url"
      }
    }
  ]
}
error.codeMeaning
validation_failedThe row's params are invalid; errors lists each one.
image_load_failedAn image URL of the row could not be fetched or decoded; param names it.
internal_errorSomething broke on our side.
timeoutThe image did not finish in time.

For a row with bad params, error.errors lists each one; param is the param (column) name.

Formats

idSize
square1080×1080
portrait1080×1350
story1080×1920
landscape1200×628
pin1000×1500

Output is PNG for now; JPEG and WebP are planned. Image URLs can be PNG, JPEG, GIF or SVG over https.

Retries and idempotency

Add an Idempotency-Key header (any unique string, up to 255 characters) to POST /v1/renders or POST /v1/batches to make retries safe. Repeating a request with the same key returns the first result with 200 and the header Idempotent-Replayed: true, and charges only once. The same key with a different body is rejected with idempotency_key_reused. If a render fails, the key is released and you can retry with it.

Rate limits

Up to 60 single renders and 10 batches per minute per key. Over the limit you get 429 with Retry-After in seconds.

Errors

Errors are JSON with a machine-readable code and a human message. Validation errors list every bad parameter:

{
  "code": "validation_failed",
  "message": "\"quote\" is required",
  "errors": [
    {
      "param": "params.quote",
      "code": "required",
      "message": "\"quote\" is required"
    }
  ]
}
StatuscodeMeaning
401missing_api_keyNo Authorization: Bearer <key> header.
401invalid_api_keyThe key is unknown or revoked.
402insufficient_creditsNot enough credits for the render, or for the valid rows of a batch.
404not_foundUnknown path, template or batch.
409idempotency_in_progressA request with this Idempotency-Key is still running. Retry shortly.
400invalid_jsonThe body is not a JSON object.
422validation_failedBad parameters; errors lists each one with param, code and message.
422image_load_failedAn image URL could not be fetched or decoded; param names it.
422idempotency_key_reusedThis Idempotency-Key was already used with a different request body.
429rate_limitedToo many renders or batches for this key. Wait Retry-After seconds.
500internal_errorSomething broke on our side. The credit is returned.

Templates

The image shows only what you send. Leave a param out (or send null or "") and its element is not drawn: no placeholder text, no empty button. Only styling params (theme, font, toggles like trend or numbered) have defaults.

Every template also takes the brand params: background, primary_color, accent_color, font, logo_url, handle, theme.

quote-card — Quote card

A big quote with attribution. Good for thought leadership and customer voice.

ParamTypeDescription
quote requiredtext ≤ 280The quote, without quotation marks.
authortext ≤ 60Who said it.
author_roletext ≤ 60Role or company.
author_photo_urlimage_urlAuthor photo, shown as a circle.
backgroundbackgroundHex color, linear-gradient(<angle>deg, #hex, #hex) or an https image URL. Defaults depend on theme.
primary_colorcolorMain brand color (headings, key shapes).
accent_colorcolorHighlight color (badges, buttons, decorations).
fontenumFont family from the curated list. Default: playfair.
logo_urlimage_urlLogo (PNG, JPEG, GIF or SVG over https).
handletext ≤ 40Signature such as @brand or brand.com.
themelight | darkQuick light/dark switch for the default palette. Default: light.

Example params:

{
  "quote": "Simplicity is not the absence of clutter, it is the presence of clarity.",
  "author": "Maya Chen",
  "author_role": "Head of Design, Northwind",
  "logo_url": "https://avatars.githubusercontent.com/u/9919?s=256",
  "handle": "@northwind"
}
blog-post — Blog post announcement

"New on the blog" card with title, excerpt and a call to action.

ParamTypeDescription
labeltext ≤ 30Small label above the title.
title requiredtext ≤ 120Post title.
excerpttext ≤ 180One or two sentences under the title.
ctatext ≤ 24Button text.
image_urlimage_urlCover image shown next to or above the text.
backgroundbackgroundHex color, linear-gradient(<angle>deg, #hex, #hex) or an https image URL. Defaults depend on theme.
primary_colorcolorMain brand color (headings, key shapes).
accent_colorcolorHighlight color (badges, buttons, decorations).
fontenumFont family from the curated list. Default: inter.
logo_urlimage_urlLogo (PNG, JPEG, GIF or SVG over https).
handletext ≤ 40Signature such as @brand or brand.com.
themelight | darkQuick light/dark switch for the default palette. Default: light.

Example params:

{
  "label": "New on the blog",
  "title": "How we cut our onboarding time in half with three tiny changes",
  "excerpt": "What we measured, what we changed and what surprised us along the way.",
  "cta": "Read the post",
  "logo_url": "https://avatars.githubusercontent.com/u/9919?s=256",
  "handle": "@northwind"
}
product-promo — Product promo

Product shot with name, price, old price and a discount badge.

ParamTypeDescription
product_name requiredtext ≤ 60Product name.
taglinetext ≤ 80Short benefit line.
pricetext ≤ 20Price as shown, with currency.
old_pricetext ≤ 20Crossed-out previous price.
badgetext ≤ 14Discount badge text.
ctatext ≤ 24Button text.
product_image_urlimage_urlProduct photo, ideally on a plain or transparent background.
backgroundbackgroundHex color, linear-gradient(<angle>deg, #hex, #hex) or an https image URL. Defaults depend on theme.
primary_colorcolorMain brand color (headings, key shapes).
accent_colorcolorHighlight color (badges, buttons, decorations).
fontenumFont family from the curated list. Default: poppins.
logo_urlimage_urlLogo (PNG, JPEG, GIF or SVG over https).
handletext ≤ 40Signature such as @brand or brand.com.
themelight | darkQuick light/dark switch for the default palette. Default: light.

Example params:

{
  "product_name": "Aero Running Shoe",
  "tagline": "Featherlight. Built for long runs.",
  "price": "$89",
  "old_price": "$129",
  "badge": "-30%",
  "cta": "Shop now",
  "product_image_url": "https://images.unsplash.com/photo-1542291026-7eec264c27ff?w=1200&q=80&fm=jpg",
  "logo_url": "https://avatars.githubusercontent.com/u/9919?s=256",
  "handle": "@northwind"
}
testimonial — Testimonial

Customer review with star rating, name and photo.

ParamTypeDescription
review requiredtext ≤ 300What the customer said.
nametext ≤ 60Customer name.
roletext ≤ 60Role and company.
photo_urlimage_urlCustomer photo, shown as a circle.
rating1 | 2 | 3 | 4 | 5Star rating out of 5.
backgroundbackgroundHex color, linear-gradient(<angle>deg, #hex, #hex) or an https image URL. Defaults depend on theme.
primary_colorcolorMain brand color (headings, key shapes).
accent_colorcolorHighlight color (badges, buttons, decorations).
fontenumFont family from the curated list. Default: inter.
logo_urlimage_urlLogo (PNG, JPEG, GIF or SVG over https).
handletext ≤ 40Signature such as @brand or brand.com.
themelight | darkQuick light/dark switch for the default palette. Default: light.

Example params:

{
  "review": "We replaced three tools with this one. Setup took an afternoon and the team actually likes using it.",
  "name": "Jordan Ellis",
  "role": "Ops Lead at Brightside",
  "rating": "5",
  "logo_url": "https://avatars.githubusercontent.com/u/9919?s=256",
  "handle": "@northwind"
}
carousel-slide — Carousel slide

One slide of a series: number, heading and body in a consistent style.

ParamTypeDescription
slide_numbertext ≤ 3Number of this slide.
total_slidestext ≤ 3Total slides, for the progress bar.
title requiredtext ≤ 90Slide heading.
bodytext ≤ 280Slide text.
footer_hinttext ≤ 24Hint in the corner.
backgroundbackgroundHex color, linear-gradient(<angle>deg, #hex, #hex) or an https image URL. Defaults depend on theme.
primary_colorcolorMain brand color (headings, key shapes).
accent_colorcolorHighlight color (badges, buttons, decorations).
fontenumFont family from the curated list. Default: space-grotesk.
logo_urlimage_urlLogo (PNG, JPEG, GIF or SVG over https).
handletext ≤ 40Signature such as @brand or brand.com.
themelight | darkQuick light/dark switch for the default palette. Default: light.

Example params:

{
  "slide_number": "2",
  "total_slides": "7",
  "title": "Write the hook before the content",
  "body": "People decide in the first second whether to keep swiping. Lead with the outcome, not the setup.",
  "footer_hint": "Swipe →",
  "logo_url": "https://avatars.githubusercontent.com/u/9919?s=256",
  "handle": "@northwind"
}
event — Event / webinar

Event announcement with date, time and speaker.

ParamTypeDescription
event_typetext ≤ 30Small label.
title requiredtext ≤ 90Event title.
datetext ≤ 40Date as you want it shown.
timetext ≤ 40Time with timezone.
speaker_nametext ≤ 60Speaker name.
speaker_roletext ≤ 60Speaker role.
speaker_photo_urlimage_urlSpeaker photo, shown as a circle.
ctatext ≤ 24Button text.
backgroundbackgroundHex color, linear-gradient(<angle>deg, #hex, #hex) or an https image URL. Defaults depend on theme.
primary_colorcolorMain brand color (headings, key shapes).
accent_colorcolorHighlight color (badges, buttons, decorations).
fontenumFont family from the curated list. Default: outfit.
logo_urlimage_urlLogo (PNG, JPEG, GIF or SVG over https).
handletext ≤ 40Signature such as @brand or brand.com.
themelight | darkQuick light/dark switch for the default palette. Default: light.

Example params:

{
  "event_type": "Live webinar",
  "title": "Scaling content without scaling the team",
  "date": "Thu, Nov 14",
  "time": "5:00 PM CET",
  "speaker_name": "Priya Raman",
  "speaker_role": "VP Marketing, Northwind",
  "cta": "Register free",
  "logo_url": "https://avatars.githubusercontent.com/u/9919?s=256",
  "handle": "@northwind"
}
stat — Big number

One striking number with a short explanation.

ParamTypeDescription
number requiredtext ≤ 12The number, with units.
labeltext ≤ 120What the number means.
sourcetext ≤ 80Source line.
trendnone | up | downOptional trend arrow next to the number. Default: none.
backgroundbackgroundHex color, linear-gradient(<angle>deg, #hex, #hex) or an https image URL. Defaults depend on theme.
primary_colorcolorMain brand color (headings, key shapes).
accent_colorcolorHighlight color (badges, buttons, decorations).
fontenumFont family from the curated list. Default: bricolage.
logo_urlimage_urlLogo (PNG, JPEG, GIF or SVG over https).
handletext ≤ 40Signature such as @brand or brand.com.
themelight | darkQuick light/dark switch for the default palette. Default: light.

Example params:

{
  "number": "73%",
  "label": "of buyers check a brand's social feed before their first purchase",
  "source": "Source: Northwind Consumer Survey 2026",
  "logo_url": "https://avatars.githubusercontent.com/u/9919?s=256",
  "handle": "@northwind"
}
tips-list — Tips / list

Heading with 1–5 numbered or bulleted points.

ParamTypeDescription
title requiredtext ≤ 80List heading.
item_1 requiredtext ≤ 90First point.
item_2text ≤ 90Second point.
item_3text ≤ 90Third point.
item_4text ≤ 90Fourth point.
item_5text ≤ 90Fifth point.
numberedbooleanNumbers instead of bullets. Default: true.
backgroundbackgroundHex color, linear-gradient(<angle>deg, #hex, #hex) or an https image URL. Defaults depend on theme.
primary_colorcolorMain brand color (headings, key shapes).
accent_colorcolorHighlight color (badges, buttons, decorations).
fontenumFont family from the curated list. Default: dm-sans.
logo_urlimage_urlLogo (PNG, JPEG, GIF or SVG over https).
handletext ≤ 40Signature such as @brand or brand.com.
themelight | darkQuick light/dark switch for the default palette. Default: light.

Example params:

{
  "title": "5 ways to reuse one blog post",
  "item_1": "Turn each subheading into a carousel slide",
  "item_2": "Pull the best quote into a quote card",
  "item_3": "Post the key stat as a big-number image",
  "item_4": "Record a 30-second summary for Reels",
  "item_5": "Send it to your newsletter with a new intro",
  "logo_url": "https://avatars.githubusercontent.com/u/9919?s=256",
  "handle": "@northwind"
}
hiring — We're hiring

Job announcement with role, location, type and salary.

ParamTypeDescription
headlinetext ≤ 30Top line.
role requiredtext ≤ 60Job title.
locationtext ≤ 40Location or Remote.
employment_typetext ≤ 30Full-time, contract…
salarytext ≤ 40Salary range.
ctatext ≤ 24Button text.
backgroundbackgroundHex color, linear-gradient(<angle>deg, #hex, #hex) or an https image URL. Defaults depend on theme.
primary_colorcolorMain brand color (headings, key shapes).
accent_colorcolorHighlight color (badges, buttons, decorations).
fontenumFont family from the curated list. Default: montserrat.
logo_urlimage_urlLogo (PNG, JPEG, GIF or SVG over https).
handletext ≤ 40Signature such as @brand or brand.com.
themelight | darkQuick light/dark switch for the default palette. Default: light.

Example params:

{
  "headline": "We're hiring",
  "role": "Senior Product Designer",
  "location": "Remote · EU",
  "employment_type": "Full-time",
  "salary": "€70–90k",
  "cta": "Apply now",
  "logo_url": "https://avatars.githubusercontent.com/u/9919?s=256",
  "handle": "@northwind"
}
article-cover — Article cover / OG image

Cover for articles and link previews: title, category, author and date.

ParamTypeDescription
categorytext ≤ 30Category tag.
title requiredtext ≤ 120Article title.
authortext ≤ 60Author name.
datetext ≤ 40Publication date or reading time.
image_urlimage_urlOptional photo; the card uses it as the background.
backgroundbackgroundHex color, linear-gradient(<angle>deg, #hex, #hex) or an https image URL. Defaults depend on theme.
primary_colorcolorMain brand color (headings, key shapes).
accent_colorcolorHighlight color (badges, buttons, decorations).
fontenumFont family from the curated list. Default: fraunces.
logo_urlimage_urlLogo (PNG, JPEG, GIF or SVG over https).
handletext ≤ 40Signature such as @brand or brand.com.
themelight | darkQuick light/dark switch for the default palette. Default: light.

Example params:

{
  "category": "Growth",
  "title": "The quiet power of boring marketing",
  "author": "Sam Okafor",
  "date": "Oct 28, 2026 · 6 min read",
  "logo_url": "https://avatars.githubusercontent.com/u/9919?s=256",
  "handle": "@northwind"
}