How to Poll Asynchronous OpenAI Image Tasks (A Practical Guide)
A builder-focused pattern for tracking callback-mode image jobs with task IDs, polling, and batch retrieval.

When image generation takes longer than a normal HTTP request, the hard part is not starting the job—it is tracking it without making your application fragile.

This guide shows a small, practical pattern for submitting an OpenAI image request in callback mode and checking its result later through Ace Data Cloud. The useful idea is simple: keep the returned task_id, poll a dedicated task endpoint, and treat “not finished yet” as a normal application state rather than an error.
What the Tasks API is for
The Tasks API exists for image requests submitted in callback mode. Add a callback_url to the original image generation or editing request, and the submission returns a task_id immediately. Your worker, scheduled job, or backend can then query that task independently.
There is one important boundary: task records are persisted only when the original image request includes callback_url. A synchronous request does not create a task that can later be queried through this interface.
The task endpoint is:
POST https://api.acedata.cloud/openai/tasks
Use these headers:
accept: application/json
authorization: Bearer {token}
content-type: application/json
The endpoint supports two actions:
retrievefetches one task byidortrace_id.retrieve_batchsearches multiple tasks by IDs, trace IDs, application, user, type, or creation window.
For most integrations, id is the simplest choice because it is the task_id returned by the original submission. A custom trace_id is useful only when you want to associate a request with your own business identifier.
Query one task with retrieve
Suppose your application has already submitted an image request and stored the returned task ID. A single-task lookup needs only the action and that ID:
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"
}'
A matching task can contain its original request, final response, timestamps such as created_at, started_at, and finished_at, plus elapsed. The response also identifies the relevant application_id, user_id, and credential_id. If nothing matches, the API returns an empty object, so handle {} explicitly rather than assuming every HTTP success contains a task.
The final image URL lives inside the task's response after processing completes. Until that response is present, the task is still work in progress.
Build a polling loop that stays boring
Polling code should be predictable. Submit once, save the ID, then query the task at a measured interval. Do not resubmit the generation request merely because the result is not ready yet.
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()
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(task["response"])
break
time.sleep(3)
In production, add a maximum wait time and store the task ID before polling. That way, a process restart does not lose the job. You can also let your callback handler update the same database row; polling then becomes a recovery path rather than the only completion mechanism.
Use retrieve_batch for operations and dashboards
Single retrieval works well for a request page, but operational tools often need a wider view. Set action to retrieve_batch and filter with one of ids, trace_ids, application_id, user_id, or a created_at_min / created_at_max window.
{
"action": "retrieve_batch",
"trace_ids": ["my-trace-001", "my-trace-002"]
}
The batch response contains items and count. You can narrow it further with type, using images, images_generations, or images_edits, and paginate with offset and limit (the documented default limit is 12). This is useful for an internal queue viewer, a retry dashboard, or a support tool that needs to locate a request by a customer-facing trace ID.
A practical mental model
Treat asynchronous image generation as a small state machine: submitted, running, and finished. The task_id is the stable handle; finished_at and response tell you when the useful output exists. Keep submission separate from status checks, make empty results safe, and use batch retrieval only when you actually need an operational view.
That separation is what makes the workflow maintainable: your user-facing request can return quickly, while the slower image work continues behind a clean, inspectable interface. The complete field reference and response examples are in the OpenAI Tasks API integration guide.






