# Attachments

## Pre-upload a file

**post** `/v3/attachments`

**This endpoint is optional.** You can send media by simply providing a URL in your
message's media part — no pre-upload required. Use this endpoint only when you want
to upload a file ahead of time for reuse or latency optimization.

Returns a presigned upload URL and a permanent `attachment_id` you can reference
in future messages.

## Step 1: Request an upload URL

Call this endpoint with file metadata:

```json
POST /v3/attachments
{
  "filename": "photo.jpg",
  "content_type": "image/jpeg",
  "size_bytes": 1024000
}
```

The response includes an `upload_url` (valid for 15 minutes) and a permanent `attachment_id`.

## Step 2: Upload the file

Make a PUT request to the `upload_url` with the raw file bytes as the request body.
You **must** include all headers from `required_headers` exactly as returned — the presigned URL
is signed with these values and S3 will reject the upload if they don't match.

The request body is the binary file content — **not** JSON, **not** multipart form data.
The file must equal `size_bytes` bytes (the value you declared in step 1).

```bash
curl -X PUT "<upload_url from step 1>" \
  -H "Content-Type: image/jpeg" \
  -H "Content-Length: 1024000" \
  --data-binary @photo.jpg
```

## Step 3: Send a message with the attachment

Reference the `attachment_id` in a media part. The ID never expires — use it in as many messages as you want.

```json
POST /v3/chats
{
  "from": "+15559876543",
  "to": ["+15551234567"],
  "message": {
    "parts": [
      { "type": "media", "attachment_id": "<attachment_id from step 1>" }
    ]
  }
}
```

## When to use this instead of a URL in the media part

- Sending the same file to multiple recipients (avoids re-downloading each time)
- Large files where you want to separate upload from message send
- Latency-sensitive sends where the file should already be stored

If you just need to send a file once, skip all of this and pass a `url` directly in the media part instead.

**File Size Limit:** 100MB

**Unsupported Types:** WebP, SVG, FLAC, OGG, and executable files are explicitly rejected.

### Body Parameters

- `content_type: SupportedContentType`

  Supported MIME types for file attachments and media URLs.

  **Images:** image/jpeg, image/png, image/gif, image/heic, image/heif, image/tiff, image/bmp, image/svg+xml, image/webp, image/x-icon

  **Videos:** video/mp4, video/quicktime, video/mpeg, video/mpeg2, video/x-msvideo, video/3gpp

  **Audio:** audio/mpeg, audio/x-m4a, audio/x-caf, audio/x-wav, audio/x-aiff, audio/aac, audio/midi, audio/amr

  **Documents:** application/pdf, text/plain, text/markdown, text/vcard, text/rtf, text/csv, text/html, text/calendar, text/xml, application/json, application/msword, application/vnd.openxmlformats-officedocument.wordprocessingml.document, application/vnd.ms-excel, application/vnd.openxmlformats-officedocument.spreadsheetml.sheet, application/vnd.ms-powerpoint, application/vnd.openxmlformats-officedocument.presentationml.presentation, application/x-iwork-pages-sffpages, application/x-iwork-numbers-sffnumbers, application/x-iwork-keynote-sffkey, application/epub+zip, application/zip, application/x-gzip

  **Transcoded on delivery:**

  - `audio/x-caf` — CAF files are transcoded to `audio/mp4` for delivery.

  **Deprecated (accepted but transcoded):**

  - `audio/mp3` — Deprecated. Use `audio/mpeg` instead. Files sent as audio/mp3 will be delivered as audio/mpeg.
  - `audio/mp4` — Deprecated. Use `audio/x-m4a` instead. Files sent as audio/mp4 will be delivered as audio/x-m4a.
  - `audio/aiff` — Deprecated. Use `audio/x-aiff` instead. Files sent as audio/aiff will be delivered as audio/x-aiff.
  - `image/tiff` — Accepted, but TIFF images are transcoded to JPEG for delivery.

  **Unsupported:** FLAC, OGG, and executable files are explicitly rejected.

  - `"image/jpeg"`

  - `"image/png"`

  - `"image/gif"`

  - `"image/heic"`

  - `"image/heif"`

  - `"image/tiff"`

  - `"image/bmp"`

  - `"image/svg+xml"`

  - `"image/webp"`

  - `"image/x-icon"`

  - `"video/mp4"`

  - `"video/quicktime"`

  - `"video/mpeg"`

  - `"video/mpeg2"`

  - `"video/x-m4v"`

  - `"video/x-msvideo"`

  - `"video/3gpp"`

  - `"audio/mpeg"`

  - `"audio/mp3"`

  - `"audio/x-m4a"`

  - `"audio/mp4"`

  - `"audio/x-caf"`

  - `"audio/x-wav"`

  - `"audio/x-aiff"`

  - `"audio/aiff"`

  - `"audio/aac"`

  - `"audio/midi"`

  - `"audio/amr"`

  - `"application/pdf"`

  - `"text/plain"`

  - `"text/markdown"`

  - `"text/vcard"`

  - `"text/rtf"`

  - `"text/csv"`

  - `"text/html"`

  - `"text/calendar"`

  - `"application/msword"`

  - `"application/vnd.openxmlformats-officedocument.wordprocessingml.document"`

  - `"application/vnd.ms-excel"`

  - `"application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"`

  - `"application/vnd.ms-powerpoint"`

  - `"application/vnd.openxmlformats-officedocument.presentationml.presentation"`

  - `"application/x-iwork-pages-sffpages"`

  - `"application/x-iwork-numbers-sffnumbers"`

  - `"application/x-iwork-keynote-sffkey"`

  - `"application/epub+zip"`

  - `"text/xml"`

  - `"application/json"`

  - `"application/zip"`

  - `"application/x-gzip"`

- `filename: string`

  Name of the file to upload

- `size_bytes: number`

  Size of the file in bytes (max 100MB)

### Returns

- `attachment_id: string`

  Unique identifier for the attachment

- `download_url: string`

  Permanent CDN URL for the file. Does not expire. Use the `attachment_id`
  to reference this file in media parts when sending messages.

- `expires_at: string`

  When the upload URL expires (15 minutes from now)

- `http_method: "PUT"`

  HTTP method to use for upload (always PUT)

  - `"PUT"`

- `required_headers: map[string]`

  HTTP headers that must be set on the upload request. The presigned URL is signed
  with these exact values — S3 will reject the upload if they don't match.

- `upload_url: string`

  Presigned URL for uploading the file. PUT the raw binary file content to this URL
  with the `required_headers`. Do not JSON-encode or multipart-wrap the body.
  Expires after 15 minutes.

### Example

```http
curl https://api.linqapp.com/api/partner/v3/attachments \
    -H 'Content-Type: application/json' \
    -H "Authorization: Bearer $LINQ_API_V3_API_KEY" \
    -d '{
          "content_type": "image/jpeg",
          "filename": "photo.jpg",
          "size_bytes": 1024000
        }'
```

#### Response

```json
{
  "attachment_id": "550e8400-e29b-41d4-a716-446655440000",
  "upload_url": "https://uploads.linqapp.com/attachments/550e8400?X-Amz-Algorithm=AWS4-HMAC-SHA256&...",
  "download_url": "https://cdn.linqapp.com/uploads/partner-id/550e8400/photo.jpg",
  "http_method": "PUT",
  "expires_at": "2024-01-15T10:45:00Z",
  "required_headers": {
    "Content-Type": "image/jpeg",
    "Content-Length": "1024000"
  }
}
```

## Get attachment metadata

**get** `/v3/attachments/{attachmentId}`

Retrieve metadata for a specific attachment including file
information, and URLs for downloading.

`status`: (**deprecated** — will be removed in a future API version)

### Path Parameters

- `attachmentId: string`

### Returns

- `id: string`

  Unique identifier for the attachment (UUID)

- `content_type: SupportedContentType`

  Supported MIME types for file attachments and media URLs.

  **Images:** image/jpeg, image/png, image/gif, image/heic, image/heif, image/tiff, image/bmp, image/svg+xml, image/webp, image/x-icon

  **Videos:** video/mp4, video/quicktime, video/mpeg, video/mpeg2, video/x-msvideo, video/3gpp

  **Audio:** audio/mpeg, audio/x-m4a, audio/x-caf, audio/x-wav, audio/x-aiff, audio/aac, audio/midi, audio/amr

  **Documents:** application/pdf, text/plain, text/markdown, text/vcard, text/rtf, text/csv, text/html, text/calendar, text/xml, application/json, application/msword, application/vnd.openxmlformats-officedocument.wordprocessingml.document, application/vnd.ms-excel, application/vnd.openxmlformats-officedocument.spreadsheetml.sheet, application/vnd.ms-powerpoint, application/vnd.openxmlformats-officedocument.presentationml.presentation, application/x-iwork-pages-sffpages, application/x-iwork-numbers-sffnumbers, application/x-iwork-keynote-sffkey, application/epub+zip, application/zip, application/x-gzip

  **Transcoded on delivery:**

  - `audio/x-caf` — CAF files are transcoded to `audio/mp4` for delivery.

  **Deprecated (accepted but transcoded):**

  - `audio/mp3` — Deprecated. Use `audio/mpeg` instead. Files sent as audio/mp3 will be delivered as audio/mpeg.
  - `audio/mp4` — Deprecated. Use `audio/x-m4a` instead. Files sent as audio/mp4 will be delivered as audio/x-m4a.
  - `audio/aiff` — Deprecated. Use `audio/x-aiff` instead. Files sent as audio/aiff will be delivered as audio/x-aiff.
  - `image/tiff` — Accepted, but TIFF images are transcoded to JPEG for delivery.

  **Unsupported:** FLAC, OGG, and executable files are explicitly rejected.

  - `"image/jpeg"`

  - `"image/png"`

  - `"image/gif"`

  - `"image/heic"`

  - `"image/heif"`

  - `"image/tiff"`

  - `"image/bmp"`

  - `"image/svg+xml"`

  - `"image/webp"`

  - `"image/x-icon"`

  - `"video/mp4"`

  - `"video/quicktime"`

  - `"video/mpeg"`

  - `"video/mpeg2"`

  - `"video/x-m4v"`

  - `"video/x-msvideo"`

  - `"video/3gpp"`

  - `"audio/mpeg"`

  - `"audio/mp3"`

  - `"audio/x-m4a"`

  - `"audio/mp4"`

  - `"audio/x-caf"`

  - `"audio/x-wav"`

  - `"audio/x-aiff"`

  - `"audio/aiff"`

  - `"audio/aac"`

  - `"audio/midi"`

  - `"audio/amr"`

  - `"application/pdf"`

  - `"text/plain"`

  - `"text/markdown"`

  - `"text/vcard"`

  - `"text/rtf"`

  - `"text/csv"`

  - `"text/html"`

  - `"text/calendar"`

  - `"application/msword"`

  - `"application/vnd.openxmlformats-officedocument.wordprocessingml.document"`

  - `"application/vnd.ms-excel"`

  - `"application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"`

  - `"application/vnd.ms-powerpoint"`

  - `"application/vnd.openxmlformats-officedocument.presentationml.presentation"`

  - `"application/x-iwork-pages-sffpages"`

  - `"application/x-iwork-numbers-sffnumbers"`

  - `"application/x-iwork-keynote-sffkey"`

  - `"application/epub+zip"`

  - `"text/xml"`

  - `"application/json"`

  - `"application/zip"`

  - `"application/x-gzip"`

- `created_at: string`

  When the attachment was created

- `filename: string`

  Original filename of the attachment

- `size_bytes: number`

  Size of the attachment in bytes

- `status: "pending" or "complete" or "failed"`

  **DEPRECATED:** This field is deprecated and will be removed in a future API version.

  - `"pending"`

  - `"complete"`

  - `"failed"`

- `download_url: optional string`

  URL to download the attachment

### Example

```http
curl https://api.linqapp.com/api/partner/v3/attachments/$ATTACHMENT_ID \
    -H "Authorization: Bearer $LINQ_API_V3_API_KEY"
```

#### Response

```json
{
  "id": "550e8400-e29b-41d4-a716-446655440000",
  "filename": "photo.jpg",
  "content_type": "image/jpeg",
  "size_bytes": 1024000,
  "status": "complete",
  "download_url": "https://cdn.linqapp.com/attachments/550e8400-e29b-41d4-a716-446655440000/photo.jpg",
  "created_at": "2024-01-15T10:30:00Z"
}
```

## Delete an attachment

**delete** `/v3/attachments/{attachmentId}`

Permanently delete an attachment owned by the authenticated partner.

### Path Parameters

- `attachmentId: string`

### Example

```http
curl https://api.linqapp.com/api/partner/v3/attachments/$ATTACHMENT_ID \
    -X DELETE \
    -H "Authorization: Bearer $LINQ_API_V3_API_KEY"
```

#### Response

```json
{
  "error": {
    "status": 401,
    "code": 2004,
    "message": "Unauthorized - missing or invalid authentication token",
    "doc_url": "https://docs.linqapp.com/error/codes/2xxx/2004/"
  },
  "success": false
}
```

## Domain Types

### Supported Content Type

- `SupportedContentType = "image/jpeg" or "image/png" or "image/gif" or 47 more`

  Supported MIME types for file attachments and media URLs.

  **Images:** image/jpeg, image/png, image/gif, image/heic, image/heif, image/tiff, image/bmp, image/svg+xml, image/webp, image/x-icon

  **Videos:** video/mp4, video/quicktime, video/mpeg, video/mpeg2, video/x-msvideo, video/3gpp

  **Audio:** audio/mpeg, audio/x-m4a, audio/x-caf, audio/x-wav, audio/x-aiff, audio/aac, audio/midi, audio/amr

  **Documents:** application/pdf, text/plain, text/markdown, text/vcard, text/rtf, text/csv, text/html, text/calendar, text/xml, application/json, application/msword, application/vnd.openxmlformats-officedocument.wordprocessingml.document, application/vnd.ms-excel, application/vnd.openxmlformats-officedocument.spreadsheetml.sheet, application/vnd.ms-powerpoint, application/vnd.openxmlformats-officedocument.presentationml.presentation, application/x-iwork-pages-sffpages, application/x-iwork-numbers-sffnumbers, application/x-iwork-keynote-sffkey, application/epub+zip, application/zip, application/x-gzip

  **Transcoded on delivery:**

  - `audio/x-caf` — CAF files are transcoded to `audio/mp4` for delivery.

  **Deprecated (accepted but transcoded):**

  - `audio/mp3` — Deprecated. Use `audio/mpeg` instead. Files sent as audio/mp3 will be delivered as audio/mpeg.
  - `audio/mp4` — Deprecated. Use `audio/x-m4a` instead. Files sent as audio/mp4 will be delivered as audio/x-m4a.
  - `audio/aiff` — Deprecated. Use `audio/x-aiff` instead. Files sent as audio/aiff will be delivered as audio/x-aiff.
  - `image/tiff` — Accepted, but TIFF images are transcoded to JPEG for delivery.

  **Unsupported:** FLAC, OGG, and executable files are explicitly rejected.

  - `"image/jpeg"`

  - `"image/png"`

  - `"image/gif"`

  - `"image/heic"`

  - `"image/heif"`

  - `"image/tiff"`

  - `"image/bmp"`

  - `"image/svg+xml"`

  - `"image/webp"`

  - `"image/x-icon"`

  - `"video/mp4"`

  - `"video/quicktime"`

  - `"video/mpeg"`

  - `"video/mpeg2"`

  - `"video/x-m4v"`

  - `"video/x-msvideo"`

  - `"video/3gpp"`

  - `"audio/mpeg"`

  - `"audio/mp3"`

  - `"audio/x-m4a"`

  - `"audio/mp4"`

  - `"audio/x-caf"`

  - `"audio/x-wav"`

  - `"audio/x-aiff"`

  - `"audio/aiff"`

  - `"audio/aac"`

  - `"audio/midi"`

  - `"audio/amr"`

  - `"application/pdf"`

  - `"text/plain"`

  - `"text/markdown"`

  - `"text/vcard"`

  - `"text/rtf"`

  - `"text/csv"`

  - `"text/html"`

  - `"text/calendar"`

  - `"application/msword"`

  - `"application/vnd.openxmlformats-officedocument.wordprocessingml.document"`

  - `"application/vnd.ms-excel"`

  - `"application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"`

  - `"application/vnd.ms-powerpoint"`

  - `"application/vnd.openxmlformats-officedocument.presentationml.presentation"`

  - `"application/x-iwork-pages-sffpages"`

  - `"application/x-iwork-numbers-sffnumbers"`

  - `"application/x-iwork-keynote-sffkey"`

  - `"application/epub+zip"`

  - `"text/xml"`

  - `"application/json"`

  - `"application/zip"`

  - `"application/x-gzip"`

### Attachment Create Response

- `AttachmentCreateResponse object { attachment_id, download_url, expires_at, 3 more }`

  - `attachment_id: string`

    Unique identifier for the attachment

  - `download_url: string`

    Permanent CDN URL for the file. Does not expire. Use the `attachment_id`
    to reference this file in media parts when sending messages.

  - `expires_at: string`

    When the upload URL expires (15 minutes from now)

  - `http_method: "PUT"`

    HTTP method to use for upload (always PUT)

    - `"PUT"`

  - `required_headers: map[string]`

    HTTP headers that must be set on the upload request. The presigned URL is signed
    with these exact values — S3 will reject the upload if they don't match.

  - `upload_url: string`

    Presigned URL for uploading the file. PUT the raw binary file content to this URL
    with the `required_headers`. Do not JSON-encode or multipart-wrap the body.
    Expires after 15 minutes.

### Attachment Retrieve Response

- `AttachmentRetrieveResponse object { id, content_type, created_at, 4 more }`

  - `id: string`

    Unique identifier for the attachment (UUID)

  - `content_type: SupportedContentType`

    Supported MIME types for file attachments and media URLs.

    **Images:** image/jpeg, image/png, image/gif, image/heic, image/heif, image/tiff, image/bmp, image/svg+xml, image/webp, image/x-icon

    **Videos:** video/mp4, video/quicktime, video/mpeg, video/mpeg2, video/x-msvideo, video/3gpp

    **Audio:** audio/mpeg, audio/x-m4a, audio/x-caf, audio/x-wav, audio/x-aiff, audio/aac, audio/midi, audio/amr

    **Documents:** application/pdf, text/plain, text/markdown, text/vcard, text/rtf, text/csv, text/html, text/calendar, text/xml, application/json, application/msword, application/vnd.openxmlformats-officedocument.wordprocessingml.document, application/vnd.ms-excel, application/vnd.openxmlformats-officedocument.spreadsheetml.sheet, application/vnd.ms-powerpoint, application/vnd.openxmlformats-officedocument.presentationml.presentation, application/x-iwork-pages-sffpages, application/x-iwork-numbers-sffnumbers, application/x-iwork-keynote-sffkey, application/epub+zip, application/zip, application/x-gzip

    **Transcoded on delivery:**

    - `audio/x-caf` — CAF files are transcoded to `audio/mp4` for delivery.

    **Deprecated (accepted but transcoded):**

    - `audio/mp3` — Deprecated. Use `audio/mpeg` instead. Files sent as audio/mp3 will be delivered as audio/mpeg.
    - `audio/mp4` — Deprecated. Use `audio/x-m4a` instead. Files sent as audio/mp4 will be delivered as audio/x-m4a.
    - `audio/aiff` — Deprecated. Use `audio/x-aiff` instead. Files sent as audio/aiff will be delivered as audio/x-aiff.
    - `image/tiff` — Accepted, but TIFF images are transcoded to JPEG for delivery.

    **Unsupported:** FLAC, OGG, and executable files are explicitly rejected.

    - `"image/jpeg"`

    - `"image/png"`

    - `"image/gif"`

    - `"image/heic"`

    - `"image/heif"`

    - `"image/tiff"`

    - `"image/bmp"`

    - `"image/svg+xml"`

    - `"image/webp"`

    - `"image/x-icon"`

    - `"video/mp4"`

    - `"video/quicktime"`

    - `"video/mpeg"`

    - `"video/mpeg2"`

    - `"video/x-m4v"`

    - `"video/x-msvideo"`

    - `"video/3gpp"`

    - `"audio/mpeg"`

    - `"audio/mp3"`

    - `"audio/x-m4a"`

    - `"audio/mp4"`

    - `"audio/x-caf"`

    - `"audio/x-wav"`

    - `"audio/x-aiff"`

    - `"audio/aiff"`

    - `"audio/aac"`

    - `"audio/midi"`

    - `"audio/amr"`

    - `"application/pdf"`

    - `"text/plain"`

    - `"text/markdown"`

    - `"text/vcard"`

    - `"text/rtf"`

    - `"text/csv"`

    - `"text/html"`

    - `"text/calendar"`

    - `"application/msword"`

    - `"application/vnd.openxmlformats-officedocument.wordprocessingml.document"`

    - `"application/vnd.ms-excel"`

    - `"application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"`

    - `"application/vnd.ms-powerpoint"`

    - `"application/vnd.openxmlformats-officedocument.presentationml.presentation"`

    - `"application/x-iwork-pages-sffpages"`

    - `"application/x-iwork-numbers-sffnumbers"`

    - `"application/x-iwork-keynote-sffkey"`

    - `"application/epub+zip"`

    - `"text/xml"`

    - `"application/json"`

    - `"application/zip"`

    - `"application/x-gzip"`

  - `created_at: string`

    When the attachment was created

  - `filename: string`

    Original filename of the attachment

  - `size_bytes: number`

    Size of the attachment in bytes

  - `status: "pending" or "complete" or "failed"`

    **DEPRECATED:** This field is deprecated and will be removed in a future API version.

    - `"pending"`

    - `"complete"`

    - `"failed"`

  - `download_url: optional string`

    URL to download the attachment
