aisplice

API reference

Async tasks

Image, video, and music jobs share one durable lifecycle: submit once, persist task_id, observe a terminal state, then fetch the result. Build one task runner and select only the endpoint family per model.

#One lifecycle for every async model

  1. 1

    Submit once

    Use a unique Idempotency-Key and save the response immediately.

    POST /v1/{capability}
  2. 2

    Persist task_id

    Store it before the worker acknowledges the job.

    task_id
  3. 3

    Poll or receive webhook

    Compare status case-insensitively and stop at a terminal state.

    GET /{task_id}
  4. 4

    Fetch and persist result

    Call /content after success and store the returned platform URL.

    GET /{task_id}/content

#Endpoint families

CapabilitySubmitPollContent
Image/v1/images/tasks/v1/images/tasks/{task_id}/v1/images/tasks/{task_id}/content
Video/v1/videos/v1/videos/{task_id}/v1/videos/{task_id}/content
Music/v1/music/generations/v1/music/tasks/{task_id}/v1/music/tasks/{task_id}/content

#Status values

One lifecycle, two wire vocabularies. Image, music and 3D tasks report the OpenAI task words; videos and every webhook payload report the OpenAI video words. A status check written for one family silently never matches in the other — this table is the mapping.

LifecycleImage · music · 3DVideo · webhookTerminalMeaning
NOT_STARTprocessingqueuednoAccepted by the gateway, not yet handed to a channel.
SUBMITTEDqueuedqueuednoSent upstream and acknowledged by the vendor.
QUEUEDqueuedqueuednoWaiting in the vendor’s queue.
IN_PROGRESSprocessingin_progressnoRendering. progress carries a percentage string such as "60%".
SUCCESSsucceededcompletedyesFinished. Fetch the result from /content.
FAILUREfailedfailedyesFailed for good. fail_reason explains why; the reserved quota is refunded.
UNKNOWNunknownunknownnoThe vendor stopped reporting a state the gateway can map. Keep polling with a deadline, then reconcile — do not treat it as success or failure.

Match on the terminal set, never on “not running”

Treat succeeded / completed and failed as the only stopping points, and everything else — including a word this table does not list — as still running. New intermediate states can appear; new terminal ones are a breaking change and will not.

UNKNOWN is not a failure

A task can sit in UNKNOWN when the vendor stops reporting a state the gateway can map. Poll it with a deadline and escalate to a human or a reconciliation job — treating it as failure double-charges the retry, treating it as success ships an empty result.

#Safe polling loop

Stop on the terminal words for the family you are polling, keep a wall-clock deadline for everything else, and back off so a stuck task cannot turn into a hot loop.

poll.py
import time, requests

# The two vocabularies. Pick the one that matches the endpoint you poll.
TASK_DONE, TASK_FAILED = {"succeeded"}, {"failed"}      # images / music / 3D
VIDEO_DONE, VIDEO_FAILED = {"completed"}, {"failed"}    # videos + webhooks
DEADLINE_SECONDS = 15 * 60

def wait_for_image_task(task_id, api_key):
    started = time.monotonic()
    delay = 2
    while True:
        response = requests.get(
            f"https://www.aisplice.store/v1/images/tasks/{task_id}",
            headers={"Authorization": f"Bearer {api_key}"},
            timeout=30,
        )
        response.raise_for_status()
        task = response.json()
        status = task.get("status", "")

        if status in TASK_DONE:
            return task
        if status in TASK_FAILED:
            raise RuntimeError((task.get("error") or {}).get("message", "task failed"))

        # queued / processing / unknown all mean "not finished". Wait — but
        # never forever: hand an overdue task to reconciliation.
        if time.monotonic() - started > DEADLINE_SECONDS:
            raise TimeoutError(f"task {task_id} still {status} after the deadline")

        time.sleep(delay)
        delay = min(delay * 1.5, 15)

Resume after restarts

Persist task_id, endpoint family, model, creation time, and your own business identifier. A restarted worker can continue polling without submitting and charging a second task.

#Result retention

Fetch /content only after success. Result files are kept for 3 days after the task finishes; after that /content answers 410 with the code media_expired. Download a copy within 3 days if you need to keep it.

Still stuck?

Send us the request ID or the error message and we will look into it.