# Upload an attachment to an entity

`POST /entities/{entity_uuid}/attachments`

- Base: `POST https://portal.watcheye.com.au/api/v1/entities/{entity_uuid}/attachments`

Upload a file and attach it to the specified entity, for example a trust deed, an ASIC
extract, a signed declaration or a contract. The attachment inherits the entity's program and
account, and is attributed to the calling API key.

Send the request as `multipart/form-data` with the file in the `file` field:

```bash
curl -X POST https://watcheye.globaldata.net.au/api/v1/entities/{entity_uuid}/attachments \
  -H "Authorization: Bearer {api_key}|{api_secret}" \
  -F "file=@Smith Family Trust Deed.pdf" \
  -F "category=Trust Deed" \
  -F "description=Signed copy received from the trustee"
```

## Accepted files

Files can be up to 10 MB. The type is detected from the file contents, and these formats
are accepted: PDF, images (JPEG, PNG, WEBP, GIF, HEIC), Word (DOC, DOCX), Excel (XLS,
XLSX), CSV, plain text, RTF and email (EML, MSG). Any other type is rejected with `400`.

## Duplicates

The response includes a `duplicates` array listing every other attachment on the account with
exactly the same contents (an empty array when there are none). The upload is accepted
either way.

Attachments cannot be added to an archived entity; the request is rejected with `409`.
[Unarchive](/docs/reference/entity.unarchive) the entity first to add an attachment.

## Idempotency

This endpoint accepts the `Idempotency-Key` header so that retries on network failure are
safe. A retry with the same key and the same file returns the original response; the same
key sent with a different file is rejected with `422`. See the
[Idempotency](/docs/guides/watcheye_api/idempotency) section of the API guide for the full
contract.

## Parameters

| Name | In | Type | Description |
|------|----|------|-------------|
| `entity_uuid` | path | string (uuid) | **Required.** The entity UUID |
| `Idempotency-Key` | header | string [max 255 characters] | Optional client-generated key (typically a UUID) that lets you safely retry a write request without risk of duplicate work or duplicate billing. A retry with the same key and body returns the original response verbatim, with the `Idempotent-Replay: true` response header. Honoured on `POST` requests only. See the [Idempotency](/docs/guides/watcheye_api/idempotency) section of the API guide for the full contract. Example: `8c4d3a18-2f63-4f9a-9f3a-9b1f5a7c2d4f` |

## Request body

The file and its details

## Responses

### 201 Attachment uploaded

Content type: `application/json`

| Field | Type | Description |
|-------|------|-------------|
| `data` | object | An attachment: a file attached to an entity, such as a trust deed, an ASIC extract, a signed declaration or a contract. The contents are stored encrypted and are returned by the [download](/docs/reference/attachment.download) endpoint. Deleting an attachment is a soft-delete: subsequent show or list calls for it return `404`. Attachments on an archived entity are archived with it and cannot be changed or deleted. |
| `data.uuid` | string (uuid) | The attachment's UUID Example: `3f2b1c4d-5e6f-4a7b-8c9d-0e1f2a3b4c5d` |
| `data.attachment_number` | string | A short public identifier for the attachment, shown in the portal Example: `EA-3C-9A1-0B7` |
| `data.entity_uuid` | string (uuid) | UUID of the entity the attachment is on |
| `data.program_uuid` | string (uuid) | UUID of the program the entity belongs to |
| `data.filename` | string | The name of the file as uploaded Example: `Smith Family Trust Deed.pdf` |
| `data.category` | string | What the file is. Any text up to 100 characters; `Other` when none is given. A category that matches an existing one on the account (ignoring case and extra spaces) is stored with the existing spelling, so `trust deed` is stored as `Trust Deed`. The categories offered in the portal are: Trust Deed, Company Constitution, Partnership Agreement, ASIC Extract, Companies House Extract, Identity Document, Proof of Address, Statutory Declaration, Declaration, Contract / Agreement, Correspondence, Financial Statement and Other. Example: `Trust Deed` |
| `data.description` | string or null | An optional description of the file (max 2000 characters) Example: `Signed copy received from the trustee` |
| `data.mime_type` | string | The type of the file, detected from its contents Example: `application/pdf` |
| `data.format` | string | A readable name for the type of file Enum: `PDF`, `Image`, `Word`, `Excel`, `CSV`, `Text`, `RTF`, `Email`, `Other` Example: `PDF` |
| `data.size_bytes` | integer | The size of the file in bytes Example: `248113` |
| `data.sha256` | string | SHA-256 hash of the file contents, as lowercase hex. Files with the same hash have identical contents. Example: `9f86d081884c7d659a2feaa0c55ad015a3bf4f1b2b0b822cd15d6c15b0f00a08` |
| `data.created_by` | object or null | Identifies who uploaded the file. The `type` discriminator picks the shape of the remaining fields: * `{ type: "user", uuid, username }` - a portal user uploaded the file. * `{ type: "api_key", uuid, label }` - an API key on this account uploaded the file. * `null` - the user or API key that uploaded the file is no longer available. |
| `data.created_by.type` | string | Discriminator for the actor type. Enum: `user`, `api_key` |
| `data.created_by.uuid` | string (uuid) | UUID of the user or API key that uploaded the file. |
| `data.created_by.username` | string | Username of the portal user. Present only when `type` is `user`. |
| `data.created_by.label` | string | Label of the API key. Present only when `type` is `api_key`. |
| `data.archived_at` | string (date-time) or null | ISO 8601 timestamp at which the attachment was archived with its entity (null if not archived) |
| `data.created_at` | string (date-time) | Example: `2025-01-01T00:00:00Z` |
| `data.updated_at` | string (date-time) | Example: `2025-01-01T00:00:00Z` |
| `duplicates` | array of objects | Other attachments on this account with exactly the same contents |
| `duplicates[].attachment_uuid` | string (uuid) | UUID of the matching attachment |
| `duplicates[].attachment_number` | string | Public identifier of the matching attachment Example: `EA-7D-21B-4C0` |
| `duplicates[].entity_uuid` | string (uuid) | UUID of the entity the matching attachment is on |
| `api_reference` | string (uuid) |  |

**Sample response**

```json
{
    "data": {
        "uuid": "3f2b1c4d-5e6f-4a7b-8c9d-0e1f2a3b4c5d",
        "attachment_number": "EA-3C-9A1-0B7",
        "entity_uuid": "00000000-0000-0000-0000-000000000000",
        "program_uuid": "00000000-0000-0000-0000-000000000000",
        "filename": "Smith Family Trust Deed.pdf",
        "category": "Trust Deed",
        "description": "Signed copy received from the trustee",
        "mime_type": "application/pdf",
        "format": "PDF",
        "size_bytes": 248113,
        "sha256": "9f86d081884c7d659a2feaa0c55ad015a3bf4f1b2b0b822cd15d6c15b0f00a08",
        "created_by": {
            "type": "user",
            "uuid": "00000000-0000-0000-0000-000000000000",
            "username": "string",
            "label": "string"
        },
        "archived_at": "2024-01-01T00:00:00Z",
        "created_at": "2025-01-01T00:00:00Z",
        "updated_at": "2025-01-01T00:00:00Z"
    },
    "duplicates": [
        {
            "attachment_uuid": "00000000-0000-0000-0000-000000000000",
            "attachment_number": "EA-7D-21B-4C0",
            "entity_uuid": "00000000-0000-0000-0000-000000000000"
        }
    ],
    "api_reference": "00000000-0000-0000-0000-000000000000"
}
```

### 409 Conflict - either the entity is archived, or a request with this Idempotency-Key is currently being processed

Content type: `application/json`

| Field | Type | Description |
|-------|------|-------------|
| `message` | string | Example: `Attachments cannot be added to an archived entity` |

**Sample response**

```json
{
    "message": "Attachments cannot be added to an archived entity"
}
```

### 422 Idempotency-Key was reused with a different request body

Content type: `application/json`

| Field | Type | Description |
|-------|------|-------------|
| `message` | string | Example: `Idempotency-Key was reused with a different request body.` |

**Sample response**

```json
{
    "message": "Idempotency-Key was reused with a different request body."
}
```

Standard error responses: 400, 401, 403, 404, 429, 5XX (see [Common error responses](/docs/reference/general/common-error-responses.md))

