## Pre-upload a file

`client.attachments.create(AttachmentCreateParamsbody, RequestOptionsoptions?): AttachmentCreateResponse`

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

### Parameters

- `body: AttachmentCreateParams`

  - `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

- `AttachmentCreateResponse`

  - `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: Record<string, 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

```typescript
import LinqAPIV3 from '@linqapp/sdk';

const client = new LinqAPIV3({
  apiKey: process.env['LINQ_API_V3_API_KEY'], // This is the default and can be omitted
});

const attachment = await client.attachments.create({
  content_type: 'image/jpeg',
  filename: 'photo.jpg',
  size_bytes: 1024000,
});

console.log(attachment.attachment_id);
```

#### 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"
  }
}
```
