> ## Documentation Index
> Fetch the complete documentation index at: https://docs.sunor.cc/llms.txt
> Use this file to discover all available pages before exploring further.

# Get Task

> Retrieve the status and output of a task

# Get Task

Retrieve the current status, input, and output of a previously created task. If the task is still in progress, sunor will live-poll the upstream provider and return the latest status.

## Request

```
GET /api/v1/task/{taskId}
```

### Path parameters

<ParamField path="taskId" type="string" required>
  The task ID returned from the [Create Task](/api-reference/create-task) endpoint.
</ParamField>

### Headers

<ParamField header="x-api-key" type="string" required>
  Your API key.
</ParamField>

## Response

<ResponseField name="code" type="number">
  HTTP status code (`200` on success).
</ResponseField>

<ResponseField name="data" type="object">
  <ResponseField name="task_id" type="string">
    The unique task identifier.
  </ResponseField>

  <ResponseField name="model" type="string">
    The model used (e.g., `"suno"`).
  </ResponseField>

  <ResponseField name="type" type="string">
    The task type (`"music"`, `"lyrics"`, `"upload"`, or `"concat"`).
  </ResponseField>

  <ResponseField name="status" type="string">
    Current task status. One of: `"pending"`, `"running"`, `"success"`, `"failure"`, `"timeout"`.
  </ResponseField>

  <ResponseField name="credits_cost" type="number">
    Credits charged (or frozen) for this task.
  </ResponseField>

  <ResponseField name="input" type="object">
    The original input parameters submitted with the task.
  </ResponseField>

  <ResponseField name="audio_format" type="string | null">
    The delivery format this task was created with. Currently always `null` — conversion is not
    enabled — so `audio_url` points at the provider's own file.
  </ResponseField>

  <ResponseField name="output" type="object | null">
    The task output. `null` while the task is still processing. Contains model-specific results on completion.
  </ResponseField>

  <ResponseField name="error" type="string | null">
    Error message if the task failed. `null` otherwise.
  </ResponseField>

  <ResponseField name="created_at" type="string">
    ISO 8601 timestamp of task creation.
  </ResponseField>

  <ResponseField name="completed_at" type="string | null">
    ISO 8601 timestamp of task completion. `null` if not yet completed.
  </ResponseField>
</ResponseField>

### Status values

| Status    | Description                                                            |
| --------- | ---------------------------------------------------------------------- |
| `pending` | Task has been submitted and is waiting to be processed                 |
| `running` | Task is actively being processed by the upstream provider              |
| `success` | Task completed successfully. Output is available                       |
| `failure` | Task failed. Check the `error` field for details. Credits are refunded |
| `timeout` | Task timed out. Credits are refunded                                   |

## Audio URL lifetime

<Warning>
  **`audio_url` is valid for 7 days after the task completes.** After that it
  returns `404` permanently. If you need the audio for longer, download and
  store it yourself.
</Warning>

Cover art (`image_url`, `image_large_url`) is served by the model provider and
is not covered by this window.

## Contract

The fields listed on this page are the response contract, and they hold across
provider changes: every one of them has been present on every clip we have
returned.

`output.result` also carries additional fields from the upstream model provider.
Those are passed through as-is. They are not part of the contract, they differ
between providers, and they may appear or disappear without notice — build
against the documented fields.

## Audio format

`audio_url` points at the file exactly as the provider produced it. **That format is not fixed, and
it has changed more than once.** As of 2026-09-06 it is MP3, served with a `.mp3` extension. Between
2026-08-29 and 2026-09-05 it was Opus in an MP4 container, served with an `.m4a` extension.

Two things follow, and both are worth building around rather than checking once:

* **Read the format from the response's `Content-Type`.** Not from the URL's extension, and not from
  what the provider was serving the last time you looked. An `.m4a` extension in particular does not
  imply AAC.
* **Do not assume every container decodes on every platform.** Apple's CoreAudio — the API every iOS
  and macOS app sits on — cannot decode Opus in an MP4 container at all. If you target Apple
  platforms, branch on `Content-Type` and convert on your side when you receive something it cannot
  read.

## Output format

The `output` field structure depends on the task type. All outputs share a common wrapper:

<ResponseField name="output.task_type" type="string">
  The task type (`"music"`, `"lyrics"`, `"upload"`, or `"concat"`).
</ResponseField>

<ResponseField name="output.status" type="string">
  Internal processing status: `"queued"`, `"processing"`, `"completed"`, or `"failed"`.
</ResponseField>

<ResponseField name="output.progress" type="string | null">
  Processing progress (e.g., `"50%"`, `"100%"`).
</ResponseField>

<ResponseField name="output.fail_reason" type="string | null">
  Reason for failure, if any.
</ResponseField>

<ResponseField name="output.result" type="array | object | null">
  The task-specific result. Shape varies by task type (see below).
</ResponseField>

### Output by task type

<Tabs>
  <Tab title="Music">
    `result` is an **array of clip objects**. Each music generation typically returns one or more clip variations.

    | Field       | Type     | Description                                                                                                                                                   |
    | ----------- | -------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------- |
    | `id`        | `string` | Unique clip identifier. Use this for continuation or concat tasks                                                                                             |
    | `audio_url` | `string` | URL to the generated audio file. Derive the format from the response's `Content-Type` rather than assuming one. See [Audio URL lifetime](#audio-url-lifetime) |
    | `image_url` | `string` | URL to the generated cover art                                                                                                                                |
    | `title`     | `string` | Generated or provided song title                                                                                                                              |
    | `metadata`  | `object` | Additional info: `duration` (seconds), `tags`, `prompt`, etc.                                                                                                 |

    ```json theme={null}
    "output": {
      "task_type": "music",
      "status": "completed",
      "progress": "100%",
      "fail_reason": null,
      "result": [
        {
          "id": "clip-id-1",
          "audio_url": "https://audio.sunor.cc/audio/6fdfdf84-43d5-4a63-90c4-340e678739b2/810509c7d9873364.mp3",
          "image_url": "https://cdn2.suno.ai/image_clip-id-1.jpeg",
          "title": "Summer Days",
          "metadata": {
            "duration": 120,
            "tags": "acoustic, cheerful, summer"
          }
        },
        {
          "id": "clip-id-2",
          "audio_url": "https://audio.sunor.cc/audio/6fdfdf84-43d5-4a63-90c4-340e678739b2/72683fa7bd9b4723.mp3",
          "image_url": "https://cdn2.suno.ai/image_clip-id-2.jpeg",
          "title": "Summer Days",
          "metadata": {
            "duration": 118,
            "tags": "acoustic, cheerful, summer"
          }
        }
      ]
    }
    ```
  </Tab>

  <Tab title="Lyrics">
    `result` is an **object** containing the generated lyrics and title.

    | Field   | Type     | Description                                                        |
    | ------- | -------- | ------------------------------------------------------------------ |
    | `title` | `string` | Generated song title                                               |
    | `text`  | `string` | Generated lyrics with structure tags (`[Verse]`, `[Chorus]`, etc.) |

    ```json theme={null}
    "output": {
      "task_type": "lyrics",
      "status": "completed",
      "progress": "100%",
      "fail_reason": null,
      "result": {
        "title": "Ocean Sunset",
        "text": "[Verse]\nWaves are crashing on the shore\nGolden light I can't ignore\n\n[Chorus]\nAt the edge of the sea\nYou and me, finally free"
      }
    }
    ```
  </Tab>

  <Tab title="Upload">
    `result` is an **array** containing the uploaded clip information.

    | Field       | Type     | Description                                                              |
    | ----------- | -------- | ------------------------------------------------------------------------ |
    | `id`        | `string` | Clip ID for the uploaded audio. Use this in other tasks                  |
    | `audio_url` | `string` | URL to the uploaded audio. See [Audio URL lifetime](#audio-url-lifetime) |

    ```json theme={null}
    "output": {
      "task_type": "upload",
      "status": "completed",
      "progress": "100%",
      "fail_reason": null,
      "result": [
        {
          "id": "uploaded-clip-id",
          "audio_url": "https://audio.sunor.cc/audio/6fdfdf84-43d5-4a63-90c4-340e678739b2/a256638015d2e5f4.mp3"
        }
      ]
    }
    ```
  </Tab>

  <Tab title="Concat">
    `result` is an **array** containing the concatenated clip.

    | Field       | Type     | Description                                                                       |
    | ----------- | -------- | --------------------------------------------------------------------------------- |
    | `id`        | `string` | Clip ID for the concatenated audio                                                |
    | `audio_url` | `string` | URL to the concatenated audio file. See [Audio URL lifetime](#audio-url-lifetime) |

    ```json theme={null}
    "output": {
      "task_type": "concat",
      "status": "completed",
      "progress": "100%",
      "fail_reason": null,
      "result": [
        {
          "id": "concat-clip-id",
          "audio_url": "https://audio.sunor.cc/audio/6fdfdf84-43d5-4a63-90c4-340e678739b2/b5cdf870fc295ff7.mp3"
        }
      ]
    }
    ```
  </Tab>
</Tabs>

***

## Example responses

### Task in progress

```json 200 theme={null}
{
  "code": 200,
  "data": {
    "task_id": "f47ac10b-58cc-4372-a567-0e02b2c3d479",
    "model": "suno",
    "type": "music",
    "status": "running",
    "credits_cost": 10,
    "input": {
      "gpt_description_prompt": "A cheerful acoustic guitar song about summer",
      "make_instrumental": false
    },
    "output": {
      "task_type": "music",
      "status": "processing",
      "progress": "50%",
      "fail_reason": null,
      "result": null
    },
    "error": null,
    "created_at": "2025-01-15T10:30:00.000Z",
    "completed_at": null
  }
}
```

### Task completed (music)

```json 200 theme={null}
{
  "code": 200,
  "data": {
    "task_id": "f47ac10b-58cc-4372-a567-0e02b2c3d479",
    "model": "suno",
    "type": "music",
    "status": "success",
    "credits_cost": 10,
    "input": {
      "gpt_description_prompt": "A cheerful acoustic guitar song about summer",
      "make_instrumental": false
    },
    "output": {
      "task_type": "music",
      "status": "completed",
      "progress": "100%",
      "fail_reason": null,
      "result": [
        {
          "id": "clip-id-1",
          "audio_url": "https://audio.sunor.cc/audio/6fdfdf84-43d5-4a63-90c4-340e678739b2/810509c7d9873364.mp3",
          "image_url": "https://cdn2.suno.ai/image_clip-id-1.jpeg",
          "title": "Summer Days",
          "metadata": {
            "duration": 120,
            "tags": "acoustic, cheerful, summer"
          }
        }
      ]
    },
    "error": null,
    "created_at": "2025-01-15T10:30:00.000Z",
    "completed_at": "2025-01-15T10:32:15.000Z"
  }
}
```

### Task failed

```json 200 theme={null}
{
  "code": 200,
  "data": {
    "task_id": "f47ac10b-58cc-4372-a567-0e02b2c3d479",
    "model": "suno",
    "type": "music",
    "status": "failure",
    "credits_cost": 10,
    "input": {
      "gpt_description_prompt": "A cheerful acoustic guitar song about summer"
    },
    "output": {
      "task_type": "music",
      "status": "failed",
      "progress": null,
      "fail_reason": "Upstream provider returned an error",
      "result": null
    },
    "error": "Upstream provider returned an error",
    "created_at": "2025-01-15T10:30:00.000Z",
    "completed_at": "2025-01-15T10:30:45.000Z"
  }
}
```

## Polling strategy

Tasks typically take **30 seconds to 5 minutes** to complete, depending on the task type and upstream provider load.

<Tip>
  Poll the Get Task endpoint every **5-10 seconds** until the status is `"success"`, `"failure"`, or `"timeout"`. Avoid polling more frequently than once per second.
</Tip>

### Polling example

<CodeGroup>
  ```python Python theme={null}
  import time
  import requests

  API_KEY = "YOUR_API_KEY"
  TASK_ID = "f47ac10b-58cc-4372-a567-0e02b2c3d479"

  while True:
      response = requests.get(
          f"https://sunor.cc/api/v1/task/{TASK_ID}",
          headers={"x-api-key": API_KEY},
      )
      data = response.json()["data"]
      status = data["status"]
      print(f"Status: {status}")

      if status in ("success", "failure", "timeout"):
          print("Result:", data["output"])
          break

      time.sleep(5)
  ```

  ```javascript Node.js theme={null}
  const API_KEY = "YOUR_API_KEY";
  const TASK_ID = "f47ac10b-58cc-4372-a567-0e02b2c3d479";

  async function pollTask() {
    while (true) {
      const response = await fetch(
        `https://sunor.cc/api/v1/task/${TASK_ID}`,
        { headers: { "x-api-key": API_KEY } }
      );
      const { data } = await response.json();
      console.log("Status:", data.status);

      if (["success", "failure", "timeout"].includes(data.status)) {
        console.log("Result:", data.output);
        break;
      }

      await new Promise((r) => setTimeout(r, 5000));
    }
  }

  pollTask();
  ```
</CodeGroup>

## Errors

| Status | Description                                                 |
| ------ | ----------------------------------------------------------- |
| `401`  | Missing or invalid API key                                  |
| `404`  | Task not found (invalid ID or task belongs to another user) |
| `429`  | Rate limit exceeded                                         |
| `500`  | Internal server error                                       |
