Tasks
Every generation and analysis call creates a task. Its three statuses, why a completed task can hold failed items, the ways to collect a result, and how long files last.
Every generation and analysis request creates a task. Mynth validates the request, holds the estimated cost on your balance, and returns a task id within milliseconds. The work runs after that, and you collect the result separately.
The SDK's generate(), rate(), and similar methods look synchronous because
they create the task and poll it for you. The HTTP API has no synchronous
generate call.
What creates a task#
| Request | Task type | result holds |
|---|---|---|
POST /image/generate | image.generate | generated images |
POST /image/remove-background | image.remove_background | one cutout image |
POST /image/rate | image.rate | a content rating level |
POST /image/alt | image.alt | alt text |
POST /image/review | image.review | a quality score and findings |
POST /video/generate | video.generate | a generated video |
Each answers 201 with the task id and the held estimate:
{ "data": { "taskId": "tsk_01KE7XWWEQ4MCGWKBQKJ1G47RP", "estimatedCost": "0.03" } }Task ids are tsk_ followed by a ULID, so they sort by creation time.
Statuses#
There are three. pending covers both queued and running, so there is no
running status to wait for.
201 { taskId, estimatedCost } estimate held on your balance
│
▼
pending ──┬──▶ completed result set, successful outputs charged
└──▶ failed errors set, hold released, nothing chargedA task settles once. It never leaves completed or failed, and Mynth never
reruns a settled task. To try again, send a new request, which creates a new
task and a new hold.
Completed does not mean every item worked#
image.generate with count: 4 runs four generations independently. When one
fails, the task still completes, and each entry in result.images carries its
own status:
{
"status": "completed",
"result": {
"model": "black-forest-labs/flux.2-pro",
"images": [
{
"status": "success",
"id": "img_V1StGXR8Z5jdHi6BmyT0sC1pQ2rN4wLk",
"url": "https://cdn.mynth.io/images/img_V1StGXR8Z5jdHi6BmyT0sC1pQ2rN4wLk.webp"
},
{
"status": "failed",
"error": {
"code": "RESTRICTED_CONTENT",
"message": "The request was blocked by content moderation."
}
}
]
}
}video.generate works the same way under result.videos. A provider refusal
(RESTRICTED_CONTENT) or a model with no capacity (PROVIDERS_BUSY) fails the
item, not the task, so a completed generation task can hold no usable output
at all.
Always check the task status, then every item. Only failed items are free: you pay for the images that succeeded.
The other task types (image.remove_background, image.rate, image.alt,
image.review) have no items. When their work fails, the task is failed.
In the SDK, urls and getImages() skip failed images without saying so. If a partial result is
not acceptable, compare getImages().length with the count you sent.
Collecting the result#
Pick one of three:
| Approach | Use it when |
|---|---|
| Wait in the SDK or CLI | The code can hold a connection: a script, a worker, a job queue |
| Poll | You want control over the loop, or a browser does the waiting |
| Webhook | Nothing can wait: serverless handlers, long video renders |
A destination changes where the file is stored, not how you learn the task finished, so combine it with one of the three.
The SDK polls on a fixed schedule and gives up after 30 minutes for images and
an hour for video. Tasks and polling has the
exact intervals. GET /tasks/{id}/status and GET /tasks/{id}/result are
served from a cache, so point a polling loop at them rather than at
GET /tasks/{id}.
Reading a task#
| Call | Returns |
|---|---|
GET /tasks/{id}/status | status only |
GET /tasks/{id}/result | id, type, status, result |
GET /tasks/{id} | The full record: request, result, errors, cost, and more |
GET /tasks | Recent tasks, newest first, without request or result |
GET /tasks with an API key lists only the tasks that key created. Any key on
your account with the generate scope can read any of your tasks by id.
The task object documents every field.
Retries and timeouts#
Mynth retries before a failure reaches you:
| Work | Attempts | Time budget | Each attempt |
|---|---|---|---|
| One image | 4 | 35 minutes | picks a provider again |
| One video | 3 | 32 minutes | up to 15 minutes |
A failing provider therefore fails over rather than failing the image.
RESTRICTED_CONTENT, INVALID_PROMPT, INVALID_INPUT, and
CAPABILITY_NOT_SUPPORTED are not retried, because another attempt would fail
the same way. Errors lists every
code and whether retrying helps.
A task still pending 24 hours after its last update is failed with
TASK_EXPIRED by a daily sweep, and its hold is released.
Pricing has the details.
File lifetimes#
| File | Served for |
|---|---|
| A generated image or video | 7 days |
An image uploaded with /image/upload | 1 day |
Mynth hands you a URL because that is the practical way to use the file. The
id in it is long and random, but Mynth is not a file host. To keep a file,
name a destination so Mynth writes it to your
own storage, or copy it when the webhook arrives or polling shows completed.
When copying on a machine with little memory, stream the download into the upload instead of buffering the whole file.
Next steps#
- Poll for results: a polling loop, from a server or a browser.
- Webhooks: get called when the task settles.
- The task object: every field of the record.
- Pricing: the hold, the charge, and
cost.