Skip to main content

Nano Banana 2.1 image editing takes one to fourteen source images and a description of the change, at 1k, 2k or 4k. It keeps faces and product details across edits and can print new text into the picture.

From $0.022/image30% below the publisher's list priceWith Official fallback: up to $0.048

Workbench

Send a request

Quickstart

Examples use the selected endpoint’s public parameter definitions. Replace the API key and example media, then send the request from your server.

SDKs & integrations
POSThttps://api.spicyapi.ai/api/v1/jobs/createTask

API authentication

Keep the API key in the server environment variable SPICY_API_KEY. Use Bearer authentication and Content-Type: application/json for JSON requests.

Authorization: Bearer $SPICY_API_KEY
Nano Banana 2.1 · Image Editing · Sample output
Sample outputUse this example
# Generate the idempotency key once; reuse it when retrying after a lost response.
export SPICY_IDEMPOTENCY_KEY="${SPICY_IDEMPOTENCY_KEY:-$(uuidgen)}"
curl -X POST https://api.spicyapi.ai/api/v1/jobs/createTask \
  -H "Authorization: Bearer $SPICY_API_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: $SPICY_IDEMPOTENCY_KEY" \
  -d '{
  "model": "google/nano-banana-2.1/edit",
  "input": {
    "aspect_ratio": "auto",
    "enable_image_search": false,
    "enable_web_search": false,
    "image_urls": [
      "https://example.com/reference.png"
    ],
    "output_format": "png",
    "prompt": "A ceramic teapot on a linen cloth, soft window light, muted palette",
    "resolution": "1k"
  }
}'

# Copy data.taskId from the response into TASK_ID, then poll the status.
TASK_ID="TASK_ID_FROM_RESPONSE"
curl "https://api.spicyapi.ai/api/v1/jobs/recordInfo?taskId=$TASK_ID" \
  -H "Authorization: Bearer $SPICY_API_KEY"

Generated from this model’s input schema — the same one the API validates every request against.

Input parameters

Place these fields inside the request body’s input object. Names and types match the API. Do not assume a default when none is specified.

image_urlsarray<string>RequiredAffects price

1 to 14 source images, in the order your prompt refers to them. The economy route takes up to 10; an edit with 11 to 14 runs on the official route at the official price, so keep Official fallback on. On the official route each source adds a small fixed charge.

Default
Not specified
Constraints
minItems:1
maxItems:14
promptstringRequired

Up to 5,000 characters. Say what changes, then list what must stay the same; refer to sources as the first image, the second image and so on. Words in double quotes are printed in the image.

Default
Not specified
Constraints
minLength:1
maxLength:5000
official_fallbackbooleanOptional

On by default. Each edit runs on the economy route first. If that route cannot complete it, for example because it refuses a Mild-level edit, the edit runs again on the official route and is billed at the official price instead of the economy price. Turn it off to pay only the economy price; the edit may then be refused or fail, and edits with more than 10 source images, web search and image search are not available.

Default
true
output_formatstringOptional

png (default) or jpeg. JPEG files are several times smaller; the price is the same.

Default
"png"
Allowed values
"png""jpeg"
enable_image_searchbooleanOptionalAffects price

Off by default. When on, the model looks up reference pictures on the web, useful when the edit adds a real place or product you did not upload. Adds a search charge to the request, shown in the quote. In that case the edit runs on the official route at the official price, so keep Official fallback on.

Default
false
enable_web_searchbooleanOptionalAffects price

Off by default. When on, the model looks up current facts before drawing. Adds a search charge to the request, shown in the quote. In that case the edit runs on the official route at the official price, so keep Official fallback on.

Default
false
resolutionstringOptionalAffects price

1k (default), 2k or 4k. A square frame is 1024, 2048 or 4096 pixels across; each tier has its own price.

Default
"1k"
Allowed values
"1k""2k""4k"
aspect_ratiostringOptional

auto (default) keeps the shape of the source image; with several sources, choose a shape explicitly. Fourteen shapes are available, including 4:1, 1:4, 8:1 and 1:8. The shape does not change the price. Extending a photo to 4:1 looked natural in our runs, while 8:1 left visible seams in the newly added sides.

Default
"auto"
Allowed values
"auto""1:1""3:2""2:3""3:4""4:3""4:5""5:4""9:16""16:9""21:9""1:4""4:1""1:8""8:1"

Track the task

HTTP 202 means the task was accepted, not completed. Save the returned taskId and query that task. Do not create another task while waiting for its result.

Accepted response
HTTP/1.1 202 Accepted
Location: /api/v1/jobs/recordInfo?taskId=job_01k3m8x9q2z4v7n5p6r8s0t1w3

{
  "code": 200,
  "msg": "success",
  "request_id": "req_example_create",
  "data": {
    "taskId": "job_01k3m8x9q2z4v7n5p6r8s0t1w3",
    "state": "queued",
    "estimatedCost": "0.750000"
  }
}

The accepted response includes the estimate so your app can show the same amount in task history and billing.

Read the job
curl --get "https://api.spicyapi.ai/api/v1/jobs/recordInfo" \
  --data-urlencode "taskId=$TASK_ID" \
  -H "Authorization: Bearer $SPICY_API_KEY"

Start polling at about 2 seconds and gradually increase the interval. Stop at a terminal state. After a connection failure, query the original taskId. Retry creation only with the original idempotency key and body.

Or let the callback find you
import { verifyWebhook } from "@spicyapi/sdk";

// express.raw keeps the bytes we signed; express.json never matches.
app.post("/hooks/spicy", express.raw({ type: "application/json" }), (req, res) => {
  const { payload } = verifyWebhook({
    rawBody: req.body,
    timestamp: req.header("X-Webhook-Timestamp"),
    signature: req.header("X-Webhook-Signature"),
    payloadVersion: Number(req.header("X-Webhook-Payload-Version")),
    secret: process.env.SPICY_WEBHOOK_SECRET,
  });
  res.status(200).end();
  void handleFinishedTask(payload);
});

Pass callBackUrl when you create the task and the finished record is POSTed to you — no polling loop at all. Every delivery carries X-Webhook-Timestamp, X-Webhook-Signature and X-Webhook-Payload-Version. The signature is a base64 HMAC-SHA256 over taskId.timestamp.sha256(body), so it must be checked against the raw bytes: parsing the JSON and re-serialising it changes them and the check will fail. Failed deliveries are retried, so the same taskId can arrive twice — make the handler idempotent. Answer 2xx first and do the work afterwards; a slow handler is treated as a failed delivery.

Read the result

Consume output only when state is succeeded. On failure, use errorCode, errorMessage and request_id to investigate. Example costs and states do not represent an actual bill.

Completed response example
{
  "code": 200,
  "msg": "success",
  "request_id": "req_example_record",
  "data": {
    "taskId": "job_01k3m8x9q2z4v7n5p6r8s0t1w3",
    "model": "google/nano-banana-2.1/edit",
    "state": "succeeded",
    "output": {
      "assets": [
        {
          "key": "tasks/2026/08/28/job_01k3m8x9q2z4v7n5p6r8s0t1w3/3f7a1c9e5b2d48f0a6c1e3d5b7f9a1c3.png",
          "mime": "image/png",
          "url": "https://example.r2.cloudflarestorage.com/results/job_01k3m8x9q2z4v7n5p6r8s0t1w3/result.png?X-Amz-Signature=SIGNATURE_FROM_RESPONSE",
          "expiresAt": "2026-08-28T12:20:08.000Z"
        }
      ]
    },
    "cost": "0.750000",
    "settled": true,
    "createdAt": "2026-08-28T12:00:00Z",
    "completedAt": "2026-08-28T12:00:30Z"
  }
}

For each available asset, open or download assets[].url directly without an API Authorization header. The signed URL expires at expiresAt; poll the task again to refresh it while the asset remains within its retention period. A pending or unavailable asset has no URL. Treat signed URLs as private.

SDKs & integrations

Use SpicyAPI in your app, terminal, AI assistant or visual workflow. Choose a setup guide below.

Use it in ComfyUI

Install the SpicyAPI nodes from ComfyUI Manager or with the command below, then search for Nano Banana 2.1 · Image Editing on the canvas. The node has the same options as this page and shows its price before it runs.

cd ComfyUI/custom_nodes
git clone https://github.com/spicyapi-ai/comfyui-spicyapi