# Attachments

## Pre-upload a file

`client.Attachments.New(ctx, body) (*AttachmentNewResponse, error)`

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

  - `ContentType param.Field[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.

  - `Filename param.Field[string]`

    Name of the file to upload

  - `SizeBytes param.Field[int64]`

    Size of the file in bytes (max 100MB)

### Returns

- `type AttachmentNewResponse struct{…}`

  - `AttachmentID string`

    Unique identifier for the attachment

  - `DownloadURL string`

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

  - `ExpiresAt Time`

    When the upload URL expires (15 minutes from now)

  - `HTTPMethod AttachmentNewResponseHTTPMethod`

    HTTP method to use for upload (always PUT)

    - `const AttachmentNewResponseHTTPMethodPut AttachmentNewResponseHTTPMethod = "PUT"`

  - `RequiredHeaders map[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.

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

```go
package main

import (
  "context"
  "fmt"

  "github.com/linq-team/linq-go"
  "github.com/linq-team/linq-go/option"
)

func main() {
  client := linqgo.NewClient(
    option.WithAPIKey("My API Key"),
  )
  attachment, err := client.Attachments.New(context.TODO(), linqgo.AttachmentNewParams{
    ContentType: linqgo.SupportedContentTypeImageJpeg,
    Filename: "photo.jpg",
    SizeBytes: 1024000,
  })
  if err != nil {
    panic(err.Error())
  }
  fmt.Printf("%+v\n", attachment.AttachmentID)
}
```

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

`client.Attachments.Get(ctx, attachmentID) (*AttachmentGetResponse, error)`

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

### Parameters

- `attachmentID string`

### Returns

- `type AttachmentGetResponse struct{…}`

  - `ID string`

    Unique identifier for the attachment (UUID)

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

    - `const SupportedContentTypeImageJpeg SupportedContentType = "image/jpeg"`

    - `const SupportedContentTypeImagePng SupportedContentType = "image/png"`

    - `const SupportedContentTypeImageGif SupportedContentType = "image/gif"`

    - `const SupportedContentTypeImageHeic SupportedContentType = "image/heic"`

    - `const SupportedContentTypeImageHeif SupportedContentType = "image/heif"`

    - `const SupportedContentTypeImageTiff SupportedContentType = "image/tiff"`

    - `const SupportedContentTypeImageBmp SupportedContentType = "image/bmp"`

    - `const SupportedContentTypeImageSvgXml SupportedContentType = "image/svg+xml"`

    - `const SupportedContentTypeImageWebp SupportedContentType = "image/webp"`

    - `const SupportedContentTypeImageXIcon SupportedContentType = "image/x-icon"`

    - `const SupportedContentTypeVideoMP4 SupportedContentType = "video/mp4"`

    - `const SupportedContentTypeVideoQuicktime SupportedContentType = "video/quicktime"`

    - `const SupportedContentTypeVideoMpeg SupportedContentType = "video/mpeg"`

    - `const SupportedContentTypeVideoMpeg2 SupportedContentType = "video/mpeg2"`

    - `const SupportedContentTypeVideoXM4v SupportedContentType = "video/x-m4v"`

    - `const SupportedContentTypeVideoXMsvideo SupportedContentType = "video/x-msvideo"`

    - `const SupportedContentTypeVideo3gpp SupportedContentType = "video/3gpp"`

    - `const SupportedContentTypeAudioMpeg SupportedContentType = "audio/mpeg"`

    - `const SupportedContentTypeAudioMP3 SupportedContentType = "audio/mp3"`

    - `const SupportedContentTypeAudioXM4a SupportedContentType = "audio/x-m4a"`

    - `const SupportedContentTypeAudioMP4 SupportedContentType = "audio/mp4"`

    - `const SupportedContentTypeAudioXCaf SupportedContentType = "audio/x-caf"`

    - `const SupportedContentTypeAudioXWav SupportedContentType = "audio/x-wav"`

    - `const SupportedContentTypeAudioXAiff SupportedContentType = "audio/x-aiff"`

    - `const SupportedContentTypeAudioAiff SupportedContentType = "audio/aiff"`

    - `const SupportedContentTypeAudioAac SupportedContentType = "audio/aac"`

    - `const SupportedContentTypeAudioMidi SupportedContentType = "audio/midi"`

    - `const SupportedContentTypeAudioAmr SupportedContentType = "audio/amr"`

    - `const SupportedContentTypeApplicationPdf SupportedContentType = "application/pdf"`

    - `const SupportedContentTypeTextPlain SupportedContentType = "text/plain"`

    - `const SupportedContentTypeTextMarkdown SupportedContentType = "text/markdown"`

    - `const SupportedContentTypeTextVcard SupportedContentType = "text/vcard"`

    - `const SupportedContentTypeTextRtf SupportedContentType = "text/rtf"`

    - `const SupportedContentTypeTextCsv SupportedContentType = "text/csv"`

    - `const SupportedContentTypeTextHTML SupportedContentType = "text/html"`

    - `const SupportedContentTypeTextCalendar SupportedContentType = "text/calendar"`

    - `const SupportedContentTypeApplicationMsword SupportedContentType = "application/msword"`

    - `const SupportedContentTypeApplicationVndOpenxmlformatsOfficedocumentWordprocessingmlDocument SupportedContentType = "application/vnd.openxmlformats-officedocument.wordprocessingml.document"`

    - `const SupportedContentTypeApplicationVndMsExcel SupportedContentType = "application/vnd.ms-excel"`

    - `const SupportedContentTypeApplicationVndOpenxmlformatsOfficedocumentSpreadsheetmlSheet SupportedContentType = "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"`

    - `const SupportedContentTypeApplicationVndMsPowerpoint SupportedContentType = "application/vnd.ms-powerpoint"`

    - `const SupportedContentTypeApplicationVndOpenxmlformatsOfficedocumentPresentationmlPresentation SupportedContentType = "application/vnd.openxmlformats-officedocument.presentationml.presentation"`

    - `const SupportedContentTypeApplicationXIworkPagesSffpages SupportedContentType = "application/x-iwork-pages-sffpages"`

    - `const SupportedContentTypeApplicationXIworkNumbersSffnumbers SupportedContentType = "application/x-iwork-numbers-sffnumbers"`

    - `const SupportedContentTypeApplicationXIworkKeynoteSffkey SupportedContentType = "application/x-iwork-keynote-sffkey"`

    - `const SupportedContentTypeApplicationEpubZip SupportedContentType = "application/epub+zip"`

    - `const SupportedContentTypeTextXml SupportedContentType = "text/xml"`

    - `const SupportedContentTypeApplicationJson SupportedContentType = "application/json"`

    - `const SupportedContentTypeApplicationZip SupportedContentType = "application/zip"`

    - `const SupportedContentTypeApplicationXGzip SupportedContentType = "application/x-gzip"`

  - `CreatedAt Time`

    When the attachment was created

  - `Filename string`

    Original filename of the attachment

  - `SizeBytes int64`

    Size of the attachment in bytes

  - `Status AttachmentGetResponseStatus`

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

    - `const AttachmentGetResponseStatusPending AttachmentGetResponseStatus = "pending"`

    - `const AttachmentGetResponseStatusComplete AttachmentGetResponseStatus = "complete"`

    - `const AttachmentGetResponseStatusFailed AttachmentGetResponseStatus = "failed"`

  - `DownloadURL string`

    URL to download the attachment

### Example

```go
package main

import (
  "context"
  "fmt"

  "github.com/linq-team/linq-go"
  "github.com/linq-team/linq-go/option"
)

func main() {
  client := linqgo.NewClient(
    option.WithAPIKey("My API Key"),
  )
  attachment, err := client.Attachments.Get(context.TODO(), "abc12345-1234-5678-9abc-def012345678")
  if err != nil {
    panic(err.Error())
  }
  fmt.Printf("%+v\n", attachment.ID)
}
```

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

`client.Attachments.Delete(ctx, attachmentID) error`

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

Permanently delete an attachment owned by the authenticated partner.

### Parameters

- `attachmentID string`

### Example

```go
package main

import (
  "context"

  "github.com/linq-team/linq-go"
  "github.com/linq-team/linq-go/option"
)

func main() {
  client := linqgo.NewClient(
    option.WithAPIKey("My API Key"),
  )
  err := client.Attachments.Delete(context.TODO(), "abc12345-1234-5678-9abc-def012345678")
  if err != nil {
    panic(err.Error())
  }
}
```

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

- `type SupportedContentType string`

  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.

  - `const SupportedContentTypeImageJpeg SupportedContentType = "image/jpeg"`

  - `const SupportedContentTypeImagePng SupportedContentType = "image/png"`

  - `const SupportedContentTypeImageGif SupportedContentType = "image/gif"`

  - `const SupportedContentTypeImageHeic SupportedContentType = "image/heic"`

  - `const SupportedContentTypeImageHeif SupportedContentType = "image/heif"`

  - `const SupportedContentTypeImageTiff SupportedContentType = "image/tiff"`

  - `const SupportedContentTypeImageBmp SupportedContentType = "image/bmp"`

  - `const SupportedContentTypeImageSvgXml SupportedContentType = "image/svg+xml"`

  - `const SupportedContentTypeImageWebp SupportedContentType = "image/webp"`

  - `const SupportedContentTypeImageXIcon SupportedContentType = "image/x-icon"`

  - `const SupportedContentTypeVideoMP4 SupportedContentType = "video/mp4"`

  - `const SupportedContentTypeVideoQuicktime SupportedContentType = "video/quicktime"`

  - `const SupportedContentTypeVideoMpeg SupportedContentType = "video/mpeg"`

  - `const SupportedContentTypeVideoMpeg2 SupportedContentType = "video/mpeg2"`

  - `const SupportedContentTypeVideoXM4v SupportedContentType = "video/x-m4v"`

  - `const SupportedContentTypeVideoXMsvideo SupportedContentType = "video/x-msvideo"`

  - `const SupportedContentTypeVideo3gpp SupportedContentType = "video/3gpp"`

  - `const SupportedContentTypeAudioMpeg SupportedContentType = "audio/mpeg"`

  - `const SupportedContentTypeAudioMP3 SupportedContentType = "audio/mp3"`

  - `const SupportedContentTypeAudioXM4a SupportedContentType = "audio/x-m4a"`

  - `const SupportedContentTypeAudioMP4 SupportedContentType = "audio/mp4"`

  - `const SupportedContentTypeAudioXCaf SupportedContentType = "audio/x-caf"`

  - `const SupportedContentTypeAudioXWav SupportedContentType = "audio/x-wav"`

  - `const SupportedContentTypeAudioXAiff SupportedContentType = "audio/x-aiff"`

  - `const SupportedContentTypeAudioAiff SupportedContentType = "audio/aiff"`

  - `const SupportedContentTypeAudioAac SupportedContentType = "audio/aac"`

  - `const SupportedContentTypeAudioMidi SupportedContentType = "audio/midi"`

  - `const SupportedContentTypeAudioAmr SupportedContentType = "audio/amr"`

  - `const SupportedContentTypeApplicationPdf SupportedContentType = "application/pdf"`

  - `const SupportedContentTypeTextPlain SupportedContentType = "text/plain"`

  - `const SupportedContentTypeTextMarkdown SupportedContentType = "text/markdown"`

  - `const SupportedContentTypeTextVcard SupportedContentType = "text/vcard"`

  - `const SupportedContentTypeTextRtf SupportedContentType = "text/rtf"`

  - `const SupportedContentTypeTextCsv SupportedContentType = "text/csv"`

  - `const SupportedContentTypeTextHTML SupportedContentType = "text/html"`

  - `const SupportedContentTypeTextCalendar SupportedContentType = "text/calendar"`

  - `const SupportedContentTypeApplicationMsword SupportedContentType = "application/msword"`

  - `const SupportedContentTypeApplicationVndOpenxmlformatsOfficedocumentWordprocessingmlDocument SupportedContentType = "application/vnd.openxmlformats-officedocument.wordprocessingml.document"`

  - `const SupportedContentTypeApplicationVndMsExcel SupportedContentType = "application/vnd.ms-excel"`

  - `const SupportedContentTypeApplicationVndOpenxmlformatsOfficedocumentSpreadsheetmlSheet SupportedContentType = "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"`

  - `const SupportedContentTypeApplicationVndMsPowerpoint SupportedContentType = "application/vnd.ms-powerpoint"`

  - `const SupportedContentTypeApplicationVndOpenxmlformatsOfficedocumentPresentationmlPresentation SupportedContentType = "application/vnd.openxmlformats-officedocument.presentationml.presentation"`

  - `const SupportedContentTypeApplicationXIworkPagesSffpages SupportedContentType = "application/x-iwork-pages-sffpages"`

  - `const SupportedContentTypeApplicationXIworkNumbersSffnumbers SupportedContentType = "application/x-iwork-numbers-sffnumbers"`

  - `const SupportedContentTypeApplicationXIworkKeynoteSffkey SupportedContentType = "application/x-iwork-keynote-sffkey"`

  - `const SupportedContentTypeApplicationEpubZip SupportedContentType = "application/epub+zip"`

  - `const SupportedContentTypeTextXml SupportedContentType = "text/xml"`

  - `const SupportedContentTypeApplicationJson SupportedContentType = "application/json"`

  - `const SupportedContentTypeApplicationZip SupportedContentType = "application/zip"`

  - `const SupportedContentTypeApplicationXGzip SupportedContentType = "application/x-gzip"`
