Tutorials

FLUX 1.1 Pro API Python Tutorial: Generate Images Fast

AI API Playbook · · 8 min read
FLUX 1.1 Pro API Python Tutorial: Generate Images Fast

FLUX 1.1 Pro API Python Tutorial: Image Generation in Under 5 Minutes

3 numbers before you read further: FLUX 1.1 Pro generates images in ~8 seconds average latency (6x faster than FLUX 1.0 Pro), costs $0.04 per image at 1MP resolution, and scored 72.6% on the ELO benchmark — outperforming Midjourney v6 and DALL-E 3 on prompt adherence in Black Forest Labs’ internal evaluations.

This tutorial walks you from zero to working image generation code using the FLUX 1.1 Pro API via two routes: the official BFL (Black Forest Labs) endpoint and Replicate. You’ll get copy-paste-ready Python that handles authentication, generation, polling, error recovery, and cost tracking.


Prerequisites

You need three things before writing a single line of code:

1. API Access

Choose one provider (or both — the code handles both):

  • Black Forest Labs (BFL) API: Register at api.bfl.ml. Free tier gives you limited credits; paid usage is billed per image.
  • Replicate: Register at replicate.com. FLUX 1.1 Pro is available as black-forest-labs/flux-1.1-pro. $0.04/image.

2. Python Environment

Python 3.8+ required. Create an isolated environment:

python -m venv flux-env
source flux-env/bin/activate  # Windows: flux-env\Scripts\activate

pip install requests pillow python-dotenv replicate
  • requests: HTTP client for BFL’s REST API
  • pillow: Save and inspect returned images
  • python-dotenv: Keep secrets out of your code
  • replicate: Official SDK for Replicate’s API

3. Environment File

Create .env in your project root:

BFL_API_KEY=your_bfl_key_here
REPLICATE_API_TOKEN=your_replicate_token_here

Never hardcode API keys. Never commit .env to git — add it to .gitignore now.


API Parameter Reference

Before writing code, know what you’re sending. Both providers accept overlapping parameters.

ParameterTypeDefaultValid Range / OptionsWhat It Affects
promptstringrequired1–2048 charactersPrimary generation instruction
widthinteger1440256–1440 (BFL), 256–1408 (Replicate)Output image width in pixels
heightinteger1440256–1440 (BFL), 256–1408 (Replicate)Output image height in pixels
stepsinteger281–50Denoising steps; more = slower + sharper
guidancefloat3.51.5–5.0Prompt adherence vs. creativity trade-off
safety_toleranceinteger20–6Content filter strictness (0 = strictest)
output_formatstring"jpeg""jpeg", "png"File format; PNG adds ~30% size, preserves transparency
seedintegerrandomany intSet for reproducible outputs
prompt_upsamplingbooleanfalsetrue / falseBFL internal prompt expansion — adds variance
aspect_ratiostring"1:1""1:1", "16:9", "4:3", "3:4", etc.Replicate-specific shorthand for dimensions

Note on guidance: Values below 2.0 give the model more creative freedom but reduce prompt accuracy. Above 4.5, you get diminishing returns and occasional artifacts. 3.5 is the documented sweet spot.


Authentication and Setup

FLUX 1.1 Pro’s BFL endpoint uses a synchronous request/poll pattern — you POST a job, receive a task ID, then poll until the image is ready. Replicate uses a similar async pattern but wraps it in their SDK.

# flux_setup.py
# Verify your credentials work before building anything else.
# Run this file first — if it prints your key prefix, you're good.

import os
import requests
from dotenv import load_dotenv

# Load .env from current directory
load_dotenv()

BFL_API_KEY = os.getenv("BFL_API_KEY")
REPLICATE_API_TOKEN = os.getenv("REPLICATE_API_TOKEN")

# BFL base URL — this is the v1 production endpoint as of 2024
BFL_BASE_URL = "https://api.bfl.ml/v1"

def verify_bfl_auth():
    """
    BFL doesn't have a dedicated /me endpoint.
    We verify by hitting the models list endpoint — 401 = bad key.
    """
    headers = {"X-Key": BFL_API_KEY}
    
    # /flux-pro-1.1 is the correct model slug for FLUX 1.1 Pro
    # A malformed request returns 422, not 401 — that means auth passed
    response = requests.post(
        f"{BFL_BASE_URL}/flux-pro-1.1",
        headers=headers,
        json={"prompt": "test"},  # Intentionally minimal to trigger fast validation
        timeout=10
    )
    
    if response.status_code == 401:
        raise ValueError("BFL_API_KEY is invalid or expired")
    elif response.status_code in (200, 422):
        # 422 = request schema error, but auth succeeded
        print(f"BFL auth OK — key prefix: {BFL_API_KEY[:8]}...")
        return True
    else:
        print(f"Unexpected status {response.status_code}: {response.text}")
        return False

def verify_replicate_auth():
    """
    Replicate SDK raises replicate.exceptions.ReplicateError on bad tokens.
    """
    import replicate
    os.environ["REPLICATE_API_TOKEN"] = REPLICATE_API_TOKEN
    
    try:
        # account() is a lightweight call that validates the token
        account = replicate.account.current()
        print(f"Replicate auth OK — username: {account.username}")
        return True
    except Exception as e:
        print(f"Replicate auth failed: {e}")
        return False

if __name__ == "__main__":
    if BFL_API_KEY:
        verify_bfl_auth()
    else:
        print("BFL_API_KEY not set — skipping")
    
    if REPLICATE_API_TOKEN:
        verify_replicate_auth()
    else:
        print("REPLICATE_API_TOKEN not set — skipping")

Run this before anything else: python flux_setup.py


Core Implementation

Basic: Single Image Generation (BFL Endpoint)

The BFL API is a two-step process. POST the job, then GET the result by polling.

# flux_basic.py
# Generates one image using the BFL REST API directly.
# No SDK dependency — useful when you want full control over the HTTP layer.

import os
import time
import requests
from pathlib import Path
from dotenv import load_dotenv

load_dotenv()

BFL_API_KEY = os.getenv("BFL_API_KEY")
BFL_BASE_URL = "https://api.bfl.ml/v1"

def generate_image_bfl(
    prompt: str,
    width: int = 1024,
    height: int = 1024,
    guidance: float = 3.5,
    steps: int = 28,
    seed: int = None,
    output_path: str = "output.jpg"
) -> str:
    """
    Submit a generation job to BFL and poll until complete.
    Returns the local file path of the saved image.
    
    Typical wait time: 8–15 seconds depending on server load.
    """
    
    headers = {
        "X-Key": BFL_API_KEY,
        "Content-Type": "application/json"
    }
    
    # Build payload — only include seed if explicitly set
    # Omitting seed means every run produces a different image
    payload = {
        "prompt": prompt,
        "width": width,
        "height": height,
        "guidance": guidance,
        "steps": steps,
        "output_format": "jpeg",
        "safety_tolerance": 2,  # Default: blocks explicit content, allows most creative work
    }
    
    if seed is not None:
        payload["seed"] = seed
    
    # Step 1: Submit the job
    print(f"Submitting job for prompt: '{prompt[:60]}...'")
    response = requests.post(
        f"{BFL_BASE_URL}/flux-pro-1.1",
        headers=headers,
        json=payload,
        timeout=30
    )
    response.raise_for_status()
    
    job_data = response.json()
    task_id = job_data.get("id")
    
    if not task_id:
        raise ValueError(f"No task ID in response: {job_data}")
    
    print(f"Job submitted. Task ID: {task_id}")
    
    # Step 2: Poll for completion
    # BFL recommends polling every 500ms. More frequent = no benefit, may rate-limit.
    poll_url = f"{BFL_BASE_URL}/get_result"
    max_attempts = 60  # 60 * 0.5s = 30s max wait
    
    for attempt in range(max_attempts):
        time.sleep(0.5)
        
        result_response = requests.get(
            poll_url,
            headers=headers,
            params={"id": task_id},
            timeout=10
        )
        result_response.raise_for_status()
        result = result_response.json()
        
        status = result.get("status")
        
        if status == "Ready":
            # Image URL is temporary — download immediately, it expires
            image_url = result["result"]["sample"]
            print(f"Generation complete after {(attempt + 1) * 0.5:.1f}s")
            
            # Download the image
            img_response = requests.get(image_url, timeout=30)
            img_response.raise_for_status()
            
            Path(output_path).write_bytes(img_response.content)
            print(f"Image saved to: {output_path}")
            return output_path
            
        elif status in ("Error", "Failed"):
            raise RuntimeError(f"Generation failed: {result.get('result', 'Unknown error')}")
            
        elif status in ("Pending", "Processing"):
            # Normal — keep waiting
            if attempt % 10 == 0:  # Print progress every 5 seconds
                print(f"  Status: {status} ({(attempt + 1) * 0.5:.1f}s elapsed)")
        else:
            print(f"  Unknown status '{status}' — continuing to poll")
    
    raise TimeoutError(f"Job {task_id} did not complete within 30 seconds")


if __name__ == "__main__":
    path = generate_image_bfl(
        prompt="A detailed close-up of a mechanical watch movement, macro photography, studio lighting, sharp focus on gears",
        width=1024,
        height=1024,
        seed=42,  # Fixed seed for reproducibility while testing
        output_path="watch_movement.jpg"
    )
    print(f"Done: {path}")

Intermediate: Replicate SDK with Batch Processing

Replicate’s SDK handles polling internally, which simplifies batch generation.

# flux_replicate.py
# Uses the official Replicate SDK.
# Preferred when: you want async, you're already on Replicate, or you want webhooks.

import os
import replicate
import requests
from pathlib import Path
from dotenv import load_dotenv
from concurrent.futures import ThreadPoolExecutor, as_completed

load_dotenv()

# Replicate SDK reads this env var automatically
os.environ["REPLICATE_API_TOKEN"] = os.getenv("REPLICATE_API_TOKEN", "")

# Model identifier — pin to specific version in production to avoid breaking changes
FLUX_MODEL = "black-forest-labs/flux-1.1-pro"

def generate_single_replicate(
    prompt: str,
    aspect_ratio: str = "1:1",
    output_format: str = "jpeg",
    output_quality: int = 80,
    seed: int = None,
    output_path: str = "output.jpg"
) -> str:
    """
    Single image generation via Replicate.
    Replicate's SDK blocks until the prediction completes — no manual polling needed.
    """
    
    inputs = {
        "prompt": prompt,
        "aspect_ratio": aspect_ratio,
        "output_format": output_format,
        "output_quality": output_quality,  # JPEG quality 1–100; 80 is a good size/quality balance
        "safety_tolerance": 2,
        "prompt_upsampling": False,  # Disable for predictable outputs; enable for creative exploration
    }
    
    if seed is not None:
        inputs["seed"] = seed
    
    output = replicate.run(FLUX_MODEL, input=inputs)
    
    # Replicate returns a FileOutput object (or URL string depending on SDK version)
    # Handle both cases
    if hasattr(output, 'url


> **Note:** If you're integrating multiple AI models into one pipeline, [AtlasCloud](https://www.atlascloud.ai?ref=JPM683) provides unified API access to 300+ models including Kling, Flux, Seedance, Claude, and GPT — one API key, no per-provider setup. New users get a 25% credit bonus on first top-up (up to $100).

Try this API on AtlasCloud

AtlasCloud

Frequently Asked Questions

How much does FLUX 1.1 Pro API cost per image and how does pricing compare between BFL and Replicate?

FLUX 1.1 Pro costs $0.04 per image at 1MP resolution on the Black Forest Labs (BFL) direct API at api.bfl.ml. Replicate also offers FLUX 1.1 Pro access with per-image billing that may vary slightly based on resolution and compute time. At $0.04/image, generating 1,000 images costs $40, making it significantly more cost-efficient than many competitors. BFL offers a free tier with limited credits fo

What is FLUX 1.1 Pro API latency and how fast does it generate images compared to the previous version?

FLUX 1.1 Pro achieves an average latency of approximately 8 seconds per image generation, which is 6x faster than FLUX 1.0 Pro. This speed improvement is critical for production applications requiring near-real-time generation. Because the BFL API uses an asynchronous polling model rather than a synchronous response, your Python code must implement a polling loop — typically checking every 1-2 sec

How does FLUX 1.1 Pro benchmark score compare to Midjourney v6 and DALL-E 3?

FLUX 1.1 Pro scored 72.6% on the ELO benchmark in Black Forest Labs' internal evaluations, outperforming both Midjourney v6 and DALL-E 3 specifically on prompt adherence metrics. ELO benchmarks measure head-to-head preference rates where human evaluators choose between outputs — a 72.6% ELO score indicates FLUX 1.1 Pro was preferred in roughly 72.6% of direct comparisons. This makes it particularl

What Python code structure is needed to handle FLUX 1.1 Pro API authentication, polling, and error recovery?

The FLUX 1.1 Pro BFL API requires a Bearer token passed in the Authorization header — set your BFL_API_KEY environment variable and load it via os.environ.get('BFL_API_KEY') to avoid hardcoding credentials. The generation workflow has two steps: (1) POST to the generation endpoint to receive a job ID, then (2) poll a status endpoint every 1-2 seconds until status returns 'Ready' with an image URL.

Tags

Flux FLUX 1.1 Pro Python Image Generation API 2026

Related Articles