Sending a file
1
Create the attachment
POST /v1/attachments with the file’s filename, content_type and size_bytes. The response contains the attachment id, an upload_url and the required_headers of the upload.2
Upload the file
Send the bytes with one HTTP
PUT to upload_url, with the headers of required_headers, before upload_expires_at: 15 minutes after the create call.3
Wait until the attachment is ready
Read
GET /v1/attachments/{id} until status is ready. iSnap checks for the uploaded file every 30 seconds.4
Send it
Pass the
id in the attachments of POST /v1/messages. Send one attachment per message.attachments.upload, that runs the first three steps. Its default wait can end before iSnap sees an upload that succeeded: see The attachments helper.
Creating an attachment
POST /v1/attachments takes:
The response is
201 with id, upload_url, upload_expires_at, required_headers, status: awaiting_upload and warnings. Above 100,000,000 bytes the call succeeds, and warnings holds large_attachment_may_delay_delivery.
Idempotency-Key, and the key belongs to your account. While the first attachment is still awaiting_upload and before its deadline, a repeat with the same key returns the same id, with a new upload_url and a new 15-minute deadline. The body of the repeat is not compared with the first. In any other state, the key returns 409 idempotency_terminal_state: create the attachment again with a new key. See Attachments in Idempotency.
Uploading the file
Upload the bytes with one HTTPPUT to upload_url, with the headers listed in required_headers (content-type and content-length), before upload_expires_at. The file goes to that URL and does not pass through the iSnap API: do not send your API key with it.
iSnap does not compare the uploaded bytes with the size_bytes and the content_type you declared. The attachment, and the messages that carry it, show the values you declared. An audio file is the exception: see Audio files.
Statuses
iSnap checks for the uploaded file every 30 seconds. When it finds the file,
status changes from awaiting_upload to ready, or to transcoding for an audio file, and uploaded_at is set. When no file is there at the upload deadline, status becomes failed: create the attachment again. No event announces these changes: read the attachment with GET /v1/attachments/{id}.
Wait for status: ready before you send an attachment. iSnap does not check the status when it accepts a send. An attachment that is not ready when the line’s device takes the message is left out of the message, without an error: an upload not finished, an audio file still converting, a failed attachment and an expired one alike. The message goes out without that file. When the message has no body, iSnap does not define what the line’s device does with it.
Audio files
iSnap converts every file whosecontent_type starts with audio/ to a mono CAF file before it is ready. After the conversion, the attachment reads content_type: audio/x-caf, size_bytes is the size of the converted file, and duration_ms is its duration in milliseconds. duration_ms is null on every other file.
An audio file larger than 52,428,800 bytes (50 MiB), or one that iSnap fails to convert after 3 attempts, becomes failed.
A send with one audio attachment and no body is a voice note: see Voice notes.
Downloading a file
GET /v1/attachments/{id} returns id, filename, content_type, size_bytes, status, download_url, download_expires_at, duration_ms, created_at, uploaded_at, expires_at and warnings.
download_urlis a signed URL, valid 15 minutes, untildownload_expires_at. It is set only whenstatusisready: otherwise it anddownload_expires_atarenull. Call the operation again for a new URL.uploaded_atisnulluntil iSnap has seen the file.- An API key of your account can read the attachments that the account created, and the files received on the inbound messages of its lines. Any other id returns
404 not_found.
attachments, each as { id, content_type, filename, size_bytes, duration_ms }, with no download URL: read each one with this operation.
Retention
An attachment expires 72 hours afterPOST /v1/attachments created it, at expires_at, whether or not it was uploaded or sent. From then on, GET /v1/attachments/{id} returns 410 attachment_expired, and iSnap deletes the file. iSnap keeps the record of the attachment, with its file name, content type and size.
Create an attachment close to the send that uses it. A held message whose attachment expires before the message leaves goes out without it.
How the device sends a file
This section describes iMessage lines. iSnap makes no statement on this page about what the device of an Android line does with a file.- One file per message. The line’s device sends only the first attachment of a message. The other files are not sent, and the message is still reported
sent. Send one attachment per message. - Download. The device downloads every file of the message before it sends it, with 3 attempts per file. A file that it cannot download within 5 minutes, or whose link expired, makes the whole message fail.
- Caption. The
bodyof the message can arrive as a caption in the same bubble as the file, or as a separate message after the file. Write abodythat reads well both ways. - Conversion. The device can send the file unchanged, or convert it first, by file extension:
A file sent as SMS or RCS can be converted, and its caption can arrive separately. A conversion has 30 seconds: when it fails, the device tries the send once more, then the message fails. The contact sees the original file name; after a conversion its extension changes, so that
photo.heic arrives as photo.jpg.
An effect is never applied to a message that carries an attachment: the message goes out without it.
Voice notes
A send with nobody and exactly one attachment whose content type starts with audio/ is a voice note, with kind: voice. The line’s device sends it as a voice message when it supports voice notes: rented iMessage lines do, and a BYOD line does when reactions_out is active on GET /v1/lines/{id}/health. Otherwise the voice note fails. To send the same audio file as an ordinary attachment, add a body.
- When there is no Messages conversation with the contact on the device, and the device cannot open one, it sends the voice note as an ordinary audio file.
- To a contact who is not on iMessage, it goes as an audio file over SMS or RCS when the line has that route, and fails when it does not. See Services and fallback.
- Audio that the device cannot turn into a voice message makes the voice note fail.
- A voice note is never shown as a threaded reply, and
use_typing_indicatorhas no effect on it.
Inbound attachments
The files received with an inbound message are listed in itsattachments. Read each one with GET /v1/attachments/{id}, which returns its download_url once it is ready. A received file cannot go in the attachments of POST /v1/messages: its id returns 404 not_found.
A received file expires 72 hours after iSnap registered it, at expires_at. Copy it to your own storage before then: after it, GET /v1/attachments/{id} returns 410 attachment_expired.
What the line’s device does with a received file:
- It uploads the file unchanged: a
heicphoto staysheic, and a voice message arrives as anaudio/x-caffile. A file whose type the device cannot name has the content typeapplication/octet-stream. - It accepts at most 20 files per message, of at most 5 GiB each.
- It reports the message only after every file is uploaded. It waits up to 60 seconds per file for Apple to finish downloading it, and makes up to 3 upload attempts. The later messages of the line wait meanwhile.
- When one file is not available within 60 seconds, or cannot be uploaded, the device does not report the message at all: the text is lost with the file, and no event is sent.
- A sticker that a contact places on a message arrives as a received message that carries the sticker file, not as a reaction.
Errors
The refusals of each operation are on its reference page:POST /v1/attachments and GET /v1/attachments/{id}. An attachment id that a send cannot use is refused by POST /v1/messages. The errors that every operation shares are in Errors.
Personal data
Files and their names can hold personal data: a photo, a document, the name of a person in a file name. Request a file only when needed, and do not copy it, its name or its URLs into logs, tickets or other tools. Treatupload_url and download_url as secrets for as long as they are valid.