Skip to the page

Sending and receiving

Files and voice memos

Upload pictures, video, audio, PDFs and contact cards and send them on a text, read the pictures and voice memos people send you, and know the limits on each.

A text can carry pictures, video, audio, a PDF or a contact card, and texts that come in carry whatever people send you, voice memos included. Sending a file takes two calls: upload it, then send its id.

Send a file

Dana wants to send Maria the photos of 412 Oak St.

Upload it

POST/v1/files takes the file as multipart/form-data in a field named file:

POST/v1/filesUpload a file →
curl -X POST "https://usebluebot.com/api/v1/files" \
  -H "Authorization: Bearer $BLUEBOT_API_KEY" \
  -H "Idempotency-Key: upload-412-oak-kitchen" \
  -F "file=@kitchen.jpg"
Response201The uploaded file
{
  "id": "file_1Hq2LxW9cVbN3mKpRtYs0a",
  "object": "file",
  "name": "kitchen.jpg",
  "content_type": "image/jpeg",
  "size": 482113,
  "kind": "image",
  "status": "ready",
  "url": "https://usebluebot.com/files/f/2Bf8QzD4kJmA6nXwEuTr1c?sig=…",
  "url_expires_at": "2026-11-13T20:41:00.000Z",
  "transcript": null,
  "transcript_language": null,
  "created_at": "2026-11-13T19:40:00.000Z"
}

The file goes by the name it was uploaded with. To send it under another name, add a name form field (-F name=412-oak-kitchen.jpg with curl). The person sees that name on a PDF or a contact card.

BlueBot reads the file’s type from the Content-Type of the form part. curl and the SDKs set it from the file’s extension. If your code builds the form by hand, set it, or the upload is refused as 415 unsupported_media_type.

Send it

Put the id in files, with words or without:

POST/v1/messagesSend a text →
curl -X POST "https://usebluebot.com/api/v1/messages" \
  -H "Authorization: Bearer $BLUEBOT_API_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: listing-412-oak-photos" \
  -d '{
    "to": "+15555550123",
    "text": "Here’s the kitchen at 412 Oak St, as promised.",
    "files": [
      "file_1Hq2LxW9cVbN3mKpRtYs0a"
    ]
  }'

Up to 10 files go on one text. They follow the words in the order you list them. Each one arrives as its own picture or attachment in the conversation, the way it would if you dragged them into Messages one after another.

Check it went

message.sent fires once the words and every file went. If the words went and a file didn’t, the text is still sent, with failure set to say which file:

Response200Sent, with one file that didn’t go
{
  "id": "msg_1Hq2LxW9cVbN3mKpRtYs0a",
  "object": "message",
  "state": "sent",
  "service": "imessage",
  "failure": {
    "reason": "file_unavailable",
    "detail": "Messages didn’t send kitchen.jpg."
  }
}

If the Mac couldn’t download a file to send it, nothing goes: the text fails with failure.reason: "file_unavailable", so the person never gets words that point at a picture they don’t have.

What you can send

KindTypeskind on the file
PicturesJPEG, PNG, GIF, HEIC, HEIF, WebPimage
VideoMP4, QuickTime (.mov)video
AudioMP3, M4A, AAC, WAV, CAFaudio
DocumentsPDFpdf
Contact cardsvCard (.vcf, text/vcard)contact_card

Each file can be up to 25 MB. Anything else is 415 unsupported_media_type, and a larger file is 413 payload_too_large. An empty file is 400 invalid_request.

One upload can go on more than one text, so a logo or a menu you send to many people needs uploading once. An upload no text uses is deleted after a day, and a file that went out is kept for 30 days, the same as the words of a text. After that its status is deleted. Upload again for a text after that.

iMessage and regular texts

Over iMessage, files up to the 25 MB limit go as they are. Over a regular text, a file goes as a picture message (MMS) through your iPhone, and your carrier decides how large that may be: phones usually shrink a big photo to fit, and may refuse a long video. Send large files to people on iMessage, or send a link to the file instead.

Contact cards

Upload a .vcf file and send it like any other file. The person can tap it to save your details. A good first text to a new client carries one, so your name shows up when you text them next time:

POST/v1/messagesSend a text →
curl -X POST "https://usebluebot.com/api/v1/messages" \
  -H "Authorization: Bearer $BLUEBOT_API_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: deal-48213-card" \
  -d '{
    "to": "+15555550123",
    "text": "Here’s my card so you have my number saved.",
    "files": [
      "file_3Lp3VsC7hGqE5tZyKbWn2d"
    ]
  }'

Voice memos

Sending audio

Upload an audio file (M4A, MP3, AAC, WAV or CAF) and send it. It arrives as audio the person can play in the conversation. BlueBot can’t record a voice memo in Messages for you, so a recording made elsewhere goes as an audio file.

Voice memos you receive

When somebody sends you a voice memo, it comes on the message as a file with "kind": "voice_memo" and "content_type": "audio/x-caf". Safari plays CAF files and most other browsers don’t, so convert one before you play it on a web page. ffmpeg -i memo.caf memo.m4a does it.

If you turn on transcription in BlueBot’s settings on the Mac, the Mac transcribes each voice memo with Apple’s own speech recognition, on the Mac itself, before it copies the message. The words come in transcript, with the language in transcript_language:

A voice memo with a transcript
{
  "id": "file_2Bf8QzD4kJmA6nXwEuTr1c",
  "object": "file",
  "name": "Audio Message.caf",
  "content_type": "audio/x-caf",
  "size": 41022,
  "kind": "voice_memo",
  "status": "ready",
  "url": "https://usebluebot.com/files/f/3Lp3VsC7hGqE5tZyKbWn2d?sig=…",
  "url_expires_at": "2026-11-13T20:44:00.000Z",
  "transcript": "Hey Dana, Thursday works, can we do 3 instead of 2?",
  "transcript_language": "en-US",
  "created_at": "2026-11-13T19:44:00.000Z"
}

Transcription is off until you turn it on, costs nothing, and sends no audio anywhere but BlueBot. GET /v1/device says whether it’s on, in transcription. A memo that couldn’t be transcribed has "transcript": null.

Files you receive

Pictures, videos, voice memos and documents people send you are on the message’s files, in order. A file’s status says whether you can read it:

statusIt meansDo next
readyBlueBot has it. url reads it for an hour.Download it now if you want to keep it.
waitingThe Mac is still uploading it, usually for a few seconds.Read the message or the file again shortly.
too_largeIt’s over 25 MB, so the Mac didn’t upload it.Open it in Messages on your Mac or iPhone.
deletedIt’s more than 30 days old.Nothing. Copy files into your own storage when they come if you need them longer.

message.received waits until the Mac has uploaded the text’s files, so the files on the event are usually ready. If they take more than 2 minutes, the event goes anyway and the slow ones are waiting.

Each url is a signed link that works for an hour and needs no key, so anyone with it can read the file in that hour. Don’t paste it anywhere public. When a link has run out, ask for the file again and you get a fresh one:

GET/v1/files/file_2Bf8QzD4kJmA6nXwEuTr1cGet a file →
curl "https://usebluebot.com/api/v1/files/file_2Bf8QzD4kJmA6nXwEuTr1c" \
  -H "Authorization: Bearer $BLUEBOT_API_KEY"

The Mac uploads files only from the chats it copies. Receive texts explains which those are.

Limits

LimitValue
One file25 MB
Files on one text10
An upload no text usesDeleted after a day
A file that was sent or receivedKept 30 days
A file’s urlWorks for an hour

Limits lists every limit in one place.