---
name: bfl
description: Use when building applications that generate, edit, or manipulate images and video through the FLUX API. Reach for this skill when integrating FLUX models into production systems, handling async generation workflows, managing credits and billing, or implementing image/video editing features.
metadata:
    mintlify-proj: bfl
    version: "1.0"
---

# BFL (Black Forest Labs) FLUX API

## Product summary

BFL provides a REST API for generating and editing images and video using FLUX models. FLUX 3 is the latest unified model supporting text-to-video, image-to-video, video continuation, and image generation/editing with synchronized audio. FLUX.2 offers specialized models for different quality/speed tradeoffs (klein, pro, flex, max). The API is asynchronous: submit a request, receive a `polling_url`, poll until `Ready`, then download results within expiration windows (1–2 hours depending on endpoint).

**Key files and endpoints:**
- Primary endpoint: `https://api.bfl.ai` (global load balancing)
- Regional: `https://api.eu.bfl.ai`, `https://api.us.bfl.ai`
- Authentication: `x-key` header with API key from dashboard
- Async pattern: POST to submit, GET `polling_url` to check status
- Delivery URLs expire after 10 minutes to 2 hours; download immediately

**Primary docs:** https://docs.bfl.ai — see llms.txt for full page navigation.

## When to use

Reach for this skill when:
- Building image or video generation features into applications
- Implementing async workflows that submit tasks and poll for results
- Handling credit-based billing and rate limiting
- Choosing between FLUX models (klein for speed, pro for production, max for quality)
- Downloading and re-serving generated media
- Setting up webhooks for async notifications
- Integrating with MCP clients (Claude, Cursor) for creative workflows
- Fine-tuning models with LoRA training
- Implementing error handling for moderation, rate limits, and insufficient credits

## Quick reference

### API Request Pattern

All generation endpoints follow this pattern:

```bash
# 1. Submit request
curl -X POST https://api.bfl.ai/v1/flux-3-image \
  -H "x-key: $BFL_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"prompt": "...", "aspect_ratio": "16:9"}'

# Response: {"id": "...", "polling_url": "...", "cost": 0.XX, "output_mp": 1.5}

# 2. Poll for result
curl "$POLLING_URL" -H "x-key: $BFL_API_KEY"

# Response: {"status": "Ready", "result": {"sample": "https://delivery.*.bfl.ai/..."}}

# 3. Download within expiration window (1–2 hours)
curl -o image.png "$SAMPLE_URL"
```

### FLUX Model Selection

| Model | Best for | Speed | Quality | Cost | Multi-ref limit |
|-------|----------|-------|---------|------|-----------------|
| **FLUX 3** | Video + audio, latest image gen | Medium | High | $0.17–0.95/s video | N/A |
| **FLUX.2 [klein]** | Real-time, high volume | Sub-second | Good | $0.014–0.015/MP | 4 images |
| **FLUX.2 [pro]** | Production workflows | Fast | High | $0.03–0.045/MP | 8–10 images |
| **FLUX.2 [flex]** | Typography, fine control | Medium | High | $0.06/MP | 8–10 images |
| **FLUX.2 [max]** | Highest quality, grounding search | Slow | Highest | $0.07+/MP | 8–10 images |

### HTTP Status Codes

| Code | Meaning | Action |
|------|---------|--------|
| 200 | Success | Proceed with polling or result |
| 400 | Bad request | Check request format and required fields |
| 402 | Insufficient credits | Add credits to account |
| 403 | Forbidden | Verify API key and permissions |
| 422 | Invalid parameters | Check field names, types, and constraints |
| 429 | Rate limited | Wait and retry; max 24 concurrent requests (6 for kontext-max) |
| 500 | Server error | Retry after brief delay |
| 503 | Service unavailable | Retry with exponential backoff |

### Polling Response Statuses

| Status | Meaning | Next step |
|--------|---------|-----------|
| Pending, Reasoning, Generating | In progress | Keep polling |
| Ready | Complete | Download from `result.sample` |
| Request Moderated | Input blocked | Adjust prompt/image and resubmit |
| Content Moderated | Output blocked | Adjust prompt and resubmit |
| Error | Failed | Inspect error details, resubmit if transient |
| Task not found | ID expired | Submit new request |

### Key Parameters by Endpoint

**FLUX 3 Image (text-to-image/editing):**
- `prompt` (required): Description of image or edit instruction
- `images` (optional): Up to 10 base64 images for editing/multi-reference
- `aspect_ratio`: 21:9, 2:1, 16:9, 4:3, 1:1, 3:4, 9:16, 9:21 (default: auto)
- `resolution`: 768sq, 1k, 2k, 4k (default: 1k)
- `safety_tolerance`: 0–4 (default: 2; 0 = strictest)

**FLUX 3 Video (text-to-video/image-to-video/continuation):**
- `mode` (required): t2v, i2v, v2v, or draft_enhance
- `prompt` (required): Scene description or edit instruction
- `keyframes` (i2v): Base64 images or [[seconds, image], ...] pairs
- `start_video` (v2v): Base64 video to continue from
- `duration`: 5–20 seconds (default: auto)
- `resolution`: hd, fhd, qhd, uhd (default: hd)
- `draft`: true for fast preview (~1/3 cost)
- `generate_audio`: true/false (default: true)

**FLUX.2 Models (text-to-image/editing):**
- `prompt` (required): Text description
- `width`, `height`: Pixels (multiples of 32)
- `image_prompt` (optional): Base64 image for remix/editing
- `seed`: Integer for reproducibility
- `safety_tolerance`: 0–5 (default: 2)
- `output_format`: jpeg, png, webp (default: jpeg)

## Decision guidance

### When to use FLUX 3 vs FLUX.2

| Scenario | Use FLUX 3 | Use FLUX.2 |
|----------|-----------|-----------|
| Generating video with audio | ✓ | ✗ |
| Text-to-image only | Consider | ✓ (faster, cheaper) |
| Image editing with references | ✓ (up to 10) | ✓ (up to 10) |
| Real-time generation needed | ✗ | ✓ (klein) |
| Production image workflows | Consider | ✓ (pro/max) |
| Grounding search (real-time info) | ✗ | ✓ (max only) |

### When to use polling vs webhooks

| Approach | Best for | Trade-offs |
|----------|----------|-----------|
| **Polling** | Simple scripts, testing, low volume | Requires polling loop, higher latency perception |
| **Webhooks** | Production systems, high volume, async workflows | Requires public endpoint, webhook verification, retry logic |

### When to download vs stream

| Approach | Best for | Trade-offs |
|----------|----------|-----------|
| **Download immediately** | All production use | URLs expire in 1–2 hours; must handle expiration |
| **Re-serve from CDN** | High-traffic applications | Requires storage infrastructure, but decouples from BFL URLs |

## Workflow

### Typical image generation task

1. **Prepare the request.** Write a detailed prompt describing subject, lighting, style, and composition. For text in images, quote exact strings. Choose model (klein for speed, pro for production, max for quality).

2. **Submit the request.** POST to the appropriate endpoint (`/v1/flux-3-image`, `/v1/flux-2-pro`, etc.) with `x-key` header and JSON body. Capture the `polling_url` from the response.

3. **Poll for completion.** Loop: sleep 1–2 seconds, GET the `polling_url`, check `status`. Stop when status is `Ready`, `Request Moderated`, `Content Moderated`, `Error`, or `Task not found`.

4. **Handle the result.** If `Ready`, download `result.sample` within the expiration window (1–2 hours). If moderated or error, inspect `details` field and adjust the prompt.

5. **Store or serve the image.** Download to local storage or CDN immediately. Do not rely on delivery URLs for long-term serving; they expire and have no CORS support.

### Typical video generation task

1. **Choose a mode.** Text-to-video (t2v), image-to-video with keyframes (i2v), video continuation (v2v), or draft-then-enhance.

2. **Submit with draft mode first.** Set `draft: true` to get a fast preview (~1/3 cost) in HD. Inspect motion and timing.

3. **Enhance the draft.** If satisfied, extract the `draft_cache` from the result and submit with `mode: "draft_enhance"` to render at full quality (fhd, qhd, uhd).

4. **Poll and download.** Same polling pattern as images. Video URLs expire after ~1 hour; download promptly.

5. **Handle audio.** Audio is generated by default with the video. Disable with `generate_audio: false` if needed.

### Typical editing task

1. **Prepare reference images.** Upload up to 10 base64-encoded images for multi-reference editing or style transfer.

2. **Write an edit instruction.** Describe what should change (e.g., "change the jacket to red") and what should stay the same (e.g., "keep the face and pose").

3. **Submit with images.** POST to the image endpoint with `prompt` (edit instruction) and `images` array. For FLUX 3, use bounding boxes in the prompt to target specific regions.

4. **Poll and download.** Same pattern as generation.

## Common gotchas

- **Forgetting to use `polling_url`.** Always use the `polling_url` returned in the submit response, not a hardcoded endpoint. It points to the region holding your task.

- **Delivery URLs expire quickly.** Images expire after 1–2 hours; videos after ~1 hour. Download immediately upon `Ready` status. Do not store URLs for later use.

- **No CORS on delivery URLs.** Cannot fetch delivery URLs directly from browsers. Download server-side and re-serve from your own infrastructure.

- **Rate limits are concurrent, not per-second.** Max 24 concurrent requests (6 for kontext-max). Hitting 429 means wait for a running task to finish, not retry in a loop.

- **Insufficient credits returns 402.** Check account balance before submitting large batches. Add credits via dashboard.

- **Moderation blocks at two stages.** `Request Moderated` = input blocked before processing (no charge). `Content Moderated` = output blocked after processing (charge applied). Adjust prompt and resubmit.

- **Image dimensions must be multiples of 32.** FLUX.2 requires width/height divisible by 32. FLUX 3 uses aspect ratios instead.

- **Prompt upsampling not available on klein.** Write detailed, descriptive prompts for klein; it does not auto-expand short prompts.

- **Negative prompts don't work.** FLUX responds to what you describe, not what to avoid. Use positive descriptions instead.

- **Webhook payloads changed.** If checking for `SUCCESS` status, update to `Ready`. See release notes for migration details.

- **Regional endpoints require polling_url.** When using `api.eu.bfl.ai` or `api.us.bfl.ai`, always use the returned `polling_url`, not a hardcoded endpoint.

## Verification checklist

Before submitting work:

- [ ] API key is set in environment and not exposed in code
- [ ] Request uses correct endpoint for the model (flux-3-image, flux-2-pro, etc.)
- [ ] All required fields are present (prompt, mode for video, etc.)
- [ ] Image dimensions are multiples of 32 (FLUX.2) or valid aspect ratio (FLUX 3)
- [ ] Polling loop checks for all terminal statuses (Ready, Error, Moderated, Task not found)
- [ ] Downloaded images are saved immediately; URLs are not stored for later use
- [ ] Error handling covers 402 (credits), 429 (rate limit), 422 (validation), 503 (retry)
- [ ] Webhook verification (if used) validates signature with webhook_secret
- [ ] Multi-reference images are base64-encoded and within size limits
- [ ] Moderation sensitivity (safety_tolerance) is appropriate for use case
- [ ] Concurrent request count respects limits (24 max, 6 for kontext-max)

## Resources

**Full documentation navigation:** https://docs.bfl.ai/llms.txt

**Critical pages:**
- [Quick Start & API Setup](https://docs.bfl.ai/quick_start/get_started) — Create account, add credits, make first call
- [Integration Guidelines](https://docs.bfl.ai/api_integration/integration_guidelines) — Polling, endpoints, image handling, best practices
- [FLUX 3 Overview](https://docs.bfl.ai/flux_3/flux3_overview) — Video modes, draft mode, specifications, audio

---

> For additional documentation and navigation, see: https://docs.bfl.ml/llms.txt