> ## Documentation Index
> Fetch the complete documentation index at: https://bluebubbles.anmho.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Work with Attachments in the BlueBubbles SDK

> Upload files before multipart sends, download attachments by GUID, generate blurhashes for placeholders, and retrieve live photo videos.

The BlueBubbles SDK exposes all attachment operations through `client.attachments`. You can upload files before embedding them in multipart messages, download attachments by GUID, force-download files not yet cached on the Mac, fetch metadata, generate blur hashes for progressive image loading, and retrieve live photo videos. Each method corresponds to an endpoint on your BlueBubbles Server.

## Upload an attachment for multipart messages

When you want to include a file inside a multipart message, you must upload it first. The two-step flow is:

<Steps>
  <Step title="Upload the file">
    Call `uploadAttachment()` with a multipart form body containing your file. The server stores the file and returns a unique UUID you reference in the next step.

    ```typescript theme={null}
    import { BlueBubblesClient } from "bluebubbles-sdk";
    import { readFileSync } from "fs";

    const client = new BlueBubblesClient({
    BASE: "http://your-server:1234",
    PASSWORD: "your-server-password",
    });

    const formData = new FormData();
    formData.append(
      "attachment",
      new Blob([readFileSync("./photo.jpg")], { type: "image/jpeg" }),
      "photo.jpg"
    );

    const uploadResponse = await client.attachments.uploadAttachment({
      requestBody: formData,
    });

    // The UUID you need for the next step
    const attachmentUuid = uploadResponse.data.hash;
    ```

    The response shape looks like:

    ```json theme={null}
    {
      "status": 200,
      "message": "Success",
      "data": {
        "hash": "a04a23a0833b33db8a63ee0816948786"
      }
    }
    ```
  </Step>

  <Step title="Reference the UUID in a multipart message">
    Pass the `hash` value from the upload response as the `attachment` field in the corresponding part:

    ```typescript theme={null}
    await client.messages.sendMultipartMessage({
      requestBody: {
        chatGuid: "iMessage;+;+15551234567",
        parts: [
          { partIndex: 0, text: "Here's the photo you asked for!" },
          {
            partIndex: 1,
            attachment: attachmentUuid,
            name: "photo.jpg",
          },
        ],
      },
    });
    ```
  </Step>
</Steps>

<Note>
  This two-step upload flow is only required for multipart messages. If you just want to send a single file to a chat, use `client.messages.sendAttachment()` directly instead — no pre-upload needed.
</Note>

***

## Download an attachment

Use `download()` to retrieve the raw file bytes for an attachment you already have the GUID for. This is the standard download path — it works when the attachment is already cached on the Mac.

```typescript theme={null}
const fileData = await client.attachments.download({
  guid: "ATTACHMENT-GUID-HERE",
});

// fileData contains the raw binary response from the server
```

You can get attachment GUIDs from message query results. When you call `client.messages.list()` with `"with": ["attachment"]`, each message object includes an `attachments` array with GUIDs you can pass directly to `download()`.

***

## Force-download an attachment

If an attachment exists in the database but hasn't been downloaded to the Mac yet, `download()` returns a 404. In that case, use `forceDownloadAttachment()` to trigger the Mac to fetch the file from iCloud first.

<Note>
  `forceDownloadAttachment()` requires the Private API to be enabled on your BlueBubbles Server.
</Note>

```typescript theme={null}
// Try the regular download first
try {
  const fileData = await client.attachments.download({
    guid: "ATTACHMENT-GUID-HERE",
  });
  // Handle file data
} catch (err) {
  // Fall back to force-download if the file isn't on the Mac yet
  const fileData = await client.attachments.forceDownloadAttachment({
    guid: "ATTACHMENT-GUID-HERE",
  });
  // Handle file data
}
```

<Tip>
  Use `forceDownloadAttachment()` when building apps that need to reliably retrieve older messages. Attachments from messages received before the BlueBubbles Server was installed may not be locally cached.
</Tip>

***

## Fetch attachment metadata

Use `get()` to retrieve the database record for an attachment without downloading the file. This is useful for checking the MIME type, filename, or size before deciding whether to download.

```typescript theme={null}
const attachment = await client.attachments.get({
  guid: "ATTACHMENT-GUID-HERE",
});

console.log(attachment.data.mimeType);   // e.g. "image/jpeg"
console.log(attachment.data.transferName); // e.g. "photo.jpg"
```

***

## Generate a blur hash

`getAttachmentBlurhash()` generates a [BlurHash](https://blurha.sh/) string for an image attachment. You can use the hash to render a blurred placeholder in your UI before the full image loads.

<Note>
  Generating a BlurHash is CPU-intensive on the server. For large images, the server resizes internally before hashing. Expect slightly longer response times compared to other attachment endpoints.
</Note>

```typescript theme={null}
const blurhashResponse = await client.attachments.getAttachmentBlurhash({
  guid: "ATTACHMENT-GUID-HERE",
});

const hash = blurhashResponse.data; // e.g. "LKO2?U%2Tw=w]~RBVZRi};RPxuwH"

// Use with the `blurhash` npm package to decode and render
```

***

## Retrieve a live photo

Use `getAttachmentLivePhoto()` to retrieve the video component of a Live Photo. If the attachment is not an image or doesn't have a live version, the server returns an error.

```typescript theme={null}
try {
  const livePhoto = await client.attachments.getAttachmentLivePhoto({
    guid: "ATTACHMENT-GUID-HERE",
  });
  // livePhoto contains the raw video bytes (typically a .mov file)
} catch (err) {
  // The attachment does not have a live photo component
  console.error("No live photo available for this attachment.");
}
```

<Tip>
  Check the attachment's MIME type with `get()` before calling `getAttachmentLivePhoto()`. Live photos are associated with `image/jpeg` or `image/heic` attachments that also have a paired video file.
</Tip>
