# FLUX.1 [dev] with Controlnets and Loras · Differential Diffusion API

> FLUX.1 [dev] image edit driven by a change map that sets how strongly each region is altered

Transforms a source image region by region, using a change map image to control how much each area is modified. Requires `prompt`, `image_url` and `change_map_image_url`. It also accepts LoRAs, ControlNets, IP-Adapters and a reference image. `num_inference_steps` runs 1 to 50 and `num_images` up to 10, with png or jpeg output.

- Model id: `flux-general/differential-diffusion`
- Made by: Black Forest Labs
- Category: Image Editing
- Output: image
- Estimated price per run: $0.138 / image (cheapest run $0.138 (138 API credits))
- Run: `POST https://api.doitong.com/v1/run/flux-general/differential-diffusion`
- Quote: `POST https://api.doitong.com/v1/quote/flux-general/differential-diffusion`
- Docs page: https://doitong.com/en-US/developers/models/flux-general/differential-diffusion

## Pricing

Price: **$0.138 / image**. Estimated from the typical cost of one run, per output (`num_images`). The quote is exactly what the run charges.

The full example input below costs $0.138 = 138 API credits (1 image × 138 API credits).

Prices are the upstream price in USD, paid from the API balance in API credits (1000 API credits = 1 USD). `POST https://api.doitong.com/v1/quote/flux-general/differential-diffusion` with the same JSON body returns the exact price for that input; the quote is exactly what a run charges. Invalid input is never charged and failed or canceled requests are refunded automatically.

## Input parameters

Send either the canonical name or the native field name (not both). Canonical names are the same across models.

| Parameter | Canonical name | Type | Required | Default | Allowed values / range | Description |
|---|---|---|---|---|---|---|
| `prompt` |  | string | yes |  |  | Prompt that guides image generation. |
| `image_size` |  | object {width, height} \| enum (string) | no |  | `square_hd`, `square`, `portrait_4_3`, `portrait_16_9`, `landscape_4_3`, `landscape_16_9` | Dimensions of the generated image. |
| `num_inference_steps` |  | integer | no | `28` | 1 – 50 | Count of inference steps to run. |
| `seed` |  | integer \| null | no |  |  | Seed for reproducible images: an identical prompt and seed produce an identical image when the model version is unchanged. |
| `loras` |  | array of object {path, scale} | no | `[]` |  | LoRAs whose combined effect produces the generated image, with no limit on how many you supply. |
| `loras[].path` |  | string | yes |  |  | Location of the LoRA weights, specified as a URL or path. |
| `loras[].scale` |  | object \| number | no | `1` |  | Scaling applied to LoRA weights before they are merged into the base model. Supply a dictionary of the form {"layer_name":layer_scale} to set individual layer scales; unspecified layers use 1.0. |
| `control_loras` |  | array of object {path, scale, control_image_url, preprocess} | no | `[]` |  | Control-image LoRAs merged into a combined configuration for generating the final image; the number supplied is unrestricted. |
| `control_loras[].path` |  | string | yes |  |  | Location of the LoRA weights, specified as a URL or path. |
| `control_loras[].scale` |  | object \| number | no | `1` |  | Scaling applied to LoRA weights before they are merged into the base model. Supply a dictionary of the form {"layer_name":layer_scale} to set individual layer scales; unspecified layers use 1.0. |
| `control_loras[].control_image_url` |  | string (image URL) | yes |  |  | Image URL supplying the control image. |
| `control_loras[].preprocess` |  | enum (string) | no | `None` | `canny`, `depth`, `None` | Preprocessing method applied to the supplied image. |
| `controlnets` |  | array of object {path, config_url, variant, control_image_url, mask_image_url, mask_threshold, conditioning_scale, start_percentage, end_percentage} | no | `[]` |  | ControlNet configuration for image generation, currently limited to a single ControlNet. |
| `controlnets[].path` |  | string | yes |  |  | ControlNet weight location, specified as a URL or path. |
| `controlnets[].config_url` |  | string \| null | no |  |  | Optional URL pointing to the ControlNet's config.json file. |
| `controlnets[].variant` |  | string \| null | no |  |  | Optional variant for use with a Hugging Face repository key. |
| `controlnets[].control_image_url` |  | string (image URL) | yes |  |  | Image URL supplying the control image. |
| `controlnets[].mask_image_url` |  | string (image URL) | no |  |  | Mask URL associated with the control image. |
| `controlnets[].mask_threshold` |  | number | no | `0.5` | 0.01 – 0.99 | Mask threshold value. |
| `controlnets[].conditioning_scale` |  | number | no | `1` | 0 – 2 | Scaling applied to ControlNet weights before they are merged into the base model. |
| `controlnets[].start_percentage` |  | number | no | `0` | 0 – 1 | Percentage of total timesteps at which ControlNet starts influencing image generation. |
| `controlnets[].end_percentage` |  | number | no | `1` | 0 – 1 | Percentage of total timesteps at which ControlNet stops influencing image generation. |
| `controlnet_unions` |  | array of object {path, config_url, variant, controls} | no | `[]` |  | ControlNet union configuration for image generation, subject to the current single-ControlNet restriction. |
| `controlnet_unions[].path` |  | string | yes |  |  | ControlNet weight location, specified as a URL or path. |
| `controlnet_unions[].config_url` |  | string \| null | no |  |  | Optional URL pointing to the ControlNet's config.json file. |
| `controlnet_unions[].variant` |  | string \| null | no |  |  | Optional variant for use with a Hugging Face repository key. |
| `controlnet_unions[].controls` |  | array of object {control_image_url, mask_image_url, control_mode, conditioning_scale, mask_threshold, start_percentage, end_percentage} | yes |  |  | Control images and associated modes supplied to the ControlNet. |
| `controlnet_unions[].controls[].control_image_url` |  | string (image URL) | yes |  |  | Image URL supplying the control image. |
| `controlnet_unions[].controls[].mask_image_url` |  | string (image URL) | no |  |  | Mask URL associated with the control image. |
| `controlnet_unions[].controls[].control_mode` |  | enum (string) | yes |  | `canny`, `tile`, `depth`, `blur`, `pose`, `gray`, `low-quality` | Control mode used by Flux Controlnet Union. Options: canny guides generation with edges; tile guides it with tiles; depth guides it with a grayscale depth map; blur blurs the image; pose guides generation with the image's pose; gray makes the image grayscale; low-quality produces a low-quality version of the image. |
| `controlnet_unions[].controls[].conditioning_scale` |  | number | no | `1` | 0 – 2 | Scaling applied to ControlNet weights before they are merged into the base model. |
| `controlnet_unions[].controls[].mask_threshold` |  | number | no | `0.5` | 0.01 – 0.99 | Mask threshold value. |
| `controlnet_unions[].controls[].start_percentage` |  | number | no | `0` | 0 – 1 | Percentage of total timesteps at which ControlNet starts influencing image generation. |
| `controlnet_unions[].controls[].end_percentage` |  | number | no | `1` | 0 – 1 | Percentage of total timesteps at which ControlNet stops influencing image generation. |
| `ip_adapters` |  | array of object {path, subfolder, weight_name, image_encoder_path, image_encoder_subfolder, image_encoder_weight_name, image_url, mask_image_url, mask_threshold, scale} | no | `[]` |  | IP-Adapter applied during image generation. |
| `ip_adapters[].path` |  | string | yes |  |  | IP-Adapter location on Hugging Face. |
| `ip_adapters[].subfolder` |  | string \| null | no |  |  | Subfolder containing the ip_adapter weights. |
| `ip_adapters[].weight_name` |  | string \| null | no |  |  | Safetensors filename for the IP-Adapter's weights. |
| `ip_adapters[].image_encoder_path` |  | string | yes |  |  | IP-Adapter image encoder location, such as 'openai/clip-vit-large-patch14'. |
| `ip_adapters[].image_encoder_subfolder` |  | string \| null | no |  |  | Subfolder containing weights for the image encoder. |
| `ip_adapters[].image_encoder_weight_name` |  | string \| null | no |  |  | Image encoder name. |
| `ip_adapters[].image_url` |  | string (image URL) | yes |  |  | Conditioning image URL supplied to the IP-Adapter. |
| `ip_adapters[].mask_image_url` |  | string (image URL) \| null | no |  |  | Mask URL associated with the control image. |
| `ip_adapters[].mask_threshold` |  | number | no | `0.5` | 0.01 – 0.99 | Mask threshold value. |
| `ip_adapters[].scale` |  | number | yes |  |  | IP-Adapter scaling factor. |
| `easycontrols` |  | array of object {control_method_url, scale, image_url, image_control_type} | no | `[]` |  | EasyControl inputs applied during image generation. |
| `easycontrols[].control_method_url` |  | string | yes |  |  | Control method's safetensor weight URL, or a supported identifier: `canny`, `depth`, `hedsketch`, `inpainting`, `pose`, `seg`, `subject`, `ghibli`. |
| `easycontrols[].scale` |  | number | no | `1` | 0 – 2 | Control method scaling factor. |
| `easycontrols[].image_url` |  | string (image URL) | yes |  |  | Image URL supplying a control input. |
| `easycontrols[].image_control_type` |  | enum (string) | yes |  | `subject`, `spatial` | Image control mode; accepts either `spatial` or `subject`. |
| `fill_image` |  | object {fill_image_url} \| null | no |  |  | Input image that guides generation and can supply content for masked regions. |
| `fill_image.fill_image_url` |  | string (image URL) \| array of image URL | no | `[]` |  | Image URLs for filling via redux prompting. |
| `guidance_scale` |  | number | no | `3.5` | 0 – 20 | Prompt-adherence strength for image selection, expressed as CFG (Classifier Free Guidance). |
| `real_cfg_scale` |  | number | no | `3.5` | 0 – 5 | Prompt-adherence strength for image selection, expressed as CFG (Classifier Free Guidance). |
| `use_real_cfg` |  | boolean | no | `false` |  | Classical CFG switch, automatically enabled with XLabs IP-Adapter v1. The guidance behavior matches that of models such as SD1.5 and SDXL. |
| `use_cfg_zero` |  | boolean | no | `false` |  | Enables CFG-zero initialization sampling, described at https://arxiv.org/abs/2503.18886. |
| `num_images` | `num_outputs` | integer | no | `1` | 1 – 10 | Set how many images to generate; this choice is fixed at 1 when output is streamed. |
| `enable_safety_checker` |  | boolean | no | `true` |  | Safety checking, which returns black images in place of any images flagged unsafe. A value of true enables checking; false disables it only for authorized accounts, while requests without authorization are checked regardless. |
| `reference_image_url` |  | string (image URL) | no |  |  | Image URL used for Reference-Only guidance. |
| `reference_strength` |  | number | no | `0.65` | -3 – 3 | Reference-image influence during reference_only generation; without a supplied reference image, this strength setting has no effect. |
| `reference_start` |  | number | no | `0` | 0 – 1 | Reference guidance start point, expressed as a percentage of all timesteps. |
| `reference_end` |  | number | no | `1` | 0 – 1 | Reference guidance end point, expressed as a percentage of all timesteps. |
| `base_shift` |  | number | no | `0.5` | 0.01 – 5 | Baseline shift applied to scheduled timesteps. |
| `max_shift` |  | number | no | `1.15` | 0.01 – 5 | Maximum shift applied to scheduled timesteps. |
| `output_format` |  | enum (string) | no | `png` | `jpeg`, `png` | File format for the resulting image. |
| `use_beta_schedule` |  | boolean | no | `false` |  | Controls whether to use beta sigmas. |
| `sigma_schedule` |  | string \| null | no |  |  | Sigma schedule used during denoising. |
| `scheduler` |  | enum (string) | no | `euler` | `euler`, `dpmpp_2m` | Scheduler used during denoising. |
| `negative_prompt` |  | string | no | `` |  | Negative prompt processed with NAG by default to discourage the specified unwanted features in generated images. |
| `nag_scale` |  | number | no | `3` | ≤ 10, > 1 | Negative-prompt avoidance controlled by the NAG scale: increasing it makes the generated image less like the negative description. |
| `nag_tau` |  | number | no | `2.5` | > 0 | NAG tau setting for hidden-state normalization; leaving it unchanged is recommended. Raising it weakens normalization and risks unexpected departures from the original image. |
| `nag_alpha` |  | number | no | `0.25` | ≤ 1, > 0 | NAG alpha sets how much the positive prompt redirects normalized guidance combining the positive and negative prompts. This final weighting gives the positive prompt more influence at lower settings and reduces redirection at higher settings. |
| `nag_end` |  | number | no | `0.25` | ≤ 1, > 0 | NAG cutoff expressed as a proportion of the generation steps. FLUX's original attention processors take over after NAG has run for that initial proportion. |
| `image_url` | `image` | string (image URL) | yes |  |  | Image URL supplying the initial image. |
| `change_map_image_url` |  | string (image URL) | yes |  |  | URL pointing to the change map. |
| `strength` |  | number | no | `0.85` | 0.01 – 1 | Differential diffusion strength, spanning preservation of the original at 0.0 to a complete remake at 1.0. |

File parameters (`reference_image_url`, `image`, `change_map_image_url`) take a public `https://` URL, a `data:` URI up to 10 MB, or the `file_url` of an upload from `POST /files`.

## Example input

Required parameters only:

```json
{
  "prompt": "A red fox trots through fresh snow at sunrise, soft golden light, shallow depth of field",
  "image": "https://content.doitong.com/images/showcase/v3/gen_fox_cartoon.jpg",
  "change_map_image_url": "https://content.doitong.com/images/showcase/v3/gen_fox_cartoon.jpg"
}
```

A fuller example:

```json
{
  "prompt": "A red fox trots through fresh snow at sunrise, soft golden light, shallow depth of field",
  "image_url": "https://content.doitong.com/images/showcase/v3/gen_fox_cartoon.jpg",
  "change_map_image_url": "https://content.doitong.com/images/showcase/v3/gen_fox_cartoon.jpg"
}
```

## Run it

Set `DOITONG_API_KEY` to a key from https://doitong.com/developers/dashboard#keys. `?wait=20` returns the finished request in the same call when it is ready within 20 seconds; otherwise poll `GET /requests/{id}` (it also accepts `?wait=`), or pass `webhook_url`.

### curl

```bash
# Run the model; wait up to 20 s for the finished result in the same call
curl -X POST "https://api.doitong.com/v1/run/flux-general/differential-diffusion?wait=20" \
  -H "Authorization: Bearer $DOITONG_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "prompt": "A red fox trots through fresh snow at sunrise, soft golden light, shallow depth of field",
    "image_url": "https://content.doitong.com/images/showcase/v3/gen_fox_cartoon.jpg",
    "change_map_image_url": "https://content.doitong.com/images/showcase/v3/gen_fox_cartoon.jpg"
  }'

# Still "queued" or "running"? Poll with the id from the response:
curl "https://api.doitong.com/v1/requests/REQUEST_ID?wait=20" \
  -H "Authorization: Bearer $DOITONG_API_KEY"
```

### JavaScript

```javascript
const API = "https://api.doitong.com/v1";
const headers = {
  "Authorization": "Bearer " + process.env.DOITONG_API_KEY,
  "Content-Type": "application/json",
};

// Run the model; wait up to 20 s for the finished result in the same call
let res = await fetch(API + "/run/flux-general/differential-diffusion?wait=20", {
  method: "POST",
  headers,
  body: JSON.stringify({
    "prompt": "A red fox trots through fresh snow at sunrise, soft golden light, shallow depth of field",
    "image_url": "https://content.doitong.com/images/showcase/v3/gen_fox_cartoon.jpg",
    "change_map_image_url": "https://content.doitong.com/images/showcase/v3/gen_fox_cartoon.jpg"
  }),
});
let request = await res.json();
if (!res.ok) throw new Error(request.error.code + ": " + request.error.message);

// Not finished yet: long-poll until it is
while (request.status === "queued" || request.status === "running") {
  res = await fetch(API + "/requests/" + request.id + "?wait=20", { headers });
  request = await res.json();
}
if (request.status !== "succeeded") throw new Error(JSON.stringify(request.error));
console.log(request.outputs.map((o) => o.url), request.cost.credits + " API credits ($" + request.cost.usd + ")");
```

### Python

```python
import os
import requests

API = "https://api.doitong.com/v1"
headers = {"Authorization": "Bearer " + os.environ["DOITONG_API_KEY"]}

payload = {
    "prompt": "A red fox trots through fresh snow at sunrise, soft golden light, shallow depth of field",
    "image_url": "https://content.doitong.com/images/showcase/v3/gen_fox_cartoon.jpg",
    "change_map_image_url": "https://content.doitong.com/images/showcase/v3/gen_fox_cartoon.jpg",
}

# Run the model; wait up to 20 s for the finished result in the same call
r = requests.post(API + "/run/flux-general/differential-diffusion", params={"wait": 20}, json=payload, headers=headers)
request = r.json()
if not r.ok:
    raise RuntimeError(request["error"]["code"] + ": " + request["error"]["message"])

# Not finished yet: long-poll until it is
while request["status"] in ("queued", "running"):
    request = requests.get(API + "/requests/" + request["id"], params={"wait": 20}, headers=headers).json()
if request["status"] != "succeeded":
    raise RuntimeError(request["error"])
print([o["url"] for o in request["outputs"]], request["cost"]["credits"], "API credits", "$" + request["cost"]["usd"])
```

### MCP

The MCP server at `https://api.doitong.com/v1/mcp` exposes the tools `search_models`, `get_model`, `quote`, `run`, `get_request`, `cancel_request`, `list_requests`, `create_upload` and `get_account`. A `run` call for this model:

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "method": "tools/call",
  "params": {
    "name": "run",
    "arguments": {
      "model_id": "flux-general/differential-diffusion",
      "input": {
        "prompt": "A red fox trots through fresh snow at sunrise, soft golden light, shallow depth of field",
        "image_url": "https://content.doitong.com/images/showcase/v3/gen_fox_cartoon.jpg",
        "change_map_image_url": "https://content.doitong.com/images/showcase/v3/gen_fox_cartoon.jpg"
      },
      "wait_seconds": 20
    }
  }
}
```

## Response

Every call returns a request object. `status` is one of `queued`, `running`, `succeeded`, `failed`, `canceled`. `outputs` lists the generated files with URLs on our storage (kept forever, or 7 days with `?storage=temporary`; `storage` says which); `output` is the model's own result object with the same URLs.

```json
{
  "id": "req_8k2m4q7x1z9c3v5b6n0p2r4t",
  "object": "request",
  "model": "flux-general/differential-diffusion",
  "status": "succeeded",
  "created_at": "2026-10-20T12:00:00Z",
  "started_at": "2026-10-20T12:00:02Z",
  "completed_at": "2026-10-20T12:00:09Z",
  "queue_position": null,
  "cost": {
    "credits": 138,
    "usd": "0.138",
    "charged": 138,
    "refunded": 0
  },
  "input": {
    "prompt": "A red fox trots through fresh snow at sunrise, soft golden light, shallow depth of field",
    "image_url": "https://content.doitong.com/images/showcase/v3/gen_fox_cartoon.jpg",
    "change_map_image_url": "https://content.doitong.com/images/showcase/v3/gen_fox_cartoon.jpg"
  },
  "output": {
    "images": [
      {
        "url": "https://content.doitong.com/dev-api/2026/10/20/req_8k2m4q7x1z9c3v5b6n0p2r4t/0-output.jpeg",
        "width": 1024,
        "height": 768,
        "content_type": "image/jpeg"
      }
    ],
    "timings": {},
    "seed": 42,
    "has_nsfw_concepts": [
      false
    ],
    "prompt": "string"
  },
  "outputs": [
    {
      "type": "image",
      "url": "https://content.doitong.com/dev-api/2026/10/20/req_8k2m4q7x1z9c3v5b6n0p2r4t/0-output.jpeg",
      "content_type": "image/jpeg",
      "file_size": 1843200,
      "width": 1024,
      "height": 768,
      "stored": true
    }
  ],
  "error": null,
  "metrics": {
    "inference_seconds": 6.8
  },
  "urls": {
    "self": "https://api.doitong.com/v1/requests/req_8k2m4q7x1z9c3v5b6n0p2r4t",
    "cancel": "https://api.doitong.com/v1/requests/req_8k2m4q7x1z9c3v5b6n0p2r4t/cancel"
  }
}
```

### Output fields (`output`)

| Field | Type | Description |
|---|---|---|
| `images` | array of object {url, width, height, content_type} | File information for the generated images. |
| `timings` | object |  |
| `seed` | integer | Image-generation seed, including the randomly chosen value if the input omitted a seed; otherwise, it repeats the supplied value. |
| `has_nsfw_concepts` | array of boolean | Indicates whether NSFW concepts appear in the generated images. |
| `prompt` | string | Prompt used during image generation. |

## Related models

- [FLUX.1 \[dev\] with Controlnets and Loras](https://doitong.com/developers/models/flux-general.md) (`flux-general`): $0.30 / image
- [FLUX.1 \[dev\] with Controlnets and Loras · Image to Image](https://doitong.com/developers/models/flux-general/image-to-image.md) (`flux-general/image-to-image`): $0.15 / image
- [FLUX.1 \[dev\] with Controlnets and Loras · Inpainting](https://doitong.com/developers/models/flux-general/inpainting.md) (`flux-general/inpainting`): $0.192 / image
- [FLUX.1 \[dev\] with Controlnets and Loras · Rf Inversion](https://doitong.com/developers/models/flux-general/rf-inversion.md) (`flux-general/rf-inversion`): $0.025 / image
- [FLUX.1 Kontext \[pro\]](https://doitong.com/developers/models/flux-pro/kontext.md) (`flux-pro/kontext`): $0.04 / image
- [GPT Image 2.5 Edit](https://doitong.com/developers/models/openai/gpt-image-2.5/flare/edit.md) (`openai/gpt-image-2.5/flare/edit`): from $0.12 / image
- [Nano Banana 2 Edit](https://doitong.com/developers/models/nano-banana-2/edit.md) (`nano-banana-2/edit`): from $0.06 / image
- [Nano Banana Pro Edit](https://doitong.com/developers/models/nano-banana-pro/edit.md) (`nano-banana-pro/edit`): from $0.15 / image

## Links

- HTML page: https://doitong.com/developers/models/flux-general/differential-diffusion
- All models and guides for AI agents: https://doitong.com/developers/llms.txt
- OpenAPI 3.1 with this model's typed request body: https://doitong.com/developers/openapi.json?model=flux-general/differential-diffusion
- Errors: https://doitong.com/developers/docs/errors
- Model details as JSON: https://api.doitong.com/v1/models/flux-general/differential-diffusion
