> ## Documentation Index
> Fetch the complete documentation index at: https://docs.playapi.ai/llms.txt
> Use this file to discover all available pages before exploring further.

# Background responses and task retrieval

> Retrieve plugin task responses and distinguish background execution from ordinary upstream responses.

`POST /v1/responses` has ordinary relay and task-plugin paths. A plugin must declare `background` support to accept background mode, and inputs must match its model. An ordinary upstream returning a `resp_` ID does not mean the platform can retrieve it with GET.

## Create and retain

Set `background: true` on a verified Responses request for a background-capable plugin model, and retain the returned `id` and status. Use the input already verified for that model; not every media plugin accepts plain conversational text. Submission usually returns `queued` or `in_progress`, but may complete quickly. `stream` and `background` are separate options.

Do not construct a response ID by manually changing a task ID prefix. Persist the returned ID with its business request so refreshes and timeouts do not cause duplicate submissions.

## Retrieve an existing response

[`GET /v1/responses/{response_id}`](/en/api-reference/responses-retrieve) retrieves only host-recorded plugin task responses, scoped to the calling user and project. Discarded results, unavailable plugins, or IDs outside that identity can return 404. There is no general proxy retrieval for arbitrary upstream responses.

This example only reads an existing response, up to a bounded number of attempts. Install the Python example dependencies and run:

```sh theme={null}
export API_BASE_URL="https://gateway.example.com/v1"
export API_KEY="YOUR_API_KEY"
export API_RESPONSE_ID="resp_YOUR_EXISTING_RESPONSE_ID"
.venv/bin/python examples/response-status.py --max-attempts 10 --interval 2
```

```python theme={null}
import argparse
import math
import os
import time
from urllib.parse import quote
from openai import OpenAI, APIConnectionError, APIStatusError

parser = argparse.ArgumentParser(description="Poll an existing task-plugin response; never submit a new task.")
parser.add_argument("--max-attempts", type=int, default=10)
parser.add_argument("--interval", type=float, default=2.0)
args = parser.parse_args()
if not 1 <= args.max_attempts <= 60 or not math.isfinite(args.interval) or not 0 <= args.interval <= 60:
    parser.error("Use 1..60 attempts and a finite interval of 0..60 seconds.")
response_id = os.environ["API_RESPONSE_ID"]
if not response_id.startswith("resp_") or len(response_id) <= 5:
    raise SystemExit("API_RESPONSE_ID must be an existing task-plugin response ID.")

with OpenAI(base_url=os.environ["API_BASE_URL"].rstrip("/"),
            api_key=os.environ["API_KEY"], timeout=30.0, max_retries=0) as client:
    try:
        for attempt in range(args.max_attempts):
            result = client.get(f"/responses/{quote(response_id, safe='')}", cast_to=dict)
            if (not isinstance(result, dict) or result.get("id") != response_id
                    or result.get("object") != "response"):
                raise ValueError("Invalid response identity.")
            status = result.get("status")
            if result.get("error") or status in ("failed", "incomplete", "cancelled"):
                raise ValueError("Response did not complete.")
            if status == "completed":
                output = result.get("output")
                if not isinstance(output, list) or not output or any(not isinstance(item, dict) for item in output):
                    raise ValueError("Missing output.")
                # Lifecycle completion is not a text, image, or safety quality check.
                print(f"completed: {len(output)} output item(s); validate content for your application.")
                break
            if status not in ("queued", "in_progress"):
                raise ValueError("Unknown response status.")
            if attempt + 1 == args.max_attempts:
                raise SystemExit("Polling limit reached. Keep the response ID; the task may still be running.")
            time.sleep(args.interval)
    except APIStatusError as error:
        raise SystemExit(f"Request failed (HTTP {error.status_code}). Keep the response ID; do not resubmit.")
    except APIConnectionError:
        raise SystemExit("Connection failed. Keep the response ID; do not resubmit.")
    except (ValueError, TypeError, AttributeError):
        raise SystemExit("Response is invalid or not complete. Keep the response ID; do not resubmit.")
```

## Status and application results

| Status | Application action |
| - | - |
| queued / in\_progress | Wait and poll within attempt and business deadline limits |
| completed | Validate and use results according to their actual output types |
| failed / incomplete / cancelled | Do not treat as success; record status and apply business policy |
| Unknown status or invalid structure | Stop polling and retain the ID for diagnosis |

The current host primarily returns queued, in\_progress, completed, and failed. The example also rejects incomplete and cancelled so unsuccessful terminal states cannot become success. Completed output may contain media or other items rather than text. The script only reports lifecycle completion; it does not download artifacts or turn refusals into text answers. Applications must still validate content appropriately.

HTTP failures or exhausted local polling attempts do not cancel the task. To resume later, query the same ID. This endpoint returns JSON snapshots; it does not currently provide SSE resumption, `starting_after` replay, or REST deletion / cancellation.

[Video tasks](/en/guides/video-generation) use separate video endpoints. Confirm response, data, and artifact retention with the operator.

[阅读中文](/zh/guides/background-responses)


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.