GET /v1/attachments/:id
Download the raw bytes of an attachment someone sent you.
GET /v1/attachments/{id}Returns the raw bytes of one inbound attachment. Ids come from
attachmentIds on a message frame,
whose attachments says what the sender's device declared about each file;
content-type on this response is read from the bytes. There is no CDN URL on
the frame.
Test mode carries no attachments, so with a test key this is always a 404.
Request
curl -o attachment.bin \
https://api.mapier.ai/v1/attachments/8f2c1a4e-... \
-H "Authorization: Bearer $MAPIER_API_KEY"The id is the whole path segment. There are no sub-paths and no size, format or thumbnail parameter, so a query string is ignored rather than selecting a rendition.
Conditional requests
Pass the etag you stored previously to skip re-downloading:
If-None-Match: "9f3c...64hex"A match returns 304 Not Modified with no body.
Response
HTTP/1.1 200 OK
content-type: image/heic
content-length: 1048576
etag: "9f3c...64hex"
cache-control: private, max-age=31536000, immutableThe response carries these four headers:
Prop
Type
There is no content-disposition, so no filename: the frame carries none
either, and a client names the file itself.
Files are served as sent. iPhone photos commonly arrive as HEIC, which browsers other than Safari cannot display. Convert server-side if you need to render them.
Lifetime and access
The URL is permanent and unsigned — it is not a presigned link that expires. Access is controlled by your credential on every request, so the URL is safe to store but not safe to hand to a browser or a third party as-is.
An attachment belonging to another account returns 404, identical to one that
does not exist. Existence is never leaked.
An attachment that has not finished transferring also returns 404; retry
shortly.
No maximum download size is surfaced to callers. Stream large responses rather than buffering them if you cannot bound the size.
Errors
| Status | Code | Cause |
|---|---|---|
400 | bad_request | The id could not be decoded |
401 | invalid_credentials | No key, or one that is unknown, revoked or expired |
404 | not_found | Unknown attachment, another account's, or not yet available |
409 | project_archived | The project is archived |
422 | validation_failed | An x-mapier-version this build does not answer to |
429 | rate_limited | 120 requests per minute, per key; the Retry-After header says how long to wait (a transport's own rate limit may give details.retryAfter instead) |
500 | internal_error | An unhandled failure, reported; details.requestId names the log line when present |
503 | line_unavailable · upstream_unavailable | The line holding it cannot serve it right now, or the transport did not answer |
503 | service_busy | The platform had no database connection free in time and did nothing; wait details.retryAfter seconds and fetch again |