Image Generation API — Template-Driven, On-Brand OG Cards and Illustrations
REST API for generating brand-aligned images from reusable templates. Produce OG cards, hero illustrations, CTA banners, and inline graphics rendered via Satori — no prompt engineering required.
Generate brand-aligned images from templates — OG cards, hero illustrations, in-line graphics, CTA banners, list cards, comparison visuals. Every workspace inherits a library of templates; agencies can fork and customize.
Conceptual overview
Image generation in CitationBench is template-driven, not free-form prompt-to-image. Each template defines:
- A visual layout (rendered via Satori → PNG/JPG)
- A JSON schema for input data (title, subhead, highlights, brand colors)
- Brand-specific defaults (font, palette, logo)
40+ templates ship per brand in the system library. You can create new ones or fork existing ones for per-workspace customization. The benefit: every image you generate looks like it came from the same brand without any prompt engineering.
Endpoints
| Method | Path | Purpose |
|---|---|---|
| POST | /v1/produce/image | Generate one image |
| POST | /v1/produce/image/bulk | Generate many images |
| GET | /v1/produce/image | List generated images |
| GET | /v1/produce/image/{id} | Get one image |
| DELETE | /v1/produce/image/{id} | Delete |
| GET | /v1/produce/image/templates | List available templates |
| GET | /v1/produce/image/templates/{id} | Get one template (with schema + sample) |
| POST | /v1/produce/image/templates/{slug}/fork | Fork a system template into the workspace |
POST /v1/produce/image
{
"templateId": "acme-og-card",
"data": {
"title": "How engineering teams track capacity",
"subhead": "Five patterns that scale",
"tag": "Performance",
"ctaText": "Read the article"
},
"linkedContentId": "bp_***",
"purpose": "og"
}| Field | Type | Required | Notes |
|---|---|---|---|
templateId | string | yes | Slug of the template |
data | object | yes | Must match the template's input schema |
linkedContentId | string | no | Link the image to a blog post or landing page for organization |
purpose | enum | no | og, social, featured, inline, cta, custom |
format | enum | no | png (default), jpg, webp |
width / height | number | no | Defaults per template |
Response
{
"imageId": "img_***",
"templateId": "acme-og-card",
"url": "https://cdn.citationbench.com/images/img_***.png",
"width": 1200,
"height": 630,
"format": "png",
"sizeBytes": 84320,
"linkedContentId": "bp_***",
"purpose": "og",
"createdAt": "2026-05-24T08:15:00Z"
}Synchronous — no invocation handle, since image generation is sub-second.
POST /v1/produce/image/bulk
curl -X POST .../v1/produce/image/bulk -d '{
"templateId": "acme-og-card",
"items": [
{ "data": { "title": "Article A", "tag": "Performance" }, "linkedContentId": "bp_A" },
{ "data": { "title": "Article B", "tag": "Performance" }, "linkedContentId": "bp_B" }
]
}'Returns an array of generated images.
GET /v1/produce/image
curl -G .../v1/produce/image \
--data-urlencode "linkedContentId=bp_***" \
--data-urlencode "purpose=og"GET /v1/produce/image/templates
curl .../v1/produce/image/templates{
"data": [
{
"id": "acme-og-card",
"name": "Acme OG card",
"description": "1200×630 OG/Twitter card with brand styling",
"width": 1200,
"height": 630,
"purposes": ["og", "social"],
"inputSchema": {
"type": "object",
"required": ["title"],
"properties": {
"title": { "type": "string", "maxLength": 80 },
"subhead": { "type": "string", "maxLength": 140 },
"tag": { "type": "string", "maxLength": 24 },
"ctaText": { "type": "string", "maxLength": 24 }
}
},
"sampleUrl": "https://cdn.citationbench.com/templates/sample/acme-og-card.png"
},
{
"id": "acme-featured",
"name": "Acme featured image",
"...": "..."
}
],
"total": 42
}POST /v1/produce/image/templates/{slug}/fork
curl -X POST .../v1/produce/image/templates/system.og-card/fork -d '{
"id": "acme-og-card",
"overrides": {
"logoUrl": "https://acme.com/logo.svg",
"palette": { "primary": "#0070f3", "background": "#ffffff" },
"font": "Inter"
}
}'Creates a workspace-scoped customized version.
MCP
> Generate an OG image for bp_*** using the standard OG template.Claude calls produce.blog_post.get (to fetch the title), then produce.image.create.
> Show me my image template library.Claude calls produce.image.templates.list.
Errors
| Status | Code | Cause |
|---|---|---|
| 400 | validation_error | data failed the template's input schema |
| 404 | template_not_found | — |
| 422 | text_too_long | A text field exceeded the template's safe rendering width |
Cost
| Action | Credits |
|---|---|
| Per image | 1 |
| Bulk per image | 1 |
| Template CRUD | free |
Use cases (string things together)
A. Auto-generate OG image for every published blog post
Pillar default refiners include rfn_og-image (a MULTI_IMAGE_REFINER); every blog post gets an OG card without you asking.
B. Per-section in-line illustrations
A MULTI_IMAGE_REFINER can read the article's outline and pick illustration templates per section.
C. Programmatic CTA cards
for OFFER in starter pro enterprise; do
curl -X POST .../v1/produce/image -d "{
\"templateId\": \"acme-cta\",
\"data\": { \"offer\": \"$OFFER\", \"ctaText\": \"Start free\" }
}"
doneD. Fork the system OG template, customize once, ship everywhere
curl -X POST .../v1/produce/image/templates/system.og-card/fork -d '{
"id": "acme-og-card",
"overrides": { "logoUrl": "...", "palette": { ... } }
}'
# Now every reference to acme-og-card uses your customized version.Related
- Concept: Content Refiners
- API: Production · refine (IMAGE_REFINER + MULTI_IMAGE_REFINER use this endpoint)
- API: Production · blog post
- API: Production · landing page
Evaluate
REST API for scoring blog posts and landing pages against customizable rubrics. Returns per-criterion scores, weighted overall scores, flagged issues, and recommended actions for any agentic content pipeline.
Publish
REST API for publishing blog posts and landing pages to connected CMS platforms. Supports WordPress, Wisp, Ghost, Webflow, and custom REST hooks with approval gating and auto-indexing on success.