Skip to main content
POST
Send with Attachments
The Try it panel runs against production (https://app.tuco.ai) with the key you paste into it. There is no sandbox — a request from this page sends a real message from one of your lines.
Send attachments alongside or instead of text messages. Tuco handles downloading, caching, and delivering files through your device relay.

Request body

Use the same POST /api/messages endpoint. Add attachmentUrls to your request:
string[]
required
Array of public URLs to attach. Max 2 attachments per message, max 25 MB each.
string[]
Optional display names for each attachment (same order as attachmentUrls). When omitted, the filename from the URL is used.
string
Optional text to send with the attachments. When omitted, only the attachment is sent (no “Attachment” placeholder text).
string
The phone number to text, in E.164 format (e.g. "+12025551234"). This is how you address almost every send — you do not need a Tuco leadId. Tuco finds the matching lead in your workspace, or creates one under the Quick Sends list automatically.Required unless you pass leadId or recipientEmail.
string
Send to an existing lead using their stored contact details. Required unless you pass recipientPhone or recipientEmail.
string
Use recipientPhone unless you specifically need this. An email address only reaches someone over iMessage if that exact address is registered to their Apple account — rare, and not something you can assume. Addressing by phone number is what works.
Required unless you pass recipientPhone or leadId.
boolean
default:"false"
Send a single audio attachment as a native iMessage voice note (the waveform bubble) instead of a generic audio file. Accepts true or the string "true". Tuco transcodes whatever audio you supply — MP3, M4A, WAV, AAC, OGG, OPUS, FLAC, AIFF, AMR, CAF — into the exact format iMessage needs, so you do not have to convert anything yourself.The request is rejected with a 400 if voiceNote is set and the attachment is not audio (a video, an image, or a web-page link), rather than sending something that cannot become a waveform. See Voice note requirements.
All other POST /api/messages body fields apply here too — including forceFallback (skip the iMessage availability check and route straight to your configured fallback). One caveat: the SMS/fallback channel is text-only, so a forceFallback send delivers the message text but not the attachments — those go over iMessage only.

Supported formats


Voice notes

An audio attachment sends as a generic audio file by default. To get the native iMessage voice note — the waveform bubble with a play button — add voiceNote: true:
Tuco transcodes your audio server-side into the one format iMessage renders natively (Opus mono in a CAF container) and validates the result before sending. You do not need to convert the file yourself — MP3, M4A (iPhone Voice Memos), WAV, AAC, OGG, OPUS, FLAC, AIFF, AMR and CAF all work.

Voice note requirements

All five have to be true. These are conditions on the audio you link to, not request fields.

A direct link to an audio FILE

The URL has to return the audio itself. A YouTube, Google Drive or Dropbox share page is a web page, not a file — those are rejected. So is any link that needs a login.

Publicly reachable, no authentication

Our sending device fetches the URL directly. If it needs a cookie, a session or a signed-in browser, the fetch fails and nothing is sent.

Under 5 minutes

Recordings longer than 300 seconds are rejected.

Under 25 MB

Same ceiling as every other attachment sent by URL. Files you push through POST /api/attachments/upload have a tighter 5 MB cap.

Not the first message to a contact

The first-ever message to a new contact must be plain text — no attachment or voice note. Send a text first, then the voice note as a follow-up.
The easy way to get a valid URL: upload the recording in the app under Leads → Uploads (/leads?tab=uploads) and use the link it gives you back. That link is already public, direct, and correctly typed — which is what most failed voice notes turn out to be missing.
What happens if the audio is wrong. Tuco converts your file and then verifies its own output before sending. If the result would not play — the wrong codec, a stereo track, a corrupt file — the send is stopped and the message is marked failed with the reason. We do not deliver a silent 0:00 bubble. You will see one of these on the message:
Do not rename an MP3 to .caf. Tuco treats any .caf as a finished voice note and sends it as-is, so a renamed MP3 (or a .caf from a consumer web converter, which is usually PCM rather than Opus) is rejected and not sent — it would otherwise arrive as a dead 0:00 bubble. Send the original .mp3 with voiceNote: true and let Tuco encode it.
Passing voiceNote: true alongside a real .caf is always safe: a valid voice note passes straight through untouched, and an invalid one gets re-encoded instead of rejected. If you are sending .caf files you did not produce with afconvert -f caff -d opus@24000 -c 1, include the flag.

When a voice note will not send

Voice notes fail permanently (no retry) in these cases, and the reason is shown on the message in your Unibox:

Examples


Limits

Attachment caching: When you send the same attachment URL multiple times (e.g. a promo video in a campaign), Tuco caches it per line. The second send skips download + upload, making delivery significantly faster.

Device gap

Each attachment counts as part of a single message — not a separate send. Sending text + video in one API call uses one device gap (30s), not two. This is significantly faster than sending them as separate messages.
For automations that send a video followed by a text CTA, combine them into a single API call with message + attachmentUrls instead of two separate calls. This halves your device gap overhead.

Error responses

Voice-note problems are not returned as HTTP errors — the API accepts the send and the message is marked failed with a reason once the worker evaluates it. Check the message in your Unibox or via GET /api/messages. See When a voice note will not send.