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

# Get order result download URLs

> Issue a download URL for every output file of a completed Anti-AI or watermark embed order, plus one URL for all results, in a single call. The response has the same shape whether the watermark order was created with v2 or v3.

- `files[]`: `{ fileId, downloadUrl }` for each output file. It lists the same files in the same order as `result.outputFiles[]` from [`GET /api/v3/orders/{orderId}`](/api-reference/orders/get-order-v3), with the same `fileId` values
- `archiveUrl`: one URL for all results. Always a string
  - Anti-AI orders and watermark embed orders created with v2: a ZIP archive of the results
  - Watermark embed orders created with v3: a ZIP archive with two or more output files. With one output file, the URL of that file (the same file as `files[0].downloadUrl`)
- `expiresInSeconds`: how long the URLs are valid. 3600 seconds (1 hour) by default, shortened to the time left until the retention period ends (`expiresAt`) if that is sooner. Call this endpoint again for fresh URLs

**Error check order** (the first matching error is returned)
1. The order does not exist or belongs to another account → `404 ORDER_NOT_FOUND`
2. Watermark extract or AI Detection order → `400 ORDER_TYPE_CANT_DOWNLOAD`, even after the retention period ends
3. The retention period has ended → `400 ORDER_EXPIRED`. If the retention period cannot be determined → `409 FILE_RETENTION_UNKNOWN`
4. `status` is not `complete` (`pending`, `inProgress`, or `failed`) → `400 ORDER_NOT_COMPLETED`

**Changes from the previous v3 response (breaking change, 2026-10-08)**: the response changed from `{ downloadUrl, expiresInSeconds: 300 }` to `{ archiveUrl, files, expiresInSeconds }`, and Anti-AI orders and v2 watermark embed orders are now supported. URLs are valid for up to 3600 seconds instead of 300. An incomplete order returns `ORDER_NOT_COMPLETED` instead of `VALIDATION_FAILED`, and an extract order returns `ORDER_TYPE_CANT_DOWNLOAD`. The per-file endpoint `GET /api/v3/orders/{orderId}/files/{fileId}/download` was removed; use `files[]` instead.

**Test keys (`sk_test_`)**: works for completed Anti-AI and watermark embed test orders created with the same key, whether with v2 or v3. The URLs point to sample files served from `https://api.bizmori.com/api/v2/test-samples/{signedToken}`, not to your processed files. An Anti-AI test order without output files returns `files: []` and a sample ZIP as `archiveUrl`. A v3 embed test order with one output file returns that sample file as `archiveUrl`; other test orders return a sample ZIP. `expiresInSeconds`, the error codes, and the check order follow the same rules as live orders.


Use this endpoint to download the results of a completed Anti-AI or watermark embed order. One call returns a URL for every output file and one URL for all results. The response has the same shape whether you created the watermark order with v2 or v3.

> [!WARNING]
>
> The response shape changed on October 8, 2026, and `GET /api/v3/orders/{orderId}/files/{fileId}/download` was removed. See [Changes from the previous response](#changes-from-the-previous-response).

## Response fields

| Field | Type | Description |
| - | - | - |
| `archiveUrl` | string | One URL for all results. Always present |
| `files[]` | array | `{ fileId, downloadUrl }` for each output file |
| `expiresInSeconds` | integer | How long the URLs are valid, in seconds. At most 3600 |

`files[]` lists the same files in the same order as `result.outputFiles[]` from [Get order details](https://docs.contentcare.ai/api-reference/orders/get-order-v3.md), with the same `fileId` values. Use `fileId` to match each URL to its output file and its `inputFileId`.

### What `archiveUrl` points to

| Order | `archiveUrl` |
| - | - |
| Anti-AI | ZIP archive of all output files |
| Watermark embed created with v2 | ZIP archive of all output files |
| Watermark embed created with v3, two or more output files | ZIP archive of all output files |
| Watermark embed created with v3, one output file | That output file, the same file as `files[0].downloadUrl` |

You can always hand `archiveUrl` to a single Download button: it is either the only result file or a ZIP of all of them.

### URL lifetime

The URLs are valid for 3600 seconds (1 hour). If the order's retention period ends sooner (`expiresAt`), the lifetime is shortened to the time left, and `expiresInSeconds` reports the shorter value. Don't store the URLs. Call this endpoint again whenever you need to download.

## Examples

```json Anti-AI theme={null}
{
  "data": {
    "archiveUrl": "https://bucket.s3.ap-northeast-2.amazonaws.com/zip/1001/archive.zip?X-Amz-...",
    "files": [
      {
        "fileId": "21",
        "downloadUrl": "https://bucket.s3.ap-northeast-2.amazonaws.com/out/cat.png?X-Amz-..."
      },
      {
        "fileId": "22",
        "downloadUrl": "https://bucket.s3.ap-northeast-2.amazonaws.com/out/dog.png?X-Amz-..."
      }
    ],
    "expiresInSeconds": 3600
  }
}
```

```json Watermark embed (one output) theme={null}
{
  "data": {
    "archiveUrl": "https://bucket.s3.ap-northeast-2.amazonaws.com/out/logo.png?X-Amz-...",
    "files": [
      {
        "fileId": "201",
        "downloadUrl": "https://bucket.s3.ap-northeast-2.amazonaws.com/out/logo.png?X-Amz-..."
      }
    ],
    "expiresInSeconds": 3600
  }
}
```

```json Watermark embed (two outputs) theme={null}
{
  "data": {
    "archiveUrl": "https://bucket.s3.ap-northeast-2.amazonaws.com/archive/2001.zip?X-Amz-...",
    "files": [
      {
        "fileId": "201",
        "downloadUrl": "https://bucket.s3.ap-northeast-2.amazonaws.com/out/logo-1.png?X-Amz-..."
      },
      {
        "fileId": "202",
        "downloadUrl": "https://bucket.s3.ap-northeast-2.amazonaws.com/out/logo-2.png?X-Amz-..."
      }
    ],
    "expiresInSeconds": 3600
  }
}
```

## Download every output file

```javascript Node.js theme={null}
import { writeFile } from 'node:fs/promises';

const headers = { Authorization: 'Bearer YOUR_API_KEY' };
const base = `https://api.bizmori.com/api/v3/orders/${orderId}`;

const { data: order } = await (await fetch(base, { headers })).json();
const { data: download } = await (await fetch(`${base}/download`, { headers })).json();

// files[] and result.outputFiles[] share fileId values and order.
const names = new Map(order.result.outputFiles.map((file) => [file.fileId, file.fileName]));
for (const { fileId, downloadUrl } of download.files) {
  const res = await fetch(downloadUrl);
  await writeFile(`${fileId}-${names.get(fileId)}`, Buffer.from(await res.arrayBuffer()));
}
```

```python Python theme={null}
import requests

headers = {'Authorization': 'Bearer YOUR_API_KEY'}
base = f'https://api.bizmori.com/api/v3/orders/{order_id}'

order = requests.get(base, headers=headers).json()['data']
download = requests.get(f'{base}/download', headers=headers).json()['data']

# files[] and result.outputFiles[] share fileId values and order.
names = {f['fileId']: f['fileName'] for f in order['result']['outputFiles']}
for item in download['files']:
    res = requests.get(item['downloadUrl'])
    with open(f"{item['fileId']}-{names[item['fileId']]}", 'wb') as out:
        out.write(res.content)
```

## Errors

The endpoint checks for errors in this order and returns the first one that applies:

| Order | Condition | HTTP | `code` |
| - | - | - | - |
| 1 | The order does not exist or belongs to another account | 404 | `ORDER_NOT_FOUND` |
| 2 | Watermark extract or AI Detection order, even after the retention period ends | 400 | `ORDER_TYPE_CANT_DOWNLOAD` |
| 3 | The retention period has ended | 400 | `ORDER_EXPIRED` |
| 3 | The retention period cannot be determined | 409 | `FILE_RETENTION_UNKNOWN` |
| 4 | `status` is `pending`, `inProgress`, or `failed` | 400 | `ORDER_NOT_COMPLETED` |

An invalid `orderId` format returns `400 VALIDATION_FAILED`.

## Changes from the previous response

On October 8, 2026, this endpoint switched to the shape above. This is a breaking change.

| Previous behavior | Now |
| - | - |
| Response `{ downloadUrl, expiresInSeconds }` | `{ archiveUrl, files, expiresInSeconds }`. `archiveUrl` replaces `downloadUrl` |
| v3 watermark embed orders only | Anti-AI orders and watermark embed orders created with v2 or v3 |
| URLs valid for 300 seconds | Up to 3600 seconds, capped by the retention period |
| Incomplete order: `400 VALIDATION_FAILED` | `400 ORDER_NOT_COMPLETED` |
| Watermark extract and AI Detection orders: not supported | Still not supported, with a dedicated error: `400 ORDER_TYPE_CANT_DOWNLOAD` |
| `GET /api/v3/orders/{orderId}/files/{fileId}/download` for one output file | Removed. Use `files[]` from this endpoint |

The deprecated [`GET /api/v2/orders/{orderId}/download`](https://docs.contentcare.ai/api-reference/orders/download-order) still returns its previous response, unchanged.

## Test keys

With an `sk_test_` key, this endpoint works for completed Anti-AI and watermark embed test orders created with the same key. The URLs point to fixed sample files, not to your processed files. See [Test API keys](https://docs.contentcare.ai/test-api-keys.md).


## OpenAPI

````yaml api-reference/openapi.yaml GET /api/v3/orders/{orderId}/download
openapi: 3.0.0
info:
  title: BIZ MORI API
  version: 2.0.0
  description: >
    BIZ MORI API provides four core services for digital content protection:

    - **Anti-AI**: Protect images from AI training

    - **Watermark Embed**: Embed invisible digital watermarks into images

    - **Watermark Extract**: Extract and verify watermarks from images

    - **AI Detection**: Detect whether an image is AI-generated

    - **Test API keys**: Keys with the `sk_test_` prefix use the same Bearer
    authentication and support order-lifecycle testing with mock responses
    without running processing services or consuming credits; test uploads
    discard file contents and do not create result files
  contact:
    name: BIZ MORI Support
    email: support@contentcare.ai
  license:
    name: Proprietary
    url: https://docs.contentcare.ai/legal/terms
servers:
  - url: https://api.bizmori.com
    description: Production
security: []
tags:
  - name: Anti-AI
    description: Anti-AI image protection orders
  - name: Watermark Embed
    description: Watermark embedding orders
  - name: Watermark Extract
    description: Watermark extraction orders
  - name: AI Detection
    description: AI-generated image detection orders
  - name: Orders
    description: Order query and management
  - name: Webhooks
    description: Webhook configuration and events
  - name: Reports
    description: PDF analysis reports for watermark extract and AI Detection orders
paths:
  /api/v3/orders/{orderId}/download:
    get:
      tags:
        - Orders
      summary: Get order result download URLs
      description: >
        Issue a download URL for every output file of a completed Anti-AI or
        watermark embed order, plus one URL for all results, in a single call.
        The response has the same shape whether the watermark order was created
        with v2 or v3.


        - `files[]`: `{ fileId, downloadUrl }` for each output file. It lists
        the same files in the same order as `result.outputFiles[]` from [`GET
        /api/v3/orders/{orderId}`](/api-reference/orders/get-order-v3), with the
        same `fileId` values

        - `archiveUrl`: one URL for all results. Always a string
          - Anti-AI orders and watermark embed orders created with v2: a ZIP archive of the results
          - Watermark embed orders created with v3: a ZIP archive with two or more output files. With one output file, the URL of that file (the same file as `files[0].downloadUrl`)
        - `expiresInSeconds`: how long the URLs are valid. 3600 seconds (1 hour)
        by default, shortened to the time left until the retention period ends
        (`expiresAt`) if that is sooner. Call this endpoint again for fresh URLs


        **Error check order** (the first matching error is returned)

        1. The order does not exist or belongs to another account → `404
        ORDER_NOT_FOUND`

        2. Watermark extract or AI Detection order → `400
        ORDER_TYPE_CANT_DOWNLOAD`, even after the retention period ends

        3. The retention period has ended → `400 ORDER_EXPIRED`. If the
        retention period cannot be determined → `409 FILE_RETENTION_UNKNOWN`

        4. `status` is not `complete` (`pending`, `inProgress`, or `failed`) →
        `400 ORDER_NOT_COMPLETED`


        **Changes from the previous v3 response (breaking change, 2026-10-08)**:
        the response changed from `{ downloadUrl, expiresInSeconds: 300 }` to `{
        archiveUrl, files, expiresInSeconds }`, and Anti-AI orders and v2
        watermark embed orders are now supported. URLs are valid for up to 3600
        seconds instead of 300. An incomplete order returns
        `ORDER_NOT_COMPLETED` instead of `VALIDATION_FAILED`, and an extract
        order returns `ORDER_TYPE_CANT_DOWNLOAD`. The per-file endpoint `GET
        /api/v3/orders/{orderId}/files/{fileId}/download` was removed; use
        `files[]` instead.


        **Test keys (`sk_test_`)**: works for completed Anti-AI and watermark
        embed test orders created with the same key, whether with v2 or v3. The
        URLs point to sample files served from
        `https://api.bizmori.com/api/v2/test-samples/{signedToken}`, not to your
        processed files. An Anti-AI test order without output files returns
        `files: []` and a sample ZIP as `archiveUrl`. A v3 embed test order with
        one output file returns that sample file as `archiveUrl`; other test
        orders return a sample ZIP. `expiresInSeconds`, the error codes, and the
        check order follow the same rules as live orders.
      operationId: downloadOrderV3
      parameters:
        - in: path
          name: orderId
          required: true
          schema:
            type: string
            pattern: ^[0-9]{1,20}$
          description: Order ID
      responses:
        '200':
          description: A download URL for each output file and one URL for all results
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/PublicOrderV3DownloadResponse'
              examples:
                antiAi:
                  summary: Anti-AI (2 outputs, `archiveUrl` is a ZIP)
                  value:
                    data:
                      archiveUrl: >-
                        https://bucket.s3.ap-northeast-2.amazonaws.com/zip/1001/archive.zip?X-Amz-...
                      files:
                        - fileId: '21'
                          downloadUrl: >-
                            https://bucket.s3.ap-northeast-2.amazonaws.com/out/cat.png?X-Amz-...
                        - fileId: '22'
                          downloadUrl: >-
                            https://bucket.s3.ap-northeast-2.amazonaws.com/out/dog.png?X-Amz-...
                      expiresInSeconds: 3600
                watermarkEmbedV3Multiple:
                  summary: Watermark embed (v3) (2 outputs, `archiveUrl` is a ZIP)
                  value:
                    data:
                      archiveUrl: >-
                        https://bucket.s3.ap-northeast-2.amazonaws.com/archive/2001.zip?X-Amz-...
                      files:
                        - fileId: '201'
                          downloadUrl: >-
                            https://bucket.s3.ap-northeast-2.amazonaws.com/out/logo-1.png?X-Amz-...
                        - fileId: '202'
                          downloadUrl: >-
                            https://bucket.s3.ap-northeast-2.amazonaws.com/out/logo-2.png?X-Amz-...
                      expiresInSeconds: 3600
                watermarkEmbedV3Single:
                  summary: >-
                    Watermark embed (v3) (1 output, `archiveUrl` is the output
                    file URL)
                  value:
                    data:
                      archiveUrl: >-
                        https://bucket.s3.ap-northeast-2.amazonaws.com/out/logo.png?X-Amz-...
                      files:
                        - fileId: '201'
                          downloadUrl: >-
                            https://bucket.s3.ap-northeast-2.amazonaws.com/out/logo.png?X-Amz-...
                      expiresInSeconds: 3600
                watermarkEmbedV2:
                  summary: >-
                    Watermark embed (v2) (2 outputs; 20 minutes left until
                    `expiresAt`, so the URLs expire sooner)
                  value:
                    data:
                      archiveUrl: >-
                        https://bucket.s3.ap-northeast-2.amazonaws.com/zip/2101.zip?X-Amz-...
                      files:
                        - fileId: '41'
                          downloadUrl: >-
                            https://bucket.s3.ap-northeast-2.amazonaws.com/out/a.png?X-Amz-...
                        - fileId: '42'
                          downloadUrl: >-
                            https://bucket.s3.ap-northeast-2.amazonaws.com/out/b.png?X-Amz-...
                      expiresInSeconds: 1200
        '400':
          description: >-
            Invalid request, an order type that cannot be downloaded, an expired
            order, or an incomplete order
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
              examples:
                validation:
                  summary: Invalid `orderId` format
                  value:
                    code: VALIDATION_FAILED
                typeCantDownload:
                  summary: Watermark extract or AI Detection order
                  value:
                    code: ORDER_TYPE_CANT_DOWNLOAD
                expired:
                  summary: The retention period has ended
                  value:
                    code: ORDER_EXPIRED
                notCompleted:
                  summary: '`pending`, `inProgress`, or `failed` order'
                  value:
                    code: ORDER_NOT_COMPLETED
        '401':
          $ref: '#/components/responses/Unauthorized'
        '404':
          description: The order does not exist or belongs to another account
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
              example:
                code: ORDER_NOT_FOUND
        '409':
          description: The retention period of the order cannot be determined
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
              example:
                code: FILE_RETENTION_UNKNOWN
        '500':
          $ref: '#/components/responses/InternalError'
      security:
        - BearerAuth: []
      x-codeSamples:
        - lang: curl
          label: cURL
          source: >
            curl -X GET https://api.bizmori.com/api/v3/orders/ORDER_ID/download
            \
              -H "Authorization: Bearer YOUR_API_KEY"
        - lang: javascript
          label: JavaScript
          source: >
            const orderId = 'ORDER_ID';

            const response = await
            fetch(`https://api.bizmori.com/api/v3/orders/${orderId}/download`, {
              headers: { 'Authorization': 'Bearer YOUR_API_KEY' }
            });

            const { data } = await response.json();
        - lang: python
          label: Python
          source: |
            import requests

            order_id = 'ORDER_ID'
            response = requests.get(
                f'https://api.bizmori.com/api/v3/orders/{order_id}/download',
                headers={'Authorization': 'Bearer YOUR_API_KEY'}
            )
            data = response.json()['data']
components:
  schemas:
    PublicOrderV3DownloadResponse:
      type: object
      required:
        - data
      additionalProperties: false
      properties:
        data:
          type: object
          required:
            - archiveUrl
            - files
            - expiresInSeconds
          additionalProperties: false
          properties:
            archiveUrl:
              type: string
              format: uri
              description: >-
                One URL for all results. A ZIP archive for Anti-AI orders and v2
                watermark embed orders. For v3 watermark embed orders, a ZIP
                archive with two or more output files, or the URL of the single
                output file (the same file as `files[0].downloadUrl`)
            files:
              type: array
              description: >-
                Download URL for each output file. Lists the same files in the
                same order as `result.outputFiles` in the order detail
              items:
                type: object
                required:
                  - fileId
                  - downloadUrl
                additionalProperties: false
                properties:
                  fileId:
                    type: string
                    pattern: ^[0-9]+$
                    description: >-
                      Same value as `result.outputFiles[].fileId` in the order
                      detail
                  downloadUrl:
                    type: string
                    format: uri
                    description: Presigned download URL of the output file
            expiresInSeconds:
              type: integer
              maximum: 3600
              description: >-
                How long the URLs are valid, in seconds. 3600 by default,
                shortened to the time left until `expiresAt` if that is sooner
              example: 3600
    ErrorResponse:
      type: object
      properties:
        code:
          type: string
          description: Error code
  responses:
    Unauthorized:
      description: Authentication failed
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/ErrorResponse'
          example:
            code: AUTH_NOT_AUTHENTICATED
    InternalError:
      description: Internal server error
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/ErrorResponse'
          example:
            code: SERVER_INTERNAL_ERROR
  securitySchemes:
    BearerAuth:
      type: http
      scheme: bearer
      description: >-
        Bearer API key for external client access. Live keys use the `sk_`
        prefix; test keys use the `sk_test_` prefix and support order-lifecycle
        testing with mock responses without processing or credit usage.

````

This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.