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

# Download Step Document

> Download a document generated by a specific workflow step

## Endpoint

```
GET /v2/tasks/{task_id}/steps/{step_id}/document
```

## Authentication

This endpoint requires an OAuth access token. Send it as a bearer token:

```bash theme={null}
Authorization: Bearer your_access_token
```

**Required scope:** `files:read`

<Info>
  This endpoint hangs off `/tasks` but is gated on `files:read`, not `tasks:read`, because it returns a
  document. A token with only `tasks:read` gets a `403`.
</Info>

## Path Parameters

| Parameter | Type    | Required | Description                             |
| --------- | ------- | -------- | --------------------------------------- |
| `task_id` | integer | Yes      | Unique identifier for the task          |
| `step_id` | string  | Yes      | Unique identifier for the workflow step |

## Request Example

<CodeGroup>
  ```bash cURL theme={null}
  curl -X GET "https://platform.chamelio.ai/v2/tasks/12345/steps/review_step/document" \
    -H "Authorization: Bearer your_access_token"
  ```

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

  task_id = 12345
  step_id = "review_step"

  url = f"https://platform.chamelio.ai/v2/tasks/{task_id}/steps/{step_id}/document"
  headers = {
      "Authorization": "Bearer your_access_token"
  }

  response = requests.get(url, headers=headers)
  data = response.json()

  # Then fetch the presigned URL to get the file itself
  document = requests.get(data["download_url"])
  with open(data["file_name"], "wb") as f:
      f.write(document.content)
  ```

  ```javascript JavaScript theme={null}
  const taskId = 12345;
  const stepId = 'review_step';

  const response = await fetch(
    `https://platform.chamelio.ai/v2/tasks/${taskId}/steps/${stepId}/document`,
    {
      method: 'GET',
      headers: {
        'Authorization': 'Bearer your_access_token'
      }
    }
  );

  const data = await response.json();

  // Then fetch the presigned URL to get the file itself
  const downloadResponse = await fetch(data.download_url);
  if (!downloadResponse.ok) {
    throw new Error('Document download failed');
  }

  const blob = await downloadResponse.blob();
  const objectUrl = URL.createObjectURL(blob);
  const link = document.createElement('a');
  link.href = objectUrl;
  link.download = data.file_name;
  link.click();
  URL.revokeObjectURL(objectUrl);
  ```
</CodeGroup>

## Response

### Success Response

**Status Code:** `200 OK`

The response is JSON metadata containing a presigned URL - not the file bytes.

```json theme={null}
{
  "file_id": "document_790",
  "file_name": "reviewed_contract.pdf",
  "content_type": "pdf",
  "download_url": "https://s3.amazonaws.com/...",
  "expires_at": "2025-01-20T12:00:00Z"
}
```

### Response Fields

| Field          | Type   | Description                                                   |
| -------------- | ------ | ------------------------------------------------------------- |
| `file_id`      | string | Unique file identifier (`document_{id}` or `attachment_{id}`) |
| `file_name`    | string | Name of the document file                                     |
| `content_type` | string | Type of the file                                              |
| `download_url` | string | Presigned URL to download the document                        |
| `expires_at`   | string | ISO 8601 timestamp when the download URL expires              |

## Error Responses

### 400 Bad Request

Returned when the access token has no user behind it.
`client_credentials` tokens act as the admin who created the application, so this applies only to
tokens issued before application creators were recorded.

```json theme={null}
{
  "detail": "client_credentials tokens are not associated with a user"
}
```

### 401 Unauthorized

Returned when the access token is missing, unknown, revoked, or expired, or when an `X-API-Key` was
sent instead of a bearer token. See [OAuth error responses](/api-reference/oauth-apps#error-responses).

```json theme={null}
{
  "detail": "Invalid access token"
}
```

### 403 Forbidden

Returned when the token lacks the required scope:

```json theme={null}
{
  "detail": "Insufficient scope; this endpoint requires: files:read"
}
```

Or when the user may not access this task:

```json theme={null}
{
  "detail": "You do not have access to this resource"
}
```

### 404 Not Found

Returned when the step has no variables, or none of them produced a document.

```json theme={null}
{
  "detail": "No document found for step review_step in task 12345"
}
```

### 429 Too Many Requests

Returned when your organization exceeds its per-minute request limit.

```json theme={null}
{
  "detail": "Rate limit exceeded"
}
```

### 500 Internal Server Error

Returned when the request fails due to a server error.

```json theme={null}
{
  "detail": "Failed to download step document"
}
```

## Notes

<Info>
  This endpoint is specifically for documents generated by workflow steps (like document generation or AI
  review steps). For a file you already have an ID for, use the
  [Download File](/api-reference/endpoint/v2/files/download) endpoint instead.
</Info>

<Warning>
  The presigned download URL expires after a certain time (indicated by `expires_at`). Download the file
  before the URL expires or request a new URL.
</Warning>

<Tip>
  Use the [List Task Files](/api-reference/endpoint/v2/tasks/list-files) endpoint to discover which steps
  have generated documents and their associated `step_id` values.
</Tip>

## Use Cases

This endpoint is useful for:

* **Document retrieval** - Download AI-generated or modified documents from workflows
* **Contract export** - Export reviewed, redlined, or approved contracts
* **Archival** - Save generated documents to external storage systems
* **Distribution** - Share workflow outputs with external stakeholders
