Media API
Generate images
Create one or more images with a public Edy model slug. Image requests are synchronous and return the finished image data in the same response.
1. Find an image model
List active image models and their current catalogue price.
curl "https://edycode.vercel.app/api/v1/media/models?type=image"const response = await fetch("https://edycode.vercel.app/api/v1/media/models?type=image");
if (!response.ok) throw new Error(await response.text());
const { data: imageModels } = await response.json();import requests
response = requests.get("https://edycode.vercel.app/api/v1/media/models?type=image", timeout=30)
response.raise_for_status()
image_models = response.json()["data"]If you omit modelduring generation, Edy uses the Admin-selected default image model to use that provider's configured default.
2. Generate an image
curl -X POST https://edycode.vercel.app/api/v1/images/generations \
-H "Authorization: Bearer $EDY_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"model": "gpt-image-2-5",
"prompt": "A cinematic sunrise over Lake Malawi, warm mist, detailed",
"n": 1,
"aspect_ratio": "16:9",
"resolution": "2K",
"output_format": "png"
}'const response = await fetch("https://edycode.vercel.app/api/v1/images/generations", {
method: "POST",
headers: {
Authorization: "Bearer " + process.env.EDY_API_KEY,
"Content-Type": "application/json",
},
body: JSON.stringify({
model: "gpt-image-2-5",
prompt: "A cinematic sunrise over Lake Malawi, warm mist, detailed",
n: 1,
aspect_ratio: "16:9",
resolution: "2K",
output_format: "png",
}),
});
if (!response.ok) throw new Error(await response.text());
const generation = await response.json();
console.log(generation.data[0].url ?? generation.data[0].b64_json);import os
import requests
response = requests.post(
"https://edycode.vercel.app/api/v1/images/generations",
headers={
"Authorization": f"Bearer {os.environ['EDY_API_KEY']}",
"Content-Type": "application/json",
},
json={
"model": "gpt-image-2-5",
"prompt": "A cinematic sunrise over Lake Malawi, warm mist, detailed",
"n": 1,
"aspect_ratio": "16:9",
"resolution": "2K",
"output_format": "png",
},
timeout=300,
)
response.raise_for_status()
generation = response.json()
print(generation["data"][0].get("url") or generation["data"][0].get("b64_json"))model — Optional public image model slug. The configured default is used when omitted.
prompt — Required description of the image, up to 32 KB.
n — Optional number of outputs from 1–10. The selected model must support the requested count.
aspect_ratio — Optional ratio such as 1:1, 16:9, or 9:16.
resolution — Optional provider-supported tier such as 1K or 2K.
size — Optional explicit WIDTHxHEIGHT size or provider-supported size tier.
quality — Optional quality tier supported by the selected model.
output_format — Optional png, jpeg, webp, or another format supported by the model.
background — Optional auto, transparent, or opaque. Transparent output requires png or webp support.
output_compression — Optional integer from 0–100 for jpeg or webp output.
response_format — Optional url or b64_json. Availability depends on the provider.
seed — Optional non-negative integer for repeatable output where supported.
input_references — Optional array of image URLs or data URIs for editing and style guidance.
3. Edit or guide with images
Reference-capable models can edit, combine, restyle, or use existing pictures as visual guidance. JSON clients can send public URLs or base64 data URIs using the OpenRouter-compatible shape.
{
"model": "grok-imagine-image-2",
"prompt": "Put the jacket from <IMAGE_1> onto the person in <IMAGE_0>",
"input_references": [
{ "type": "image_url", "image_url": { "url": "https://example.com/person.png" } },
{ "type": "image_url", "image_url": { "url": "https://example.com/jacket.png" } }
],
"quality": "medium",
"resolution": "2K"
}To upload files directly, send multipart/form-data and repeat the input_references field. Edy validates the files and converts them to private inline data before contacting the provider; developers do not need to host them publicly.
curl -X POST https://edycode.vercel.app/api/v1/images/generations \
-H "Authorization: Bearer $EDY_API_KEY" \
-F "model=grok-imagine-image-2" \
-F "prompt=Restyle this portrait as a watercolor painting" \
-F "quality=medium" \
-F "input_references=@./portrait.png"import { readFile } from "node:fs/promises";
const form = new FormData();
form.set("model", "grok-imagine-image-2");
form.set("prompt", "Restyle this portrait as a watercolor painting");
form.set("quality", "medium");
form.append("input_references", new Blob([await readFile("./portrait.png")], { type: "image/png" }), "portrait.png");
const response = await fetch("https://edycode.vercel.app/api/v1/images/generations", {
method: "POST",
headers: { Authorization: "Bearer " + process.env.EDY_API_KEY },
body: form,
});
if (!response.ok) throw new Error(await response.text());
const generation = await response.json();import os
import requests
with open("./portrait.png", "rb") as image_file:
response = requests.post(
"https://edycode.vercel.app/api/v1/images/generations",
headers={"Authorization": f"Bearer {os.environ['EDY_API_KEY']}"},
data={
"model": "grok-imagine-image-2",
"prompt": "Restyle this portrait as a watercolor painting",
"quality": "medium",
},
files={"input_references": ("portrait.png", image_file, "image/png")},
timeout=300,
)
response.raise_for_status()
generation = response.json()Each uploaded image can be up to 10 MB, with a 30 MB combined limit. Edy accepts up to four references; Grokified editing accepts up to three. The selected model must advertise image input support.
Response
{
"id": "4b82e2a0-...",
"object": "image.generation",
"created": 1788984000,
"model": "gpt-image-2-5",
"data": [{ "b64_json": "<base64 image bytes>" }],
"usage": {
"images": 1,
"input_tokens": 320,
"output_tokens": 4096,
"credits": 4.72,
"billing_mode": "token",
"fallback_billing_used": false
}
}Billing and errors
Image models use either a fixed price per returned image or actual input and output token usage. The model catalogue reports the billing mode and current retail MWK prices.
{
"pricing": {
"mode": "token",
"currency": "MWK",
"inputPer1MTokens": 350,
"outputPer1MTokens": 2500,
"maximumPerImage": "1000.000000"
}
}For token-billed models, Edy reserves the published maximum for every requested image, charges actual reported usage, and refunds the difference. The final charge never exceeds that maximum. If the provider omits valid token usage, Edy uses the maximum fallback price and returns fallback_billing_used: true for reconciliation. Fixed-price models continue to charge once per returned image. A request returns HTTP 402 before provider work begins when the wallet cannot cover the reservation.
Fixed-price edits add the catalogue's reference-image price for every supplied source image. The reservation is (output price × n) + (reference price × references). If an administrator has not configured a reference price, Edy rejects the edit before contacting the provider rather than allowing an unpriced provider charge.
Quality, resolution, size, input count, and other supported options can change upstream cost. Check the selected model's capabilities and published Edy catalogue price before sending a request. Unsupported model-specific combinations return a structured 400 response.
Every error contains an x-request-id header and a structured error.code. See the error reference.