> ## 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.

# Add Task Attachments

> Upload files to a task and record them on its activity log

## Endpoint

```
POST /tasks/{task_id}/attachments
```

## Authentication

This endpoint requires authentication via API key. Include your API key in the `X-API-Key` header:

```bash theme={null}
X-API-Key: ca_your_api_key_here
```

## Path Parameters

| Parameter | Type    | Required | Description                       |
| --------- | ------- | -------- | --------------------------------- |
| `task_id` | integer | Yes      | ID of the task to attach files to |

## Request Body

All fields are optional, but a request that supplies neither `files` nor `attachment_ids` records nothing.

| Field            | Type                      | Required | Description                                                                                                                                                                |
| ---------------- | ------------------------- | -------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `files`          | array                     | No       | Files to upload and attach. Defaults to an empty list. See [File Object](#file-object) below                                                                               |
| `attach_to_task` | boolean                   | No       | When `true`, the files are stored on the task itself as well as recorded on the activity log. When `false` they are recorded on the activity log only. Defaults to `false` |
| `attachment_ids` | array of integers or null | No       | IDs of attachments that already exist on the task. Used when `attach_to_task` is `false` to reference them from the new activity log entry. Defaults to `null`             |
| `reply_to`       | integer or null           | No       | ID of an activity log entry this attachment is a reply to. Defaults to `null`                                                                                              |
| `user_email`     | string or null            | No       | Email of the user to attribute the upload to. Defaults to the API key's owner                                                                                              |

### File Object

| Field            | Type   | Required | Description                                                                                      |
| ---------------- | ------ | -------- | ------------------------------------------------------------------------------------------------ |
| `filename`       | string | Yes      | Filename including its extension (e.g. `"amendment.pdf"`). The extension is read from this value |
| `base64_content` | string | Yes      | Base64-encoded file content                                                                      |

## Request Example

<CodeGroup>
  ```bash cURL theme={null}
  curl -X POST "https://platform.chamelio.ai/tasks/12345/attachments" \
    -H "X-API-Key: ca_your_api_key_here" \
    -H "Content-Type: application/json" \
    -d '{
      "files": [
        {
          "filename": "counterparty-redlines.pdf",
          "base64_content": "JVBERi0xLjQKJeLjz9MK..."
        }
      ],
      "attach_to_task": true
    }'
  ```

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

  task_id = 12345

  with open("counterparty-redlines.pdf", "rb") as f:
      content = base64.b64encode(f.read()).decode()

  url = f"https://platform.chamelio.ai/tasks/{task_id}/attachments"
  headers = {
      "X-API-Key": "ca_your_api_key_here",
      "Content-Type": "application/json"
  }
  payload = {
      "files": [
          {
              "filename": "counterparty-redlines.pdf",
              "base64_content": content
          }
      ],
      "attach_to_task": True
  }

  response = requests.post(url, headers=headers, json=payload)
  print(response.json())
  ```

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

  const response = await fetch(
    `https://platform.chamelio.ai/tasks/${taskId}/attachments`,
    {
      method: 'POST',
      headers: {
        'X-API-Key': 'ca_your_api_key_here',
        'Content-Type': 'application/json'
      },
      body: JSON.stringify({
        files: [
          {
            filename: 'counterparty-redlines.pdf',
            base64_content: 'JVBERi0xLjQKJeLjz9MK...'
          }
        ],
        attach_to_task: true
      })
    }
  );

  const data = await response.json();
  console.log(data);
  ```
</CodeGroup>

## Response

### Success Response

**Status Code:** `200 OK`

```json theme={null}
{
  "attachment_ids": [8821, 8822]
}
```

### Response Fields

| Field            | Type              | Description                                                                  |
| ---------------- | ----------------- | ---------------------------------------------------------------------------- |
| `attachment_ids` | array of integers | IDs of the attachments that were added, in the order the files were supplied |

## Error Responses

### 401 Unauthorized

Returned when authentication fails. See the [authentication errors](/api-reference/api-keys#authentication-errors) section for details.

```json theme={null}
{
  "detail": "Invalid API key"
}
```

### 404 Not Found

Returned when no task exists with the given ID.

```json theme={null}
{
  "detail": "Not found"
}
```

### 422 Unprocessable Entity

Returned when the request body fails validation, for example a file missing its `base64_content`.

```json theme={null}
{
  "detail": [
    {
      "loc": ["body", "files", 0, "base64_content"],
      "msg": "Field required",
      "type": "missing"
    }
  ]
}
```

### 500 Internal Server Error

Returned when the request fails due to a server error.

```json theme={null}
{
  "detail": "Failed to add task attachments"
}
```

## Notes

<Info>
  The upload is attributed to the API key's owner unless you pass `user_email`, in which case it is
  attributed to that user. Use [`POST /v2/tasks/{task_id}/attachments`](/api-reference/endpoint/v2/tasks/attachments)
  if you want the acting user taken from an OAuth token instead.
</Info>

<Info>
  `attach_to_task` controls where the files land. With `false` (the default) they are uploaded and
  referenced from a new activity log entry, leaving the task's own file list untouched. With `true`
  they are additionally stored on the task, so they appear in [List Task Files](/api-reference/endpoint/tasks/list-files).
</Info>

<Tip>
  Pass `reply_to` with the ID of an existing activity log entry to thread the attachment underneath it,
  for example when responding to a counterparty email already recorded on the task. Entry IDs come from
  [Get Activity Logs](/api-reference/endpoint/tasks/activity-logs).
</Tip>

<Tip>
  To reference files already on the task from a new activity log entry without re-uploading them, send
  their `attachment_ids` with `attach_to_task` set to `false`.
</Tip>

## Use Cases

This endpoint is useful for:

* **Email ingestion** - Attach documents received from a counterparty to the task they belong to
* **Supporting documentation** - Add approvals, quotes, or certificates alongside a contract under review
* **Threaded correspondence** - Use `reply_to` to keep an exchange and its attachments together on the activity log
