Use one API key and the familiar OpenAI SDK to make images from a description, or to edit one you have. You choose the size; you pay per image and resolution.
Key points
- Find image models with GET /v1/models: they list images.generations in endpoints.
- Images come back as base64 (b64_json) or a link (url); save them at once, the API does not keep them.
- Price = price per image × resolution weight (1K ×1, 2K ×2, 4K ×4 on tiered models) × images.
- Edits are multipart/form-data to /v1/images/edits, with an image field.
- A failed request is never charged.
Make your first image#
Send a model and a prompt to POST /v1/images/generations. The API is compatible with OpenAI Images, so the openai SDK works as is: change only the base_url and the API key.
Images come back in data, as base64 (b64_json) or a link (url) depending on the model. The code below makes one image and saves it as fox.png.
curl https://api.xpncore.com/v1/images/generations \
-H "Authorization: Bearer $XPNCORE_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"model": "IMAGE_MODEL_ID",
"prompt": "A watercolor fox reading a book under a maple tree, soft morning light",
"n": 1,
"size": "1024x1024"
}' | jq -r '.data[0].b64_json' | base64 --decode > fox.png{
"created": 1759550400,
"data": [
{
"b64_json": "iVBORw0KGgoAAAANSUhEUgAABAAAAAQACAIAAADwf7zU..."
}
],
"usage": {
"input_tokens": 24,
"output_tokens": 1290,
"total_tokens": 1314
}
}usage is present only when the model reports tokens. The x-routing-request-id response header is your request ID; include it when you contact support.
Choose an image model#
Call GET /v1/models with your API key. Image models list images.generations in their endpoints array; models that can edit also list images.edits.
- Put the model's
idin themodelfield. - Each model's price per image is on the Models & pricing page.
- A model that does not make images is refused with a 422.
Request parameters#
The body is JSON. Other fields (for example style, background, output_format) are passed to the model unchanged; a model ignores or refuses a field it does not know.
modelstringRequiredA model ID from
GET /v1/models.promptstringRequiredWhat to draw. Be specific: subject, setting, style, light, camera angle.
nintegerOptionalHow many images, 1 to 10 (default 1). Each model has its own limit, usually 4; more is refused with a 400.
sizestringOptionalWIDTHxHEIGHT, for example1024x1024,1536x1024,1024x1536, orauto. The longest side sets the price tier (below). A model that cannot make that size returns its own error.qualitystringOptionalA quality level when the model has them, for example
low,medium,high.response_formatstringOptionalb64_jsonorurl, when the model supports both. Some models always returnb64_json.streambooleanOptionalNot supported:
trueis refused with a 422.
Sizes, resolution and pricing#
You pay per image: price per image × resolution weight × images returned.
- On a model with resolution tiers, the longest side of
sizepicks the tier: up to 1024 px is 1K (×1), up to 2048 px is 2K (×2), larger is 4K (×4). auto, or nosize, uses the model's default size.- A model without tiers charges one price for every size.
- Only images actually returned are charged. A failed request costs nothing.
Example: a model at ₫100 per image,size2048x2048andn2 → 2 images × ₫100 × 2 = ₫400.
Edit an existing image#
Send the source image and your instruction to POST /v1/images/edits as multipart/form-data (JSON is not accepted). Only models that list images.edits in endpoints can edit.
imagefileRequiredThe source image (PNG, JPEG or WebP). The field must be named exactly
image. The whole request is limited to 25 MB.promptstringRequiredWhat to change, for example "turn the background into a beach at sunset".
modelstringRequiredThe ID of a model with
images.edits.maskfileOptionalA PNG whose transparent area marks what to change, when the model supports it.
nintegerOptionalHow many images, 1 to 10 (default 1).
sizestringOptionalThe result's size; it sets the price tier as for new images.
curl https://api.xpncore.com/v1/images/edits \
-H "Authorization: Bearer $XPNCORE_API_KEY" \
-F model=IMAGE_MODEL_ID \
-F [email protected] \
-F prompt="Give the fox a red scarf and make it snow" \
-F size=1024x1024 | jq -r '.data[0].b64_json' | base64 --decode > fox-winter.pngCommon errors#
Errors come as {"error": {"code", "message", "type"}}, which the OpenAI SDKs read. A failed request is never charged.
- 400
BAD_REQUEST:nout of range, or an edit that is not multipart. - 400
CONTENT_POLICY_BLOCKED: the prompt breaks the content policy; rewrite it. - 402
INSUFFICIENT_FUNDS: the wallet balance is too low.KEY_SPEND_LIMIT: the key reached the spend limit you set. - 403
FORBIDDEN: the key may not use this model, or image generation is turned off. - 422
VALIDATION_ERROR:modelorpromptmissing, the model does not make images, orstream: true. - 429
RATE_LIMITED: too many requests; wait and retry. - 503
MODEL_PRICING_UNAVAILABLE: the model has no price yet and cannot be used.SERVICE_UNAVAILABLE: the model is unavailable; retry in a few minutes.
Best practices#
- Save images at once. The API does not keep them for you; a
url(when there is one) can expire. - Try at 1K first, then remake the one you like at 2K or 4K to save money.
- Do not resend while the outcome is unknown. Every success is charged; set a timeout of at least 3 minutes, as large images can take a while.
- Write clear prompts: subject → action → setting → style → light → camera. English prompts tend to give steadier results.
- To try ideas without code, use Chat AI › Images in the dashboard.