Async Inference (V2)
Submit inference requests asynchronously and poll for results. Ideal for long-running models like video generation, image upscaling, and LLMs.
The V2 async API lets you submit a request, get a request_id immediately,
and poll for the result when it's ready. No long-lived HTTP connections.
Sync (v1) vs. async (v2). The v1 sync API (POST /v1/{slug}) returns the
output in a single blocking response and is in maintenance mode — fine for
fast models that finish in a few seconds. Use v2 async for anything that
can take longer than ~10 s (video, upscaling, LLMs), or whenever you want
explicit control over the request deadline. Prefer not to manage the polling
loop yourself? The Python SDK wraps all of this in a
single segmind.run() call.
Quick start
1. Submit a request
curl -X POST "https://api.segmind.com/v2/seedream-4.5" \
-H "x-api-key: YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"prompt": "a red rose on a wooden table, studio lighting",
"aspect_ratio": "1:1",
"seed": 123
}'Response:
{
"request_id": "2c7f59ea-13f1-402c-9353-915a2b5a2124",
"status": "QUEUED",
"poll_url": "https://api.segmind.com/v1/requests/2c7f59ea-...",
"status_url": "https://api.segmind.com/v2/requests/2c7f59ea-.../status",
"response_url": "https://api.segmind.com/v2/requests/2c7f59ea-..."
}| Field | Description |
|---|---|
request_id | Unique identifier for this request |
status | Always QUEUED on submit |
poll_url | V1 poll endpoint (backward compatible) |
status_url | Lightweight status check (no output payload) |
response_url | Full result endpoint (output + metadata) |
2. Check status (lightweight)
Use status_url for efficient polling — it returns only status and metrics,
no output payload.
curl "https://api.segmind.com/v2/requests/2c7f59ea-.../status" \
-H "x-api-key: YOUR_API_KEY"While processing:
{
"status": "QUEUED",
"request_id": "2c7f59ea-...",
"status_url": "https://api.segmind.com/v2/requests/2c7f59ea-.../status",
"response_url": "https://api.segmind.com/v2/requests/2c7f59ea-...",
"metrics": {}
}When done:
{
"status": "COMPLETED",
"request_id": "2c7f59ea-...",
"metrics": {
"cost": 0.04,
"inference_time": 13.06,
"queue_time": 0.3,
"total_time": 13.36,
"remaining_credits": 92.86
}
}See Metrics for what each field means.
3. Fetch the result
Once status is COMPLETED, fetch the full result from response_url.
curl "https://api.segmind.com/v2/requests/2c7f59ea-..." \
-H "x-api-key: YOUR_API_KEY"Image result:
{
"status": "COMPLETED",
"images": [
{
"url": "https://images.segmind.com/generations/a1b2c3d4-.../e17ba.jpeg",
"content_type": "image/jpeg",
"file_size": "868446"
}
],
"output": "https://images.segmind.com/generations/a1b2c3d4-.../e17ba.jpeg",
"seed": "123",
"prompt": "a red rose on a wooden table, studio lighting",
"timings": { "inference": 13.06 },
"metrics": {
"cost": 0.04,
"inference_time": 13.06,
"queue_time": 0.3,
"total_time": 13.36,
"remaining_credits": 92.86
}
}Metrics
Every status (status_url) and result (response_url) response for a request
that reached COMPLETED (and, where available, FAILED) carries a metrics
object. Fields are best-effort — a field is omitted when it isn't applicable
(e.g. cost/remaining_credits on an unbilled or failed request).
| Field | Unit | Description |
|---|---|---|
cost | credits | Credits charged for this inference. Matches the X-Cost header returned by the v1 sync API. |
remaining_credits | credits | Your account balance after this inference was billed. |
inference_time | seconds | Time the model spent processing (excludes time spent queued). |
queue_time | seconds | Time the request waited in the queue before a worker picked it up. |
total_time | seconds | End-to-end time, queue_time + inference_time. |
retry_count | count | Number of times the request was retried by a worker. Present only when a retry occurred. |
cost lets you track per-request spend on the async API, the same way the
X-Cost response header works on the v1 sync API.
Response formats by modality
The result shape depends on what the model produces.
Image models
{
"status": "COMPLETED",
"images": [{ "url": "...", "content_type": "image/jpeg", "file_size": "..." }],
"output": "https://...",
"seed": "123",
"prompt": "...",
"timings": { "inference": 13.06 },
"metrics": {
"cost": 0.04,
"inference_time": 13.06,
"queue_time": 0.3,
"total_time": 13.36,
"remaining_credits": 92.86
}
}Video models
{
"status": "COMPLETED",
"video": {
"url": "...",
"content_type": "video/mp4",
"file_name": "output.mp4",
"file_size": 5757619
},
"output": "https://..."
}LLM / text models
{
"status": "COMPLETED",
"output": "The generated text...",
"reasoning": null,
"partial": false,
"error": null
}The output field is always present across all modalities for backward
compatibility.
Status values
| Status | Description |
|---|---|
QUEUED | Request accepted, waiting for a worker |
PROCESSING | A worker has picked up the request |
COMPLETED | Inference finished, result available |
FAILED | Inference failed (see error field) |
Polling guidance
Poll the status_url until status is COMPLETED or FAILED, then fetch the
full body from response_url.
- Interval: default to 1 s between polls. For known-slow models (long video, long-running LLMs) back off to 5–10 s to cut request volume.
- Timeout: use an overall deadline of ≤ 600 s for most models. Raise it for slow video models, or avoid polling entirely with webhooks for fire-and-forget jobs.
- Use the lightweight
status_url(notresponse_url) while polling — it skips the output payload.
Idempotency
Each POST /v2/{slug} creates a new request_id. The submit is the only
step worth retrying: if a submit returns a 5xx, retry the submit (you'll get
a fresh request_id). Never retry by re-POSTing after a successful submit — that
starts a second billable job. Polling (GET) is always safe to retry.
A grounded request adds a top-level grounding object to this result — see
Web Search Grounding.
Where the output lives
output and every entry in images point at images.segmind.com. If you
run behind an egress allowlist, a firewall, or a Content Security Policy, that
is the host to allow — the API host alone is not enough to fetch a result.
The output URL is public. It needs no API key — anything that has the link can fetch the file. The link is long and unguessable, so treat it the way you would any unlisted share link: fine to pass to your own frontend, not a substitute for access control.
Result expiry
Two different things expire on two different clocks, and it is worth keeping them apart:
| How long it lasts | What happens after | |
|---|---|---|
The request record — everything under /v1/requests/{id} and /v2/requests/{id} | temporary | all three poll endpoints return 404 |
The output file — the URL in output and images[].url | kept under the storage policy | the link stops resolving |
The request record is the short-lived one. The output file outlives it — a result URL keeps working after the request that produced it has stopped being pollable.
Save the output URL when you fetch the result. The polling window is not a guarantee and is not something to design around — once the request record expires you cannot recover the URL from the API, even though the file itself is still there. Treat the poll endpoints as a delivery mechanism, not as storage.
Error handling
Failed requests return HTTP 422 on V2 endpoints. Timing metrics may still be
present, but billing fields (cost, remaining_credits) are omitted since nothing
was charged:
{
"status": "FAILED",
"error": "Prompt is Mandatory and must be string",
"metrics": { "inference_time": 0.007, "queue_time": 0.23, "total_time": 0.24 }
}Not found returns HTTP 404:
{
"error": "Request 00000000-... not found"
}Endpoints summary
| Endpoint | Method | Description |
|---|---|---|
/v2/{model} | POST | Submit async request |
/v2/requests/{id}/status | GET | Lightweight status + metrics |
/v2/requests/{id} | GET | Full result (when COMPLETED) |
/v1/requests/{id} | GET | Legacy poll (status + output combined) |
Full Python example
The Python SDK does the submit-and-poll loop for you —
result = segmind.run("seedream-4.5", prompt="..."). The raw example below
shows what happens under the hood if you'd rather call the API directly.
import requests
import time
API_KEY = "YOUR_API_KEY"
BASE = "https://api.segmind.com"
# Submit
resp = requests.post(
f"{BASE}/v2/seedream-4.5",
headers={"x-api-key": API_KEY},
json={"prompt": "a beautiful sunset", "aspect_ratio": "16:9"},
)
data = resp.json()
request_id = data["request_id"]
print(f"Submitted: {request_id}")
# Poll
while True:
status = requests.get(
f"{BASE}/v2/requests/{request_id}/status",
headers={"x-api-key": API_KEY},
).json()
if status["status"] in ("COMPLETED", "FAILED"):
break
time.sleep(2)
# Fetch result
if status["status"] == "COMPLETED":
result = requests.get(
f"{BASE}/v2/requests/{request_id}",
headers={"x-api-key": API_KEY},
).json()
print(f"Image URL: {result['images'][0]['url']}")
print(f"Inference time: {result['timings']['inference']}s")See also
- Python SDK —
segmind.run()/submit_async()instead of hand-rolled polling. - Webhooks — get notified when a result is ready.
- Rate limits and API error codes.