curl --request POST \
--url https://api.infery.ai/v1/images/edits \
--header 'Authorization: <api-key>' \
--header 'Content-Type: application/json' \
--data '
{
"model": "<string>",
"prompt": "<string>",
"image_base64": "<string>",
"image_mime_type": "image/png",
"mask_base64": "<string>",
"mask_mime_type": "image/png",
"n": 1,
"size": "1024x1024",
"quality": "high",
"aspect_ratio": "16:9",
"strength": 0.35,
"image_size": "2K",
"style": "natural",
"background": "transparent",
"response_format": "url",
"steps": 4,
"prompt_extend": false
}
'import requests
url = "https://api.infery.ai/v1/images/edits"
payload = {
"model": "<string>",
"prompt": "<string>",
"image_base64": "<string>",
"image_mime_type": "image/png",
"mask_base64": "<string>",
"mask_mime_type": "image/png",
"n": 1,
"size": "1024x1024",
"quality": "high",
"aspect_ratio": "16:9",
"strength": 0.35,
"image_size": "2K",
"style": "natural",
"background": "transparent",
"response_format": "url",
"steps": 4,
"prompt_extend": False
}
headers = {
"Authorization": "<api-key>",
"Content-Type": "application/json"
}
response = requests.post(url, json=payload, headers=headers)
print(response.text)const options = {
method: 'POST',
headers: {Authorization: '<api-key>', 'Content-Type': 'application/json'},
body: JSON.stringify({
model: '<string>',
prompt: '<string>',
image_base64: '<string>',
image_mime_type: 'image/png',
mask_base64: '<string>',
mask_mime_type: 'image/png',
n: 1,
size: '1024x1024',
quality: 'high',
aspect_ratio: '16:9',
strength: 0.35,
image_size: '2K',
style: 'natural',
background: 'transparent',
response_format: 'url',
steps: 4,
prompt_extend: false
})
};
fetch('https://api.infery.ai/v1/images/edits', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));<?php
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_URL => "https://api.infery.ai/v1/images/edits",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "POST",
CURLOPT_POSTFIELDS => json_encode([
'model' => '<string>',
'prompt' => '<string>',
'image_base64' => '<string>',
'image_mime_type' => 'image/png',
'mask_base64' => '<string>',
'mask_mime_type' => 'image/png',
'n' => 1,
'size' => '1024x1024',
'quality' => 'high',
'aspect_ratio' => '16:9',
'strength' => 0.35,
'image_size' => '2K',
'style' => 'natural',
'background' => 'transparent',
'response_format' => 'url',
'steps' => 4,
'prompt_extend' => false
]),
CURLOPT_HTTPHEADER => [
"Authorization: <api-key>",
"Content-Type: application/json"
],
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}package main
import (
"fmt"
"strings"
"net/http"
"io"
)
func main() {
url := "https://api.infery.ai/v1/images/edits"
payload := strings.NewReader("{\n \"model\": \"<string>\",\n \"prompt\": \"<string>\",\n \"image_base64\": \"<string>\",\n \"image_mime_type\": \"image/png\",\n \"mask_base64\": \"<string>\",\n \"mask_mime_type\": \"image/png\",\n \"n\": 1,\n \"size\": \"1024x1024\",\n \"quality\": \"high\",\n \"aspect_ratio\": \"16:9\",\n \"strength\": 0.35,\n \"image_size\": \"2K\",\n \"style\": \"natural\",\n \"background\": \"transparent\",\n \"response_format\": \"url\",\n \"steps\": 4,\n \"prompt_extend\": false\n}")
req, _ := http.NewRequest("POST", url, payload)
req.Header.Add("Authorization", "<api-key>")
req.Header.Add("Content-Type", "application/json")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}HttpResponse<String> response = Unirest.post("https://api.infery.ai/v1/images/edits")
.header("Authorization", "<api-key>")
.header("Content-Type", "application/json")
.body("{\n \"model\": \"<string>\",\n \"prompt\": \"<string>\",\n \"image_base64\": \"<string>\",\n \"image_mime_type\": \"image/png\",\n \"mask_base64\": \"<string>\",\n \"mask_mime_type\": \"image/png\",\n \"n\": 1,\n \"size\": \"1024x1024\",\n \"quality\": \"high\",\n \"aspect_ratio\": \"16:9\",\n \"strength\": 0.35,\n \"image_size\": \"2K\",\n \"style\": \"natural\",\n \"background\": \"transparent\",\n \"response_format\": \"url\",\n \"steps\": 4,\n \"prompt_extend\": false\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.infery.ai/v1/images/edits")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Post.new(url)
request["Authorization"] = '<api-key>'
request["Content-Type"] = 'application/json'
request.body = "{\n \"model\": \"<string>\",\n \"prompt\": \"<string>\",\n \"image_base64\": \"<string>\",\n \"image_mime_type\": \"image/png\",\n \"mask_base64\": \"<string>\",\n \"mask_mime_type\": \"image/png\",\n \"n\": 1,\n \"size\": \"1024x1024\",\n \"quality\": \"high\",\n \"aspect_ratio\": \"16:9\",\n \"strength\": 0.35,\n \"image_size\": \"2K\",\n \"style\": \"natural\",\n \"background\": \"transparent\",\n \"response_format\": \"url\",\n \"steps\": 4,\n \"prompt_extend\": false\n}"
response = http.request(request)
puts response.read_body{
"created": 1713204900,
"data": [
{
"url": "https://example.com/image.png",
"b64_json": "<string>",
"revised_prompt": "<string>",
"file_id": "file_1hR9xTPZqK4mVLc2nJ7fY5wB"
}
],
"credits_used": 40
}{
"error": {
"message": "Model not found",
"type": "invalid_request_error",
"code": "model_not_found",
"param": "model",
"job_id": "job_1hR9xTPZqK4mVLc2nJ7fY5wB"
}
}{
"error": {
"message": "Model not found",
"type": "invalid_request_error",
"code": "model_not_found",
"param": "model",
"job_id": "job_1hR9xTPZqK4mVLc2nJ7fY5wB"
}
}{
"error": {
"message": "Model not found",
"type": "invalid_request_error",
"code": "model_not_found",
"param": "model",
"job_id": "job_1hR9xTPZqK4mVLc2nJ7fY5wB"
}
}Edit an image
POST /v1/images/edits — modify an existing image with a prompt.
curl --request POST \
--url https://api.infery.ai/v1/images/edits \
--header 'Authorization: <api-key>' \
--header 'Content-Type: application/json' \
--data '
{
"model": "<string>",
"prompt": "<string>",
"image_base64": "<string>",
"image_mime_type": "image/png",
"mask_base64": "<string>",
"mask_mime_type": "image/png",
"n": 1,
"size": "1024x1024",
"quality": "high",
"aspect_ratio": "16:9",
"strength": 0.35,
"image_size": "2K",
"style": "natural",
"background": "transparent",
"response_format": "url",
"steps": 4,
"prompt_extend": false
}
'import requests
url = "https://api.infery.ai/v1/images/edits"
payload = {
"model": "<string>",
"prompt": "<string>",
"image_base64": "<string>",
"image_mime_type": "image/png",
"mask_base64": "<string>",
"mask_mime_type": "image/png",
"n": 1,
"size": "1024x1024",
"quality": "high",
"aspect_ratio": "16:9",
"strength": 0.35,
"image_size": "2K",
"style": "natural",
"background": "transparent",
"response_format": "url",
"steps": 4,
"prompt_extend": False
}
headers = {
"Authorization": "<api-key>",
"Content-Type": "application/json"
}
response = requests.post(url, json=payload, headers=headers)
print(response.text)const options = {
method: 'POST',
headers: {Authorization: '<api-key>', 'Content-Type': 'application/json'},
body: JSON.stringify({
model: '<string>',
prompt: '<string>',
image_base64: '<string>',
image_mime_type: 'image/png',
mask_base64: '<string>',
mask_mime_type: 'image/png',
n: 1,
size: '1024x1024',
quality: 'high',
aspect_ratio: '16:9',
strength: 0.35,
image_size: '2K',
style: 'natural',
background: 'transparent',
response_format: 'url',
steps: 4,
prompt_extend: false
})
};
fetch('https://api.infery.ai/v1/images/edits', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));<?php
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_URL => "https://api.infery.ai/v1/images/edits",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "POST",
CURLOPT_POSTFIELDS => json_encode([
'model' => '<string>',
'prompt' => '<string>',
'image_base64' => '<string>',
'image_mime_type' => 'image/png',
'mask_base64' => '<string>',
'mask_mime_type' => 'image/png',
'n' => 1,
'size' => '1024x1024',
'quality' => 'high',
'aspect_ratio' => '16:9',
'strength' => 0.35,
'image_size' => '2K',
'style' => 'natural',
'background' => 'transparent',
'response_format' => 'url',
'steps' => 4,
'prompt_extend' => false
]),
CURLOPT_HTTPHEADER => [
"Authorization: <api-key>",
"Content-Type: application/json"
],
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}package main
import (
"fmt"
"strings"
"net/http"
"io"
)
func main() {
url := "https://api.infery.ai/v1/images/edits"
payload := strings.NewReader("{\n \"model\": \"<string>\",\n \"prompt\": \"<string>\",\n \"image_base64\": \"<string>\",\n \"image_mime_type\": \"image/png\",\n \"mask_base64\": \"<string>\",\n \"mask_mime_type\": \"image/png\",\n \"n\": 1,\n \"size\": \"1024x1024\",\n \"quality\": \"high\",\n \"aspect_ratio\": \"16:9\",\n \"strength\": 0.35,\n \"image_size\": \"2K\",\n \"style\": \"natural\",\n \"background\": \"transparent\",\n \"response_format\": \"url\",\n \"steps\": 4,\n \"prompt_extend\": false\n}")
req, _ := http.NewRequest("POST", url, payload)
req.Header.Add("Authorization", "<api-key>")
req.Header.Add("Content-Type", "application/json")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}HttpResponse<String> response = Unirest.post("https://api.infery.ai/v1/images/edits")
.header("Authorization", "<api-key>")
.header("Content-Type", "application/json")
.body("{\n \"model\": \"<string>\",\n \"prompt\": \"<string>\",\n \"image_base64\": \"<string>\",\n \"image_mime_type\": \"image/png\",\n \"mask_base64\": \"<string>\",\n \"mask_mime_type\": \"image/png\",\n \"n\": 1,\n \"size\": \"1024x1024\",\n \"quality\": \"high\",\n \"aspect_ratio\": \"16:9\",\n \"strength\": 0.35,\n \"image_size\": \"2K\",\n \"style\": \"natural\",\n \"background\": \"transparent\",\n \"response_format\": \"url\",\n \"steps\": 4,\n \"prompt_extend\": false\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.infery.ai/v1/images/edits")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Post.new(url)
request["Authorization"] = '<api-key>'
request["Content-Type"] = 'application/json'
request.body = "{\n \"model\": \"<string>\",\n \"prompt\": \"<string>\",\n \"image_base64\": \"<string>\",\n \"image_mime_type\": \"image/png\",\n \"mask_base64\": \"<string>\",\n \"mask_mime_type\": \"image/png\",\n \"n\": 1,\n \"size\": \"1024x1024\",\n \"quality\": \"high\",\n \"aspect_ratio\": \"16:9\",\n \"strength\": 0.35,\n \"image_size\": \"2K\",\n \"style\": \"natural\",\n \"background\": \"transparent\",\n \"response_format\": \"url\",\n \"steps\": 4,\n \"prompt_extend\": false\n}"
response = http.request(request)
puts response.read_body{
"created": 1713204900,
"data": [
{
"url": "https://example.com/image.png",
"b64_json": "<string>",
"revised_prompt": "<string>",
"file_id": "file_1hR9xTPZqK4mVLc2nJ7fY5wB"
}
],
"credits_used": 40
}{
"error": {
"message": "Model not found",
"type": "invalid_request_error",
"code": "model_not_found",
"param": "model",
"job_id": "job_1hR9xTPZqK4mVLc2nJ7fY5wB"
}
}{
"error": {
"message": "Model not found",
"type": "invalid_request_error",
"code": "model_not_found",
"param": "model",
"job_id": "job_1hR9xTPZqK4mVLc2nJ7fY5wB"
}
}{
"error": {
"message": "Model not found",
"type": "invalid_request_error",
"code": "model_not_found",
"param": "model",
"job_id": "job_1hR9xTPZqK4mVLc2nJ7fY5wB"
}
}multipart/form-data. The OpenAI SDK’s client.images.edit(...) sends multipart and will not work against it — call it over plain HTTP as below.curl https://api.infery.ai/v1/images/edits \
-H "Authorization: Bearer $INFERY_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"model": "nano-banana",
"prompt": "Replace the background with a tropical beach",
"image_base64": "<base64 of source image>",
"image_mime_type": "image/png"
}'
image_mime_type defaults to image/png. An optional mask_base64 (transparent = the region to repaint) enables in-painting where the model supports a mask.
Sample output

Source image — autumn Japanese garden

Edited: 'Transform this into a snowy winter wonderland — keep the layout intact.' (nano-banana)
Supported models
Image-edit capability is model-dependent, and it is decided per source rather than per model: a request routed to a source that takes no input image is refused with400 edit_not_supported before anything is billed. See Models catalog for which models edit.Authorizations
API key in format: Bearer inf_***
Body
Edit instruction
Base64-encoded source image
Base64-encoded mask (transparent area = edit region)
Must be one of the sizes the chosen model declares (GET /v1/models). Refused with 400 otherwise.
"1024x1024"
Output quality. Checked against the chosen model's own input schema — refused with 400 when that schema is the provider's own and the value is not in it, snapped for a synthesized schema, and dropped for a model that declares no quality at all. OpenAI's standard/hd and GPT Image's low/medium/high/auto are two such sets among many; read the one that applies from GET /v1/models.
What it does on THIS endpoint is select a price, not a rendering: the credit hold and the settle look the image price up by quality, and no edit path forwards the value to a provider (OpenAI's edit is a multipart form that omits it; the FAL and Replicate input mappers exclude it). On POST /v1/images/generations it reaches the provider and changes the image. Declared here because the endpoint accepts, validates and bills on it.
"high"
Aspect ratio of the edited image. Honoured by every edit-capable provider that has a field for it — Google Imagen (aspectRatio), Replicate and FAL — and dropped for a model that has none. For a model with a stored input schema the value is checked against that schema's own enum and refused with 400 if it is not a member, so read the allowed set from GET /v1/models rather than assuming a fixed list.
"16:9"
How much the source image steers the result — lower keeps more of the original, higher follows the prompt more freely. Clamped to the range the chosen model's own input schema declares (0–1 on every model that exposes it today) and dropped entirely for a model that does not, so it is silently inert rather than an error on the models that ignore it.
REQUIRED by some models and absent from most: luma-photon-modify and luma-photon-flash-modify will not run an edit without it. It is not marked required here because this one operation is shared by every edit-capable model, the large majority of which neither need nor accept it — check the chosen model's schema in GET /v1/models.
0.35
Output resolution for the models that size their output by label rather than by pixels (Imagen Standard/Ultra 1K|2K, Gemini 3 image 1K|2K|4K) — the same field POST /v1/images/generations takes. Checked against the chosen model's own input schema and dropped for a model that does not declare it.
Unlike quality above it is carried through on the edit paths that have a field for it (Gemini as imageSize, xAI as resolution). It is also a BILLING dimension: with no size sent, this is what the image price is looked up by.
"2K"
Style hint. Checked against the chosen model's own input schema — refused with 400 when that schema is the provider's own and the value is not in it, and dropped for a model that declares no style. Read the allowed set from GET /v1/models rather than assuming DALL-E's vivid/natural.
INERT on this endpoint, like quality: no edit path forwards it to a provider. Declared because the endpoint accepts and validates it — sending an unacceptable value is a 400 you would otherwise meet without warning.
"natural"
Background treatment — GPT Image's transparent/opaque/auto is one model family's set, not this endpoint's. Checked against the chosen model's own input schema and dropped for a model that declares no background. INERT here for the same reason as style above: no edit path forwards it. On POST /v1/images/generations it does reach GPT Image and change the result.
"transparent"
Person-generation policy. Accepted and validated here — any other value is refused with 400 — but unlike POST /v1/images/generations, no edit-capable provider currently forwards it upstream, so on this endpoint it constrains what you may send without changing what you get back.
dont_allow, allow_adult, allow_all url, b64_json Diffusion steps. Validated and priced here exactly as on POST /v1/images/generations — a whole number in 1–100 or a 400, and on a per-megapixel model the price is multiplied by max(1, steps ÷ the model's default steps).
INERT as a rendering control on this endpoint, like quality and style above: no edit path forwards it to a provider. Declared because sending an out-of-range value is a 400, and sending an in-range one can raise what the edit costs.
1 <= x <= 1004
Prompt rewriting. Reaches no provider from this endpoint — the edit request object has no such field — but it is read by the shared price-parameter builder, which uses it to pick z-image-turbo's extend (absent or true) or noextend (false) rate. So on this route it selects a price and nothing else.
false
Response
Image edit result
Unix timestamp, in seconds, of when the result was produced.
1713204900
One entry per produced image, in the order the provider returned them.
Show child attributes
Show child attributes
Credits actually settled for this request (1 credit = $0.01). May be fractional.
40