Skip to content
Builder2 logo builder2

API Documentation

Generate media from a prompt, get permanent CDN URLs. Authenticate with an API key — no session required.

Open Source MIT · agent-ready

Skip the boilerplate — use the instant_media skill

The official instant_media skill wraps this entire API for any SKILL.md-compatible AI agent: images, music (lyrics-to-song), narrated videos with subtitles, TTS, transcription, screenshots — one call each, permanent URL back in ~50ms, placeholders serving while the real render lands. Works with api.builder2.com or any self-hosted instance.

7 content types image → video_workflow
~50ms URLs fire-and-forget
Asset reuse surgical regenerates
Any runtime Goja / ES5 sandbox
git clone https://github.com/digimon99/instant_media.git <skills-dir>/instant_media
# then set: BUILDER2_API_KEY=bk2_...   # or BUILDER2_BASE_URL for self-hosted
digimon99/instant_media Pairs with blogpost_service for generate-then-publish pipelines.

1 Authentication

All endpoints require an Authorization: Bearer header with an API key.

API Key

Keys start with bk2_. They don't expire. Manage them from the dashboard.

Authorization: Bearer bk2_a8f3e1...
# Example: authenticated request
curl https://api.builder2.com/api/v1/user \
  -H "Authorization: Bearer bk2_YOUR_KEY"

# Missing or invalid key
{ "error": "Invalid API key" }

2 Generate Media

POST /api/v1/build-media

Send a prompt to generate media. Creates a job, generates variants, and returns a permanent CDN URL immediately.

Field Type Required Description
prompt string Yes Text description of desired media
content_type string Yes image | infographic | image_proxy | page_screenshot | video | tts | music
media_slug string No URL-friendly name (auto-slugified from prompt if omitted)
count int No Number of variants (1–4, default 1)
webhook_url string No URL to receive a callback when the job completes
character_id string No For image type: uses the character's default avatar as a reference image with an image-edit model. For other types: injects character traits into the prompt.
character_slug string No Alternative to character_id — use the character's URL slug
character_image_url string No Custom reference image URL for image-edit mode (image type only). Bypasses character lookup — use any image URL directly.
image_url string image_proxy Source image URL to proxy. Downloads the external image and re-serves it via builder2 CDN. Response includes source_url for attribution.
page_url string page_screenshot Webpage URL to screenshot. Renders the page via headless Chromium and captures a JPEG. Response includes source_page_url for attribution.
image_size string No Image aspect ratio preset (image only). Default: landscape_16_9. Options: landscape_16_9 | landscape_4_3 | square | portrait_4_3 | portrait_16_9. The closest supported value is chosen per model.
model string No Model override. For music: suno-v4.5 (default) | suno-v4.5plus | suno-v5. For images: any fal.ai model ID (e.g. fal-ai/flux-pro/v1.1).
style string music Music style tags (e.g., pop, electronic, upbeat, female vocals). Used with custom_mode.
title string music Song title (custom mode only)
custom_mode bool music Enable custom mode for full control over lyrics and style (default: false). In simple mode, the prompt describes the song; in custom mode, the prompt IS the lyrics.
instrumental bool music Generate instrumental only, no vocals (default: false)
curl -X POST https://api.builder2.com/api/v1/build-media \
  -H "Authorization: Bearer bk2_YOUR_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "prompt": "a sunset over mountains, digital art",
    "content_type": "image",
    "media_slug": "sunset-mountains",
    "count": 2,
    "image_size": "landscape_16_9",
    "webhook_url": "https://example.com/webhooks/builder2"
  }'

# Response 202 Accepted
{
  "job_id": "job_bbb60d20-028",
  "media_slug": "sunset-mountains",
  "permanent_url": "https://cdn.builder2.com/w/sunset-mountains/job_bbb60d20-028.jpeg",
  "media_url": "https://media.builder2.com/job_bbb60d20-028/1.png",
  "count": 2,
  "default_variant_index": 1,
  "status": "generating",
  "model": "fal-ai/nano-banana-pro",
  "mode": "standard",
  "embed_markdown": "![](https://www.builder2.com/embed/job_bbb60d20-028/image)",
  "embed_html": "<iframe src=\"https://www.builder2.com/embed/job_bbb60d20-028\" width=\"100%\" height=\"500\" frameborder=\"0\" style=\"border:none;border-radius:12px;overflow:hidden;\" loading=\"lazy\"></iframe>"
}

The permanent_url is the worker-served slot URL — for images it returns a compressed 1200x630 JPEG social card (Content-Type: image/jpeg). The media_url is the direct R2 URL (full-size, available once generation completes). Use /w/{type}/{slug}/{jobId}/{index}.png for a specific full-size variant.

# Image Proxy: re-serve an external image via builder2 CDN
curl -X POST https://api.builder2.com/api/v1/build-media \
  -H "Authorization: Bearer bk2_YOUR_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "content_type": "image_proxy",
    "image_url": "https://example.com/photos/rtx-5090.jpg",
    "media_slug": "rtx-5090-product",
    "prompt": "NVIDIA RTX 5090 graphics card"
  }'

# Response 202 Accepted
{
  "job_id": "job_e1f2a3b4-567",
  "media_slug": "rtx-5090-product",
  "permanent_url": "https://cdn.builder2.com/w/i/rtx-5090-product/job_e1f2a3b4-567.jpeg",
  "media_url": "https://media.builder2.com/job_e1f2a3b4-567/1.jpg",
  "count": 1,
  "status": "generating",
  "source_url": "https://example.com/photos/rtx-5090.jpg",
  "embed_markdown": "![](https://www.builder2.com/embed/job_e1f2a3b4-567/image)",
  "embed_html": "..."
}

# source_url is returned for attribution/credit
# No prompt required, no fal.ai generation — image is downloaded and served via CDN
# Generate Music (Suno via Evolink)
# Simple mode — describe the song you want
curl -X POST https://api.builder2.com/api/v1/build-media \
  -H "Authorization: Bearer bk2_YOUR_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "prompt": "A cheerful summer pop song about road trips and adventure",
    "content_type": "music",
    "media_slug": "summer-road-trip",
    "model": "suno-v4.5"
  }'

# Response 202 Accepted (returns immediately with placeholder MP3)
{
  "job_id": "job_f1e2d3c4-567",
  "media_slug": "summer-road-trip",
  "permanent_url": "https://cdn.builder2.com/w/m/summer-road-trip/job_f1e2d3c4-567.mp3",
  "media_url": "https://media.builder2.com/job_f1e2d3c4-567/1.mp3",
  "count": 1,
  "default_variant_index": 1,
  "status": "generating",
  "model": "suno-v4.5",
  "mode": "standard",
  "embed_markdown": "![](https://www.builder2.com/embed/job_f1e2d3c4-567/image)",
  "embed_html": "..."
}

# The permanent_url serves a silent placeholder MP3 immediately.
# Suno generates 2 songs (~30-90s), both saved as variants.
# Variant 1 = default, Variant 2 = alternate. Switch via PUT /jobs/:job_id/default.

# Custom mode — full control with lyrics
curl -X POST https://api.builder2.com/api/v1/build-media \
  -H "Authorization: Bearer bk2_YOUR_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "prompt": "[Verse]\nPack the car, hit the road\nSun is high, feeling bold\n[Chorus]\nSummer nights, living right\nDriving till the morning light",
    "content_type": "music",
    "media_slug": "summer-anthem",
    "model": "suno-v5",
    "custom_mode": true,
    "style": "pop, upbeat, electronic, female vocals, 120bpm",
    "title": "Summer Anthem"
  }'

# Instrumental mode — no vocals
curl -X POST https://api.builder2.com/api/v1/build-media \
  -H "Authorization: Bearer bk2_YOUR_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "prompt": "lo-fi chillhop for studying",
    "content_type": "music",
    "instrumental": true
  }'

3 Webhooks

Pass a webhook_url in your generate or regenerate request. When the job finishes, we send a POST with the full result — no follow-up call needed.

Callback Payload

Sent as JSON with the following headers:

Content-Type: application/json
X-Builder2-Signature: v1=<signature>
# POST to your webhook_url when job completes
{
  "job_id": "job_bbb60d20-028",
  "status": "completed",
  "slots": [
    {
      "key": "hero-banner",
      "url": "https://cdn.builder2.com/m/2eb8f23b-f0f3/hero-banner",
      "status": "ready"
    },
    {
      "key": "thumbnail",
      "url": "https://cdn.builder2.com/m/2eb8f23b-f0f3/thumbnail",
      "status": "ready"
    }
  ],
  "variants": [
    {
      "variant_id": "job_bbb60d20-028/hero-banner/1",
      "slot_key": "hero-banner",
      "preview_url": "https://storage.nxdot.app/builder2-qitl/.../hero-banner_1.png",
      "content_type": "image",
      "width": 1024,
      "height": 1024,
      "is_active": true
    },
    {
      "variant_id": "job_bbb60d20-028/hero-banner/2",
      "slot_key": "hero-banner",
      "preview_url": "https://storage.nxdot.app/builder2-qitl/.../hero-banner_2.png",
      "content_type": "image",
      "width": 1024,
      "height": 1024,
      "is_active": false
    },
    {
      "variant_id": "job_bbb60d20-028/hero-banner/3",
      "slot_key": "hero-banner",
      "preview_url": "https://storage.nxdot.app/builder2-qitl/.../hero-banner_3.png",
      "content_type": "image",
      "width": 1024,
      "height": 1024,
      "is_active": false
    },
    {
      "variant_id": "job_bbb60d20-028/thumbnail/1",
      "slot_key": "thumbnail",
      "preview_url": "https://storage.nxdot.app/builder2-qitl/.../thumbnail_1.png",
      "content_type": "image",
      "width": 1024,
      "height": 1024,
      "is_active": true
    }
  ]
}

Your endpoint must respond with 2xx within 10 seconds. We do not retry failed deliveries.

4 Embeds

Every /build-media response includes embed_markdown and embed_html. Drop these into chat responses, web pages, or any text that renders markdown or HTML.

Markdown Embed

Works in any markdown renderer (ChatGPT, Discord, Slack, etc.). Serves a branded placeholder while generating, then 302-redirects to the actual image.

![](https://www.builder2.com/embed/job_bbb60d20-028/image)

HTML Embed (Iframe)

Rich interactive experience for web-based chat UIs. Auto-refreshes from loading state to media. Supports image grids, video players, and audio players.

<iframe src="https://www.builder2.com/embed/job_bbb60d20-028"
  width="100%" height="500" frameborder="0"
  style="border:none;border-radius:12px;overflow:hidden;"
  loading="lazy"></iframe>

Public Status Endpoint

No authentication required. Poll this to check job progress and get variant URLs.

GET /api/v1/embed/:job_id/status
curl https://www.builder2.com/api/v1/embed/job_bbb60d20-028/status

# While generating
{
  "job_id": "job_bbb60d20-028",
  "status": "processing",
  "content_type": "image",
  "variant_count": 0
}

# When ready
{
  "job_id": "job_bbb60d20-028",
  "status": "ready",
  "content_type": "image",
  "slug": "sunset-mountains",
  "prompt": "a sunset over mountains, digital art",
  "variant_count": 2,
  "default_index": 1,
  "variants": [
    { "url": "https://media.builder2.com/job_bbb60d20-028/1", "width": 1024, "height": 1024 },
    { "url": "https://media.builder2.com/job_bbb60d20-028/2", "width": 1024, "height": 1024 }
  ]
}

Content Type Rendering

Content Type Iframe Behavior Markdown Image
imageVariant grid (1) or carousel (2+)First variant
image_proxySingle image displayProxied image
page_screenshotSingle screenshot displayScreenshot image
videoHTML5 video playerPlaceholder only
ttsAudio player(s)Placeholder only
musicAudio player(s)Placeholder only

5 Characters

Generate images using a character as a visual reference. The system uses an image-edit model that takes the character's default avatar (or a custom URL) as input, producing images that match the character's appearance.

Two ways to specify a character

  • character_id or character_slug — looks up the character's default avatar automatically
  • character_image_url — any image URL, no character record needed

For non-image content types (tts, video, music), the character's physical & soul traits are injected into the prompt text instead.

Example 1: Using character_id

The character's default avatar is used as the reference image. The image-edit model receives image_urls + your prompt.

# Request: generate image with character reference
curl -X POST https://api.builder2.com/api/v1/build-media \
  -H "Authorization: Bearer bk2_YOUR_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "prompt": "dancing in a neon-lit Berlin underground club, moody lighting, cinematic",
    "content_type": "image",
    "character_id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
    "media_slug": "lucy-berlin-club",
    "count": 2,
    "image_size": "portrait_16_9"
  }'

# Response 202 Accepted
{
  "job_id": "job_c4d5e6f7-890",
  "media_slug": "lucy-berlin-club",
  "permanent_url": "https://cdn.builder2.com/w/image/lucy-berlin-club/job_c4d5e6f7-890.jpeg",
  "media_url": "https://media.builder2.com/job_c4d5e6f7-890/1.png",
  "count": 2,
  "default_variant_index": 1,
  "status": "generating",
  "model": "fal-ai/bytedance/seedream/v4.5/edit",
  "mode": "character",
  "embed_markdown": "![](https://www.builder2.com/embed/job_c4d5e6f7-890/image)",
  "embed_html": "<iframe src=\"https://www.builder2.com/embed/job_c4d5e6f7-890\" width=\"100%\" height=\"500\" frameborder=\"0\" style=\"border:none;border-radius:12px;overflow:hidden;\" loading=\"lazy\"></iframe>"
}

# What gets sent to fal.ai internally:
# POST https://queue.fal.run/fal-ai/bytedance/seedream/v4.5/edit
# {
#   "prompt": "dancing in a neon-lit Berlin underground club...",
#   "image_urls": ["https://media.builder2.com/avatars/char_a1b2/default.png"],
#   "image_size": "portrait_16_9",
#   "num_images": 2
# }

Example 2: Using character_image_url

Pass any image URL directly — no character record needed. Useful for ad-hoc image editing or external reference images.

# Request: image edit with a custom reference URL
curl -X POST https://api.builder2.com/api/v1/build-media \
  -H "Authorization: Bearer bk2_YOUR_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "prompt": "wearing a red dress at a gala event, elegant, professional photography",
    "content_type": "image",
    "character_image_url": "https://example.com/photos/portrait.jpg",
    "media_slug": "red-dress-gala",
    "image_size": "portrait_4_3"
  }'

# Response 202 Accepted
{
  "job_id": "job_d5e6f7g8-901",
  "media_slug": "red-dress-gala",
  "permanent_url": "https://cdn.builder2.com/w/image/red-dress-gala/job_d5e6f7g8-901.jpeg",
  "media_url": "https://media.builder2.com/job_d5e6f7g8-901/1.png",
  "count": 1,
  "default_variant_index": 1,
  "status": "generating",
  "model": "fal-ai/bytedance/seedream/v4.5/edit",
  "mode": "character",
  "embed_markdown": "![](https://www.builder2.com/embed/job_d5e6f7g8-901/image)",
  "embed_html": "<iframe src=\"https://www.builder2.com/embed/job_d5e6f7g8-901\" width=\"100%\" height=\"500\" frameborder=\"0\" style=\"border:none;border-radius:12px;overflow:hidden;\" loading=\"lazy\"></iframe>"
}

# What gets sent to fal.ai internally:
# POST https://queue.fal.run/fal-ai/bytedance/seedream/v4.5/edit
# {
#   "prompt": "wearing a red dress at a gala event...",
#   "image_urls": ["https://example.com/photos/portrait.jpg"],
#   "image_size": "portrait_4_3"
# }

Character Model Selection

When a character is attached, the system selects the character mode default model for the content type instead of the standard default. Configure defaults from the dashboard Models page.

Content Type Standard Model Character Model
imageseedream/v4.5/text-to-imageseedream/v4.5/edit
infographicnano-banana-proseedream/v4.5/edit
videowan/v2.7/text-to-videominimax/video-01-subject-reference
ttsbytedance/seed-audio-1.0gemini-3.1-flash-tts
musicdiffrhythmdiffrhythm

6 Manage Slots

GET /api/v1/slots

List all your slots with status.

curl https://api.builder2.com/api/v1/slots \
  -H "Authorization: Bearer bk2_YOUR_KEY"

# Response 200 OK
{
  "slots": [
    {
      "key": "hero-banner",
      "url": "https://cdn.builder2.com/m/2eb8f23b-f0f3/hero-banner",
      "content_type": "image",
      "status": "ready",
      "created_at": "2026-06-13T01:32:59Z",
      "updated_at": "2026-06-13T01:33:05Z"
    },
    {
      "key": "thumbnail",
      "url": "https://cdn.builder2.com/m/2eb8f23b-f0f3/thumbnail",
      "content_type": "image",
      "status": "generating",
      "created_at": "2026-06-13T01:32:59Z",
      "updated_at": "2026-06-13T01:32:59Z"
    }
  ]
}
GET /api/v1/slots/:key

Get a single slot by key, including the active variant with preview URL.

curl https://api.builder2.com/api/v1/slots/hero-banner \
  -H "Authorization: Bearer bk2_YOUR_KEY"

# Response 200 OK
{
  "key": "hero-banner",
  "url": "https://cdn.builder2.com/m/2eb8f23b-f0f3/hero-banner",
  "content_type": "image",
  "status": "ready",
  "created_at": "2026-06-13T01:32:59Z",
  "updated_at": "2026-06-13T01:33:05Z",
  "active_variant": {
    "variant_id": "job_bbb60d20-028/hero-banner/1",
    "preview_url": "https://storage.nxdot.app/builder2-qitl/2eb8f23b/job_bbb60d20/hero-banner_1.png",
    "content_type": "image",
    "is_active": true
  }
}
POST /api/v1/slots/:key/regenerate

Regenerate media for an existing slot. The CDN URL stays the same.

Field Type Required Description
promptstringNoNew prompt (reuses last if omitted)
content_typestringNoChange type (keeps current if omitted)
qtyintNoVariants (2–4, default 2)
webhook_urlstringNoCallback URL on completion
curl -X POST https://api.builder2.com/api/v1/slots/hero-banner/regenerate \
  -H "Authorization: Bearer bk2_YOUR_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "prompt": "a dramatic mountain sunrise, cinematic lighting",
    "qty": 2,
    "webhook_url": "https://example.com/webhooks/builder2"
  }'

# Response 202 Accepted
{
  "job_id": "job_c7d8e9f0-135",
  "slot_key": "hero-banner",
  "slot_url": "https://cdn.builder2.com/m/2eb8f23b-f0f3/hero-banner"
}
PUT /api/v1/slots/:key/variant

Select which variant to serve at the slot's CDN URL.

curl -X PUT https://api.builder2.com/api/v1/slots/hero-banner/variant \
  -H "Authorization: Bearer bk2_YOUR_KEY" \
  -H "Content-Type: application/json" \
  -d '{"variant_id": "job_bbb60d20-028/hero-banner/2"}'

# Response 200 OK
{
  "message": "Variant updated"
}
DELETE /api/v1/slots/:key

Delete a slot and all its variants. The CDN URL will stop serving.

curl -X DELETE https://api.builder2.com/api/v1/slots/hero-banner \
  -H "Authorization: Bearer bk2_YOUR_KEY"

# Response 204 No Content

7 Jobs & Variants

GET /api/v1/jobs

List all generation jobs.

curl https://api.builder2.com/api/v1/jobs \
  -H "Authorization: Bearer bk2_YOUR_KEY"

# Response 200 OK
{
  "jobs": [
    {
      "job_id": "job_bbb60d20-028",
      "status": "completed",
      "content_type": "image",
      "created_at": "2026-06-13T01:32:59Z",
      "completed_at": "2026-06-13T01:33:05Z"
    },
    {
      "job_id": "job_a1f2e3d4-567",
      "status": "processing",
      "content_type": "image",
      "created_at": "2026-06-13T01:40:12Z",
      "completed_at": null
    }
  ]
}
GET /api/v1/jobs/:job_id

Get job detail. Status: pending → processing → completed | failed.

curl https://api.builder2.com/api/v1/jobs/job_bbb60d20-028 \
  -H "Authorization: Bearer bk2_YOUR_KEY"

# Response 200 OK
{
  "job_id": "job_bbb60d20-028",
  "status": "completed",
  "prompt": "a sunset over mountains, digital art",
  "content_type": "image",
  "created_at": "2026-06-13T01:32:59Z",
  "completed_at": "2026-06-13T01:33:05Z"
}
GET /api/v1/jobs/:job_id/variants

List all variants generated by a job, with preview URLs and dimensions.

curl https://api.builder2.com/api/v1/jobs/job_bbb60d20-028/variants \
  -H "Authorization: Bearer bk2_YOUR_KEY"

# Response 200 OK
{
  "variants": [
    {
      "variant_id": "job_bbb60d20-028/hero-banner/1",
      "slot_key": "hero-banner",
      "preview_url": "https://storage.nxdot.app/builder2-qitl/2eb8f23b/job_bbb60d20/hero-banner_1.png",
      "content_type": "image",
      "width": 1024,
      "height": 1024,
      "is_active": true,
      "created_at": "2026-06-13T01:33:03Z"
    },
    {
      "variant_id": "job_bbb60d20-028/hero-banner/2",
      "slot_key": "hero-banner",
      "preview_url": "https://storage.nxdot.app/builder2-qitl/2eb8f23b/job_bbb60d20/hero-banner_2.png",
      "content_type": "image",
      "width": 1024,
      "height": 1024,
      "is_active": false,
      "created_at": "2026-06-13T01:33:04Z"
    }
  ]
}

8 Account

GET /api/v1/user

Get your profile, plan, and quota usage.

curl https://api.builder2.com/api/v1/user \
  -H "Authorization: Bearer bk2_YOUR_KEY"

# Response 200 OK
{
  "id": "2eb8f23b-f0f3-47ab-a69d-8f162f7c9e6c",
  "email": "[email protected]",
  "plan": "free",
  "quota_used_this_month": 4,
  "quota_limit": 10
}

9 Full Example: Generate & Serve

# 1. Generate media
curl -X POST https://api.builder2.com/api/v1/build-media \
  -H "Authorization: Bearer bk2_YOUR_KEY" \
  -H "Content-Type: application/json" \
  -d '{"prompt":"minimalist logo for a coffee app","content_type":"image","media_slug":"logo","count":3,"image_size":"landscape_16_9"}'

{
  "job_id": "job_bbb60d20-028",
  "media_slug": "logo",
  "permanent_url": "https://cdn.builder2.com/w/logo/job_bbb60d20-028.jpeg",
  "media_url": "https://media.builder2.com/job_bbb60d20-028/1.png",
  "count": 3,
  "status": "generating",
  "model": "fal-ai/nano-banana-pro",
  "embed_markdown": "![](https://www.builder2.com/embed/job_bbb60d20-028/image)",
  "embed_html": "<iframe src=\"https://www.builder2.com/embed/job_bbb60d20-028\" ...></iframe>"
}

# 2. Use the permanent URL (serves default variant once ready)
<img src="https://cdn.builder2.com/w/logo/job_bbb60d20-028.jpeg" />

# 3. Embed in chat (markdown - works anywhere)
![](https://www.builder2.com/embed/job_bbb60d20-028/image)

# 4. Embed in web (iframe - rich interactive experience)
<iframe src="https://www.builder2.com/embed/job_bbb60d20-028"
  width="100%" height="500" frameborder="0"
  style="border:none;border-radius:12px;overflow:hidden;"
  loading="lazy"></iframe>

# 5. Access a specific variant (full-size)
<img src="https://cdn.builder2.com/w/logo/job_bbb60d20-028/2.png" />

# 6. Check job status (public, no auth needed)
curl https://www.builder2.com/api/v1/embed/job_bbb60d20-028/status

# 7. Change default variant
curl -X PUT https://api.builder2.com/api/v1/jobs/job_bbb60d20-028/default \
  -H "Authorization: Bearer bk2_YOUR_KEY" \
  -H "Content-Type: application/json" \
  -d '{"variant_index": 3}'

{ "message": "Default variant updated" }

# Permanent URL now serves variant #3
<img src="https://cdn.builder2.com/w/logo/job_bbb60d20-028.jpeg" />