Build
Files and media
Send and receive reports, images and other files — encrypted on your machine, names and types included.
Your agent can send files and media, and read the files users send it. The SDK encrypts the bytes locally with a fresh AES-256-GCM key, uploads only the ciphertext, and sends the key — together with the file's name and type — inside the end-to-end encrypted message. Pacerelle stores a file it cannot open, under a name it cannot read.
Send a file
import { readFile } from "node:fs/promises";
await agent.sendFile({
conversationId: message.conversationId,
to: message.from,
replyToMessageId: message.id,
text: "Here's this month's report.",
file: {
name: "report-september.pdf",
mime: "application/pdf",
data: await readFile("./out/report-september.pdf"),
},
});In JavaScript, data accepts a Uint8Array, an ArrayBuffer or a Blob. In Python, pass
bytes.
Send an image, audio or video
sendMedia works like sendFile and adds optional display hints — width and height for
images and video, durationMs (duration_ms) for audio and video — so the app can lay out the
preview before downloading it.
await agent.sendMedia({
conversationId: message.conversationId,
to: message.from,
text: "Sales by region",
file: { name: "chart.png", mime: "image/png", data: pngBytes },
width: 1200,
height: 800,
});Several files in one message
Upload each file first, then send them together:
const attachments = await Promise.all(
files.map((file) => agent.uploadFile(file)),
);
await agent.sendMessage({
conversationId: message.conversationId,
to: message.from,
text: "All three exports are ready.",
attachments,
});In Python, use upload_file(...) then send_message(..., attachments=[...]).
Files sent by the user
When a user attaches files — in a message or through a file picker —
each one appears in message.attachments with its name, mime type and size. Download and
decrypt it with downloadAttachment (download_attachment in Python): the SDK fetches the
ciphertext and decrypts it on your machine with the key carried by the message.
client.onMessage(async (message, agent) => {
for (const attachment of message.attachments) {
if (attachment.size > 10_000_000) continue; // check before processing
const bytes = await agent.downloadAttachment(attachment); // Uint8Array
console.log(attachment.name, attachment.mime, bytes.length);
}
});The agent can download the files of conversations it's a member of. In a group, that means files sent after it joined.
Limits
| Limit | Value |
|---|---|
| Maximum size per file | 25 MB |
| Files per message in the app | 5 |
| Storage | Encrypted files are kept for a limited time (10 days). Download what you need to keep. |
Downloads fail once a file has expired: save what your agent needs as soon as it arrives.
Privacy notes
- File contents, names and types are end-to-end encrypted. The relay stores ciphertext under a generic name and only sees each file's size.
- Messages sent before this protection existed keep their original names in the relay's records; new files never expose them.
- Treat every incoming file as untrusted input: check its type and size before processing it, and ask the user before sending its content to a third-party service.