Poll an asset job
Sample request
curl -H "x-api-key: $ABYSSALE_API_KEY" \
https://api.abyssale.com/asset-jobs/$JOB_ID
# {"job_id":"8f0c2a4e-…","status":"COMPLETED","outputs":[{"type":"image","url":"https://…","mime_type":"image/webp"}], …}Example 200 response
{
"job_id": "8f0c2a4e-4869-11f0-96f2-0a00d9eb8f78",
"operation": "images_remove_background",
"status": "PENDING",
"outputs": [
{
"type": "image",
"url": "https://production-banners.s3.eu-west-1.amazonaws.com/tmp_ai/4b1d6e2a-9c3f-4a7e-8b5d-2f6c1a9e7d40/8f0c2a4e-4869-11f0-96f2-0a00d9eb8f78.webp",
"mime_type": "image/webp"
}
],
"credits": {
"generation_credits": 0,
"ai_credits": 3
},
"error": {
"code": "invalid_input_asset",
"message": "The image https://example.com/product.jpg was not found (HTTP 404). Check the URL."
},
"created_at": "2026-09-21T14:13:20Z",
"finalized_at": "2026-09-21T14:13:27Z",
"version": "v2026-11-09"
}Example 401 error response
{
"message": "Unauthorized: missing or invalid API key.",
"id": "unauthorized"
}The status of an asset job started on this API (today: POST /images/remove-background, POST /images/text-to-image, POST /images/upscale) and, once it is COMPLETED, its outputs and what it cost.
Behaviour, limits and caveats
Always 200 — branch on status, not on the HTTP status: PENDING (queued), PROCESSING, then COMPLETED or FAILED, which are final. A failed job is still a 200, with error saying why. Poll every couple of seconds until the status is final; most jobs finish within seconds, but none is bounded, so never rely on a fixed wait.
Visible to the whole workspace: any API key of the workspace can read a job started with another one. A job of another workspace answers 404 asset_job_not_found, exactly like one that does not exist. Jobs started from Abyssale's AI assistant integrations are not listed on this API.
Kept 7 days: a job can be polled for 7 days after it finished (finalized_at), then answers 404 asset_job_not_found. Each outputs[].url is a signed link valid 7 days from the response that carried it: download the file to keep it.
Path parameters
jobId string (uuid) required
The job_id returned when the job was started.
Response 200
The job, whatever its status.
job_id string (uuid) always
Identifier of the job.
operation string always
The action the job runs, named {media}_{tool} after its path (POST /images/upscale → images_upscale): images_remove_background, images_text_to_image, images_upscale. Not a closed list: more actions are added over time, so treat a value you do not know as generic.
status string always
PENDING (queued) → PROCESSING → COMPLETED or FAILED. The last two are final; a job never leaves them. One of "PENDING", "PROCESSING", "COMPLETED", "FAILED".
outputs array of AssetJobOutput always
What the job produced, each output typed — one image for every action today. Always an array: empty until COMPLETED, and on a failed job.
Show child attributes
type string always
What the output is. image today; not a closed list.
url string (uri) always
Link to the file, signed and valid 7 days from the response that carried it. Download the file to keep it. The link only answers GET: a HEAD request on it answers 403.
mime_type string | null always
The file's media type, e.g. image/webp, image/png or image/jpeg. null in the rare case the type could not be read; url is always there.
credits AssetJobCredits always
What the job has spent so far, in every status.
More about credits
What the job has spent so far — the same two balances, under the same names, as GET /credits. 0 until the job completes.
Show child attributes
generation_credits integer always
Generation credits the job has spent so far; final once COMPLETED. 0 when the action doesn't spend them (every action today). Minimum 0.
ai_credits integer always
AI credits the job has spent so far; final once COMPLETED. Minimum 0.
error object | null always
Why the job failed, only when FAILED; null otherwise.
Show child attributes
code string always
Machine-readable reason.
More about code
Machine-readable reason. Not a closed list: treat a code you do not know as generic. For example:
invalid_input_asset— an input image (the image of a background removal, a reference image of a text to image) could not be downloaded or read.invalid_input— the provider refused the request's inputs (for a text to image, typically a prompt it would not generate).insufficient_credits— the AI credit balance ran out before the job ran.
message string always
Plain-language reason, safe to show to an end user.
created_at string (date-time) always
When the job was started (UTC).
finalized_at string (date-time) | null always
When the job reached COMPLETED or FAILED (UTC); null before.
version string
The API version that produced this response, named by release date (vYYYY-MM-DD). Pattern ^v\d{4}-\d{2}-\d{2}$.
More about version
The API version that produced this response, named by release date (vYYYY-MM-DD). Stamped as a top-level field on JSON object bodies, success and error alike, so a client can always tell which contract answered. There is no version-selection parameter — a single version is maintained at a time.
Two kinds of body are not stamped. Array bodies (the listings) carry no envelope. And a body that already has a version key of its own is left alone — which in practice means Banner, whose version is the generated file's integer counter. So GET /banners/{bannerId} and the synchronous generate are the two responses that do not tell you which contract answered.
The value changes when a new version is released. Match the vYYYY-MM-DD shape rather than pinning today's literal, or your client breaks on the next release.
Errors
Every failure uses the shared error envelope — {id, message, errors?}. Branch on id, never on message. See Errors.
| Status | When |
|---|---|
401 | Unauthorized — missing or invalid API key. |
404 | No such job in this workspace (asset_job_not_found) — it does not exist, belongs to another workspace, was not started on this API, or finished more than 7 days ago. A jobId that is not a UUID answers 404 endpoint_not_found instead. |
429 | Too Many Requests. |
500 | Internal Server Error — an unexpected error occurred on our side. |
