TokenLab

Core Guides

Async jobs and polling

Create media tasks and wait for the finished result

Many media endpoints return a task instead of a finished file. Save the returned task ID and use poll_url until the status is completed or failed.

Async terminal task snapshots have a lifecycle separate from the 30-day request/response capture window. Generated image, video, or audio HTTP(S) result URLs may have their own 30-day media-copy window; check the response's media_retention fields for each item's current status and expires_at. A pending or failed copy is not guaranteed to remain available. See Data retention.

Fields to save

Create responses can include:

FieldMeaningWhat to do
idTokenLab task IDStore it with your own job record
task_idAnother name for the same task IDTreat it as equivalent to id
statusCurrent task statusKeep checking until it finishes or fails
poll_urlPreferred status URLUse this first when present
modelModel used for the taskStore it with the task record

Use poll_url when it is returned. If your client needs a fixed URL, use /v1/tasks/{id}.

Save the task and check its status

Save id or task_id as soon as the create request succeeds. Store poll_url, model, endpoint, and your own user or job ID with it. For long media jobs, checking every 5–10 seconds is usually enough.

Stop when the status becomes completed or failed. A completed task contains the media result; a failed task contains the error you can show or log. Retrying a failed generation creates a new task and may create a new charge.

{
  "id": "ldtask_aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
  "task_id": "ldtask_aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
  "status": "pending",
  "poll_url": "/v1/tasks/ldtask_aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
  "model": "veo3.1"
}

Polling Example

curl "https://api.tokenlab.sh/v1/tasks/ldtask_aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" \
  -H "Authorization: Bearer sk-your-api-key"

Statuses are pending, processing, completed, and failed. A cancelled task uses failed together with cancelled: true and cancellation_status: "cancelled".

A successful status read returns HTTP 200 even when the task has failed. Use the task's status to decide whether generation succeeded. The error field retains its string or object shape. Failed tasks may also include error_details with status (the business error status), type, code, message, param, and retryable. For example, error_details.status: 400 with param: "size" means the request needs correction; it does not mean the status request itself failed. param is omitted when no specific field is known. When error_details.projection_version is 2, message is the final reason for the failure, usually the upstream service's own explanation, such as a parameter limit or a content policy decision. For a task that ran on an Official route, error_details.upstream also carries the upstream error as reported: message, plus code, param, and source (the upstream service name) when known. Keep branching on code and type; upstream.code values are defined by the upstream service and may change.

Errors that reject the create request before a task is accepted use the normal HTTP error status and structured error object. Repeating the same idempotent create request preserves that rejection. A failed status read does not change the task's terminal state.

Avoid duplicate tasks

Most duplicate generations come from retrying a create request after a timeout.

Where timeout happensSafer behavior
Before your server receives a create responseCheck the request_id; retry only if no task was created
After a create response was storedResume polling the stored task_id
During pollingRetry the status request with backoff
After terminal statusDo not poll again unless the user explicitly refreshes the record

Do not send a second create request just because the browser refreshed or a status poll failed.

Billing records

An async task may reserve its estimated cost when it is accepted. The final amount is recorded after the task finishes or fails. Status responses may include billing_transaction_id and the X-Billing-Transaction-ID header.

Keep these identifiers together:

  • request_id from the create request.
  • task_id / id from the task.
  • billing_transaction_id when present.
  • Your own user ID, project ID, or job ID.

Cancellation

DELETE /v1/tasks/{id} can cancel supported Seedance video tasks while they are still queued, including seedance-1.5-pro, seedance-2.0, and seedance-2.0-fast.

Unsupported tasks return 400 unsupported_task_cancel. A task that is already running or finished returns 409 task_not_cancellable. Cancellation is a request, not a guarantee that work already in progress will stop.

Troubleshooting

SymptomLikely causeWhat to check
404 async_task_not_foundThe task has expired or is no longer availableCheck the saved task_id and poll_url
403 task_not_ownedTask ownership cannot be confirmed for the current workspaceConfirm the workspace or organization associated with the API key
Task never appears to finishClient keeps polling the wrong URL or stopped before terminal statusUse poll_url or /v1/tasks/{id} and inspect the latest status
Final media URL missingTask is not completed, or it finished without a usable fileKeep polling until it finishes, then treat a missing result as failed
User sees duplicatesRetry path created a new task after timeout or refreshDeduplicate by your own job ID and stored task_id
Billing mismatchFinal billing is not recorded yet, or the wrong IDs are being comparedCompare request_id, task_id, and billing_transaction_id

What to send support

Include request_id, task_id, billing_transaction_id when present, endpoint, model, time, and the names of fields you sent. Never send API keys, private media, signed URLs, or full prompts unless support specifically asks for a redacted example.

API Reference

TopicReference
Get Task StatusGet Task Status
Cancel TaskCancel Task
Image GenerationImage Generation
Video GenerationVideo Generation
Music GenerationMusic Generation
3D Generation3D Generation
Billing & PricingBilling & Pricing

Configure task notifications with the Webhook management API, authenticated with an mt-… Management Token. MCP full uses TOKENLAB_MANAGEMENT_TOKEN. Stop polling terminal tasks and on 401/403/404 or non-retryable errors.

On this page