ScreenshotNeo

BlogHow-to

How To Cancel An Image Build Through An API

Cancel synchronous and streamed image requests with an HTTP abort, or cancel background Responses jobs with the dedicated endpoint.

By the ScreenshotNeo team1 October 20267 min read

Direct answer: cancel a synchronous or streamed image-generation request by terminating the HTTP connection. In Node.js, pass an AbortSignal and call abort(); this also stops the request while the response body is being read. For an asynchronous background Responses API request, send POST /v1/responses/{response_id}/cancel and record the returned response status.

There is no separate documented image-generation job cancellation method for POST /images/generations. The correct mechanism depends on how the request runs:

Execution mode How to cancel What you observe
Synchronous Image API Abort or close the HTTP connection A client-side cancellation or transport error
Streaming image request Abort the stream and close the connection A stream cancellation or transport error
Background Responses API POST to /v1/responses/{response_id}/cancel A response object with a status to persist

1. Cancel a synchronous request in Node.js

Use an AbortController. Keep the controller available to the code that handles a user cancel button, request timeout, job shutdown, or other stop condition.

import OpenAI from "openai";

const client = new OpenAI({ apiKey: process.env.OPENAI_API_KEY });
const controller = new AbortController();

// Replace this with a UI event, job timeout, or shutdown handler.
const cancelTimer = setTimeout(() => controller.abort(), 10_000);

try {
  const result = await client.images.generate(
    {
      model: "gpt-image-1",
      prompt: "A red fox reading beside a campfire",
      size: "1024x1024"
    },
    { signal: controller.signal }
  );

  console.log("Image generated:", result.data?.[0]);
} catch (error) {
  if (controller.signal.aborted) {
    console.log("Image generation was cancelled");
  } else {
    throw error;
  }
} finally {
  clearTimeout(cancelTimer);
}

The OpenAI Node SDK documents AbortSignal cancellation, including cancellation while the response body is being read. Treat an abort exception as an expected control-flow path when the caller requested cancellation.

Cancel from another function

import OpenAI from "openai";

const client = new OpenAI({ apiKey: process.env.OPENAI_API_KEY });

export function startImageBuild(prompt) {
  const controller = new AbortController();

  const promise = client.images.generate(
    { model: "gpt-image-1", prompt },
    { signal: controller.signal }
  );

  return {
    promise,
    cancel() {
      controller.abort();
    }
  };
}

const build = startImageBuild("A watercolor lighthouse in a storm");
setTimeout(() => build.cancel(), 5_000);

try {
  const result = await build.promise;
  console.log(result.data?.[0]);
} catch (error) {
  if (error.name === "AbortError" || error.code === "ABORT_ERR") {
    console.log("Cancelled by caller");
  } else {
    throw error;
  }
}

2. Cancel a streamed image generation

Streaming uses the same transport rule: abort the request and close the stream. Do not wait for the stream to finish after the user has cancelled.

import OpenAI from "openai";

const client = new OpenAI({ apiKey: process.env.OPENAI_API_KEY });
const controller = new AbortController();

setTimeout(() => controller.abort(), 8_000);

try {
  const stream = await client.images.generate(
    {
      model: "gpt-image-1",
      prompt: "A detailed architectural sketch of a treehouse",
      size: "1024x1024",
      stream: true,
      partial_images: 2
    },
    { signal: controller.signal }
  );

  for await (const event of stream) {
    if (controller.signal.aborted) break;
    // Process each image-generation stream event here.
    console.log(event);
  }
} catch (error) {
  if (controller.signal.aborted) {
    console.log("Stream cancelled");
  } else {
    throw error;
  }
}

If your HTTP client does not expose an SDK-level signal, use its equivalent cancellation primitive. The essential operation is closing the underlying connection; deleting a local variable or stopping your event loop does not reliably notify the server.

3. Cancel a background Responses API request

Background execution is different because the request can continue after the original HTTP connection ends. First retain the response ID returned when you create the background response. Then call the cancellation endpoint while it is in flight.

curl -X POST "https://api.openai.com/v1/responses/RESPONSE_ID/cancel" \
  -H "Authorization: Bearer $OPENAI_API_KEY" \
  -H "Content-Type: application/json"

The endpoint returns the response object. Persist its status in your job record so workers, dashboards, and retry logic agree about the final state.

Background cancellation in Python

import os
import requests

response_id = "RESPONSE_ID"
response = requests.post(
    f"https://api.openai.com/v1/responses/{response_id}/cancel",
    headers={
        "Authorization": f"Bearer {os.environ['OPENAI_API_KEY']}",
        "Content-Type": "application/json",
    },
    timeout=30,
)
response.raise_for_status()
body = response.json()
print("Cancellation response status:", body.get("status"))

Background cancellation in Node.js

const responseId = "RESPONSE_ID";

const res = await fetch(
  `https://api.openai.com/v1/responses/${responseId}/cancel`,
  {
    method: "POST",
    headers: {
      Authorization: `Bearer ${process.env.OPENAI_API_KEY}`,
      "Content-Type": "application/json"
    }
  }
);

if (!res.ok) {
  throw new Error(`Cancel failed: ${res.status} ${await res.text()}`);
}

const response = await res.json();
console.log("Cancellation response status:", response.status);

4. A complete cancellation workflow

  1. Choose synchronous, streaming, or background execution before starting the build.
  2. Keep the AbortController or response ID with the job record.
  3. Expose cancellation to the caller and make the operation idempotent in your application.
  4. For synchronous and streaming calls, abort the transport and classify the resulting exception as cancellation.
  5. For background calls, POST to the cancel endpoint and persist the returned response status.
  6. Stop downstream work that depends on the image, such as publishing, indexing, or notifications.

Cancellation state model

Record at least requested, cancelled, completed, and failed in your own job store. A transport abort tells your client that the connection ended; it does not provide a server-side response object. A background cancellation response gives you a status to reconcile with your job record.

5. Python and cURL for synchronous cancellation

Python’s standard HTTP clients differ in how they interrupt an in-flight request. Use the cancellation mechanism provided by the client you selected, and close the response or session when cancellation is requested. A timeout is useful for bounding work, but a timeout is not the same as a user-initiated cancel.

import os
import requests

# This bounds how long the call may wait. Close the request from the
# controlling thread or task when the user explicitly cancels it.
try:
    response = requests.post(
        "https://api.openai.com/v1/images/generations",
        headers={"Authorization": f"Bearer {os.environ['OPENAI_API_KEY']}"},
        json={
            "model": "gpt-image-1",
            "prompt": "A red fox reading beside a campfire",
            "size": "1024x1024",
        },
        timeout=(10, 120),
    )
    response.raise_for_status()
    print(response.json())
except requests.exceptions.Timeout:
    print("Request timed out; decide whether to retry or mark it cancelled")

With cURL, terminating the process or sending an interrupt closes the HTTP connection:

curl -X POST "https://api.openai.com/v1/images/generations" \
  -H "Authorization: Bearer $OPENAI_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"model":"gpt-image-1","prompt":"A red fox reading beside a campfire","size":"1024x1024"}'

6. Common errors and fixes

Symptom Cause Fix
The SDK call keeps running after the UI cancel The signal was not passed to the request, or the controller was discarded Create one controller per operation, pass its signal to the SDK call, and retain it until completion.
An abort is logged as an application failure Cancellation is being handled by the generic error path Check signal.aborted or the client’s abort error type before reporting a failure.
A stream still emits buffered events Events already arrived before the connection closed Ignore events after cancellation and make downstream writes conditional on active state.
The background cancel request returns an error The response ID is wrong, the request is no longer cancellable, or authentication is invalid Verify the ID, API key, URL, and current response state; persist the returned error for operators.
The caller expects a refund Cancellation semantics were confused with billing reversal Do not assume completed work is rolled back or that usage is refunded; the reviewed documentation makes no such promise.
A retry creates duplicate work The client cannot tell timeout, cancellation, and server failure apart Store an operation ID and state transition, and retry only when your application policy allows it.

7. Reliability, performance, and cost considerations

  • Reliability: transport cancellation is local observability. After an abort, you cannot infer a server-side final state for a synchronous request from the client exception alone.
  • Background jobs: use the cancel endpoint and persist its response status. Poll or reconcile according to your job design rather than assuming the cancel request completed the image operation instantly.
  • Performance: abort as soon as the user cancels to stop reading response bytes and release the connection. Set bounded connect and read timeouts for calls that must not run indefinitely.
  • Cost: cancellation does not guarantee that already completed work is undone or refunded. Make billing decisions from the documented usage behavior of the API and your account records.
  • Streaming: partial image events may already have consumed resources before cancellation. Treat partial output as disposable unless your product explicitly supports it.

8. Or skip the browser setup

If your workflow also needs a clean screenshot of a generated image page, preview, or result URL, ScreenshotNeo provides a single HTTP request instead of maintaining browser automation. Its API accepts a URL and returns PNG, JPEG, WebP, or PDF output.

See the ScreenshotNeo API documentation for all options. A minimal call is:

curl -G "https://api.screenshotneo.com/v1/shot" -d access_key=YOUR_API_KEY --data-urlencode url=https://stripe.com -o shot.webp
import requests
r = requests.get("https://api.screenshotneo.com/v1/shot", params={"access_key": "YOUR_API_KEY", "url": "https://stripe.com"}, timeout=90)
open("shot.webp", "wb").write(r.content)
const q = new URLSearchParams({ access_key: 'YOUR_API_KEY', url: 'https://stripe.com' }); const res = await fetch(`https://api.screenshotneo.com/v1/shot?${q}`);

ScreenshotNeo removes cookie banners, newsletter popups, and chat widgets before capture. Bot checks, blank pages, failed loads, timeouts, and cache hits are not billed, and response headers identify the page verdict and billing result. Its MCP server lets AI agents use take_screenshot, get_page_info, and capture_pdf. The free plan includes 1,000 screenshots per month without a card; paid plans start at $5 for 3,000 screenshots.

Create a free ScreenshotNeo account.

9. FAQ

Is there a cancel endpoint for Image API generations?

The documented synchronous mechanism is terminating the HTTP connection. The reviewed image method references do not list a separate image-generation job cancellation endpoint.

Can I cancel while reading a response body?

Yes. The OpenAI Node SDK documents AbortSignal cancellation while the response body is being read.

What should I store for a background request?

Store the response ID immediately, then persist the status returned by /v1/responses/{response_id}/cancel.

Does aborting guarantee a usage refund?

No guarantee is stated in the reviewed documentation. Do not build refund behavior on that assumption.

Should I keep polling after cancellation?

For background work, reconcile the returned response status with your job record. For synchronous work, the connection termination is the cancellation signal available to your client.

Sources