DEV Community

Cover image for How to Poll Async Image Tasks with the OpenAI Tasks API
Germey
Germey

Posted on • Originally published at platform.acedata.cloud

How to Poll Async Image Tasks with the OpenAI Tasks API

When an image request takes longer than a comfortable HTTP timeout, the cleanest user experience is not to keep the browser waiting — it is to submit the job, store a task ID, and let your backend check the result later.

That is the job of the OpenAI Tasks API in Ace Data Cloud: it lets you retrieve tasks created by image requests that were submitted in callback mode.

What you can do

The Tasks API is designed for asynchronous image workflows. You use it when an original image generation or editing request includes a callback_url. In that mode, the image interface accepts the request and immediately returns a task_id. Later, you can query the task by id, or by trace_id if you passed your own custom tracking identifier.

The key details are:

Endpoint: POST https://api.acedata.cloud/openai/tasks
Headers:
  accept: application/json
  authorization: Bearer {token}
  content-type: application/json
Supported actions:
  retrieve
  retrieve_batch
Enter fullscreen mode Exit fullscreen mode

There is one important constraint: task records are only persisted when the original image request includes callback_url. Synchronous, non-callback calls do not create queryable task records.

How it works

Think of the flow as a small job system:

  1. Your app submits an image request with a callback_url.
  2. The image endpoint immediately returns a task_id.
  3. You store that task ID with your internal job record.
  4. Your worker or backend calls POST /openai/tasks with action: retrieve.
  5. When the task has a response, you read the final image URL from response.data[].

A returned task can include fields such as id, trace_id, type, application_id, user_id, credential_id, created_at, finished_at, duration, request, and response. That is enough to build both a user-facing status page and an internal debugging trail.

Retrieve one task by task ID

For most apps, the simplest approach is to use the task ID returned by the original submission response. You do not need to invent a custom trace_id unless you want to map tasks to your own business identifier.

curl -X POST 'https://api.acedata.cloud/openai/tasks' \
  -H 'accept: application/json' \
  -H 'authorization: Bearer {token}' \
  -H 'content-type: application/json' \
  -d '{
    "action": "retrieve",
    "id": "7489df4c-ef03-4de0-b598-e9a590793434"
  }'
Enter fullscreen mode Exit fullscreen mode

If the task exists and has completed, the response follows this shape:

{
  "id": "7489df4c-ef03-4de0-b598-e9a590793434",
  "trace_id": "my-custom-trace-001",
  "type": "images",
  "created_at": 1763142607.967,
  "finished_at": 1763142637.404,
  "duration": 29.437,
  "request": {
    "model": "gpt-image-1",
    "prompt": "A cat sitting on a table",
    "size": "1024x1024",
    "callback_url": "https://your.server/callback"
  },
  "response": {
    "created": 1763142637,
    "data": [
      { "url": "https://platform.cdn.acedata.cloud/openai/...png" }
    ],
    "success": true
  }
}
Enter fullscreen mode Exit fullscreen mode

If no task matches, the API returns an empty object:

{}
Enter fullscreen mode Exit fullscreen mode

That empty-object behavior is useful in a polling loop: treat it as “not found or not available yet,” not as a completed image.

Submit and poll from Python

Here is the end-to-end shape for a backend worker. The image request includes callback_url, so the task is persisted and can be queried later.

import os
import time
import requests

API = "https://api.acedata.cloud"
HEADERS = {
    "authorization": f"Bearer {os.environ['ACEDATA_API_KEY']}",
    "content-type": "application/json",
}

submit = requests.post(
    f"{API}/openai/images/generations",
    headers=HEADERS,
    json={
        "model": "gpt-image-1",
        "prompt": "A watercolor style cat sitting on a table",
        "callback_url": "https://webhook.site/your-uuid",
    },
).json()

print("submitted:", submit)
task_id = submit["task_id"]

while True:
    task = requests.post(
        f"{API}/openai/tasks",
        headers=HEADERS,
        json={"action": "retrieve", "id": task_id},
    ).json()

    if task and task.get("response"):
        print("finished:", task["response"])
        break

    time.sleep(3)
Enter fullscreen mode Exit fullscreen mode

In a real app, I would not keep this loop inside a request handler. Put it in a worker, queue job, scheduled function, or background task. Store task_id, the submitted prompt, the user ID in your own system, and the final response.data[] when it arrives.

Batch query for dashboards and recovery

The second action is retrieve_batch. It is useful when you need to recover multiple jobs, build an admin dashboard, or query by your own tracking IDs.

The request can include fields such as ids, trace_ids, application_id, user_id, type, offset, limit, created_at_min, and created_at_max. At least one lookup dimension is required: for example ids, trace_ids, application_id, user_id, or a created-at time window.

curl -X POST 'https://api.acedata.cloud/openai/tasks' \
  -H 'authorization: Bearer {token}' \
  -H 'content-type: application/json' \
  -d '{
    "action": "retrieve_batch",
    "trace_ids": ["my-trace-001", "my-trace-002"]
  }'
Enter fullscreen mode Exit fullscreen mode

A batch response contains items and count, so your UI can render a task table without designing another aggregation layer first.

Practical implementation notes

A few details make this flow much easier to operate:

  • Save both task_id and trace_id when available.
  • Treat finished_at as the signal that a task has reached a terminal state.
  • Read final images from response.data[], not from the original submission payload.
  • Use duration for basic latency monitoring.
  • Remember that old task records may be cleared after the platform retention period.
  • Poll gently. The Tasks interface itself does not incur charges, but your worker should still avoid noisy loops.

This pattern keeps the image-generation UX predictable: users submit work, your system tracks the task, and the final image appears when the callback or polling result is ready.

For the complete field reference, see the OpenAI Tasks API Integration Guide.

Top comments (0)