Image Generation
Generate and edit images with the OpenAI Images API format. Generation is synchronous: one request returns base64 images directly in the JSON response, no polling. Both endpoints use the same API key as the chat endpoints.
Base URL: https://api.techopenclaw.com — authentication uses the same Authorization: Bearer toc-..... header as the chat endpoints (details in API Reference).
Text-to-image — one synchronous request returns the images inline.
| Field | Type | Required | Description |
|---|---|---|---|
model | string | Yes | Image model name from the LLM Catalog — gpt-image-2 or gpt-image-2.5-flare. |
prompt | string | Yes | What to draw. |
n | integer | No | Number of images requested, clamped to 1–10 (default 1). The value is not forwarded to the model — the response contains the images the model produced (see the note below the cards). |
size | string | No | WxH (e.g. 1024x1024). OpenAI-image models receive it as-is; Gemini-image models approximate it to the nearest supported ratio (1:1, 16:9, 9:16, 4:3, 3:4) and ignore unparseable values. An unsupported size on an OpenAI-image model surfaces as a generic 529, not a size-specific error. |
quality | string | No | Forwarded on OpenAI-image models; ignored (no effect) on Gemini-image models. |
image / images | string / array | No | Ignored on this endpoint — input images take effect only on /v1/images/edits. |
output_format | string | No | png (the default), jpeg, or webp — any other value falls back to png. |
response_format | string | No | b64_json (the default) or url. url returns a data: URI built from the returned image — images are not hosted as files, so store the data yourself. |
curl https://api.techopenclaw.com/v1/images/generations \
-H "Authorization: Bearer toc-....." \
-H "Content-Type: application/json" \
-d '{
"model": "gpt-image-2",
"prompt": "A vivid neon-lit alley in Tokyo after rain, reflections on wet asphalt",
"size": "1024x1024"
}'{
"created": 1712345678,
"data": [
{
"b64_json": "<base64…>",
"revised_prompt": null
}
]
}Works with the OpenAI SDK by pointing base_url at Techopenclaw:
import base64
from openai import OpenAI
client = OpenAI(api_key="toc-.....", base_url="https://api.techopenclaw.com/v1")
result = client.images.generate(
model="gpt-image-2",
prompt="A vivid neon-lit alley in Tokyo after rain, reflections on wet asphalt",
size="1024x1024",
)
with open("image.png", "wb") as f:
f.write(base64.b64decode(result.data[0].b64_json))Edit or reference-based generation — same behavior as generations, but an input image is required.
Send raw JSON. The body is JSON with image as a data-URI (or bare base64) — the OpenAI SDK's default multipart upload is not supported here, so build the JSON yourself like the curl example below. The whole body is capped at 32 MiB.
| Field | Type | Required | Description |
|---|---|---|---|
model | string | Yes | Image model name from the LLM Catalog — gpt-image-2 or gpt-image-2.5-flare. |
prompt | string | Yes | What to change — the edit instruction. |
n | integer | No | Number of images requested, clamped to 1–10 (default 1). The value is not forwarded to the model — the response contains the images the model produced (see the note below the cards). |
size | string | No | WxH (e.g. 1024x1024). OpenAI-image models receive it as-is; Gemini-image models approximate it to the nearest supported ratio (1:1, 16:9, 9:16, 4:3, 3:4) and ignore unparseable values. An unsupported size on an OpenAI-image model surfaces as a generic 529, not a size-specific error. |
quality | string | No | Forwarded on OpenAI-image models; ignored (no effect) on Gemini-image models. |
image / images | string / array | Yes | Required. The image(s) to edit, as data-URIs or bare base64 (bare base64 is wrapped as PNG). image accepts a string or an array; images accepts an array only — a string under images is ignored. Missing or empty returns 400 with edits require an `image` data-URI. |
output_format | string | No | png (the default), jpeg, or webp — any other value falls back to png. |
response_format | string | No | b64_json (the default) or url. url returns a data: URI built from the returned image — images are not hosted as files, so store the data yourself. |
curl https://api.techopenclaw.com/v1/images/edits \
-H "Authorization: Bearer toc-....." \
-H "Content-Type: application/json" \
-d '{
"model": "gpt-image-2",
"prompt": "Put a pair of sunglasses on the cat, keep everything else unchanged",
"image": "data:image/png;base64,iVBORw0KGgo…",
"size": "1024x1024"
}'The number of images returned follows what the model produced (requested n caps at 10) — and a successful response always contains at least one image: a model that returns nothing is reported as an error, not as an empty list.
Billing
Images are priced per request: each request costs the model's flat credits-per-request rate — tokens are not counted, and the rate is the same whether the model returns one image or several. Both endpoints (/v1/images/generations and /v1/images/edits) are billed the same way. Rates per model are shown in the Pricing Policy. You are charged only when the request succeeds.
| Outcome | Billing |
|---|---|
200 | Charged in full: the model's flat credits-per-request rate — one charge per request, however many images come back |
| Any error status | Not charged — a zero-cost row with status error appears in the activity list |
Error Codes
| Code | Meaning | Action |
|---|---|---|
400 | Malformed request — missing model or prompt, an edit without an image, or a body over 32 MiB (easy to hit with large base64 payloads) | Read error.message — an edit without an image returns 'edits require an `image` data-URI' |
401 | Invalid or missing API key | Check your toc- key |
402 | Key out of credits (daily quota and top-up exhausted, or key expired), or the model has no per-request price configured | Top up, or verify the model in the LLM Catalog |
404 | Unknown model alias | Verify the model name against the LLM Catalog |
413 | The image payload is too large for the upstream provider | Shrink or downscale the input image |
529 | Provider busy, rate-limited, failed, or the request timed out — provider errors never surface as 429/5xx here | Retry after a pause — respect Retry-After when present. Failed requests are not charged |