Skip to content

Images

Two endpoints create images:

  • POST /v1/images/generations generates images from a text prompt.
  • POST /v1/images/edits edits one or more reference images with a text prompt.

Both endpoints need an API key sent as Authorization: Bearer. See Authentication. The body is JSON. Multipart uploads are not supported, so you send reference images as URLs or data URIs inside the JSON.

Every image request runs as a job. The request can wait for the job and return the images in the response, or return the job at once so you can collect the result later.

Send the model and a prompt. The example uses sakuranbo/cherryimage-1.0-pro.

Terminal window
curl -X POST "https://api.sakuranbo.ai/v1/images/generations" \
-H "Content-Type: application/json" \
-H "Authorization: Bearer $SAKURANBO_API_KEY" \
-d '{
"model": "sakuranbo/cherryimage-1.0-pro",
"prompt": "A matte ceramic coffee mug on a walnut desk, soft morning light, shallow depth of field",
"resolution": "2k",
"aspect_ratio": "4:3"
}'

These are the input parameters of the example model:

NameTypeRequiredDefaultConstraintsDescription
promptstringYesUp to 5,000 charactersText description of the image to generate or the edit to apply.
imagesurl[]NoUp to 10 itemsReference images for editing (1 to 10). Required on /v1/images/edits.
resolutionenumNo2kOne of: 1k, 1.5k, 2kOutput resolution. Determines the per-image price.
nintegerNo11 to 100Number of images to generate (1 to 100). The price is the per-image price times this value.
aspect_ratioenumNoautoOne of: auto, 1:1, 4:3, 3:4, 16:9, 9:16, 3:2, 2:3, 21:9Aspect ratio of the output image.
output_formatenumNojpegOne of: jpeg, pngImage file format.

The request body has these fields:

NameTypeRequiredDefaultConstraints
modelstringYes1 to 128 characters
promptstringYes
nnumberNo
resolutionstringNo
aspect_ratiostringNo
output_formatstringNo
response_formatstringNourlOne of: url, b64_json

resolution selects the price. A parameter that is not in the table, or a value outside its range, returns 400 with invalid_request. error.param names the parameter, and error.details.allowed, error.details.minimum, or error.details.maximum give the valid values.

By default the request waits for the images.

  • If the job finishes within the maximum wait time, the response is 200 with the images. The wait time is stated in the API reference.
  • If the job is still running after that time, the response is 202 with the job and a Location header that points to it. The generation keeps running.
  • If you send Prefer: respond-async, the response is 202 at once, and the response has the header Preference-Applied: respond-async.
Terminal window
curl -X POST "https://api.sakuranbo.ai/v1/images/generations" \
-H "Content-Type: application/json" \
-H "Authorization: Bearer $SAKURANBO_API_KEY" \
-H "Prefer: respond-async" \
-d '{
"model": "sakuranbo/cherryimage-1.0-pro",
"prompt": "A matte ceramic coffee mug on a walnut desk, soft morning light, shallow depth of field",
"resolution": "2k",
"aspect_ratio": "4:3"
}'

After a 202 response, collect the result in one of two ways. Poll the job as described in Jobs, or receive a job.succeeded, job.failed, or job.cancelled event as described in Webhooks.

If the job fails while the request is waiting, the response is an error and not a 202, and error.details.job_id is the ID of the job. After a 202 response, a failure shows in the error field of the job instead, and the request that reads the job still returns 200.

A 200 response has these fields:

NameType
createdinteger
dataobject[]
usageobject
costobject
job_idstring

cost is the final charge. The same amount is in the X-Usage-Cost-Usd header. job_id is the ID of the job that made the images.

Set response_format to choose how the images come back.

  • url is the default. Each item in data has a url and an expires_at. The URL is signed. It needs no API key and works until expires_at, which is 7 days after the job completes. Anyone who has the URL can download the image until then, so treat the URL as a secret. After expires_at the file is deleted, so save the images you need.
  • b64_json puts the image in the response body as base64. If the images are too large to inline, the images that do not fit come back as url items.

data has one item for each image that was delivered. If part of a batch fails, data can have fewer items than n, and you pay for the images that were delivered.

POST /v1/images/edits takes the same fields as the generation endpoint, and the images field is required.

Terminal window
curl -X POST "https://api.sakuranbo.ai/v1/images/edits" \
-H "Content-Type: application/json" \
-H "Authorization: Bearer $SAKURANBO_API_KEY" \
-d '{
"model": "sakuranbo/cherryimage-1.0-pro",
"prompt": "Make the mug dark blue",
"images": [
"https://example.com/reference.png"
]
}'

images is a list of reference images. Each item is a public https URL or a data:image/...;base64, URI of a PNG, JPEG, WebP, or GIF image. The order matters, because the prompt can refer to the first image or the second image. A data URI has a smaller size limit than a URL, so send a large image as a public URL.

The server fetches each URL to check it before it creates the job. It does not follow redirects, and it rejects URLs that have credentials, IP addresses, or internal host names. An image that cannot be used returns 400 with invalid_request. error.param is images followed by the index of the item. For a URL, error.details.reason says what is wrong. For a data URI that is too large, error.details.max_bytes is the limit.

NameTypeRequiredDefaultConstraints
modelstringYes1 to 128 characters
promptstringYes
nnumberNo
resolutionstringNo
aspect_ratiostringNo
output_formatstringNo
response_formatstringNourlOne of: url, b64_json
imagesstring[]Yes1 to 10 items

The response is the same as for generation.

Send an Idempotency-Key header with a value you choose. If a request with the same key and the same content arrives again, you get the same job and you are charged once. The same key with a different request returns 409 with idempotency_conflict. The key is remembered for a limited time, which is stated in the API reference.

When a request is accepted, Sakuranbo AI reserves the price of the images you asked for from your balance. When the job finishes, the charge is calculated for the images that were delivered, and the rest of the reservation returns to your balance. A job that is cancelled, expires, or is rejected is not billed. A failed job is normally not billed either, and its reservation returns to your balance.

In rare cases, Sakuranbo AI cannot confirm whether the request reached the model provider. The job then fails with upstream_error, and its reserved amount stays reserved until Sakuranbo AI confirms whether the request is billed. If it stays reserved, contact support with the job ID.

The price depends on the model, the resolution, and the number of images. See the model catalog and the pricing page, or calculate it before you run the request with POST /v1/estimate. See the Estimate API.

The model provider can reject the prompt, a reference image, or a generated image because of its content. The job then fails with content_policy_violation, and nothing is charged. A request that is waiting for the job returns 422 with this code, and error.details.job_id is the ID of the job. After a 202 response, the code is in the error field of the job.

CodeHTTP statusTypeDescription
invalid_request400invalid_request_errorThe request is malformed or a value is out of range. details.allowed lists the valid values when they are known.
unauthorized401authentication_errorThe API key is missing, malformed, unknown, revoked, or expired. The response does not say which.
balance_insufficient402insufficient_balanceThe available balance is lower than the amount that must be reserved for this request. error.details.limit_source is balance.
key_limit_exceeded402insufficient_balanceThis request would take the API key over its spending limit. error.details.limit_source is key, and error.details.resets_at says when the counter starts again.
account_suspended403permission_errorThe account is suspended, so image, video, and chat requests are refused. Contact support. The balance, deposits, API keys, and jobs stay available.
model_not_found404not_found_errorThe model ID does not exist in the catalog. The chat endpoints also return it for a model that is not a text model.
idempotency_conflict409conflict_errorThe Idempotency-Key was already used with a different request.
payload_too_large413invalid_request_errorThe request body is larger than the allowed size. error.details.max_bytes is the limit.
content_policy_violation422content_policy_errorThe model provider rejected the prompt, a reference image, or the generated output because of its content. The request is not billed.
rate_limited429rate_limit_errorThe model provider is rate limiting requests. POST /v1/reports also returns this code when too many reports come from one address. Retry after the time given in the Retry-After header.
concurrency_limited429rate_limit_errorThe model provider is busy and cannot take this request right now. It is not a limit on the number of jobs in your account. Retry later.
upstream_error502upstream_errorThe upstream provider returned an error.
upstream_unavailable503overloaded_errorThe upstream provider is temporarily out of capacity. Retry later.

POST /v1/images/edits returns the same codes. For a 429 or 503 response, wait the number of seconds in the Retry-After header before you retry. A 402 response has error.details.limit_source, which is balance or key. See Balance and key limits. For the full list of codes, see Errors.