Skip to main content

Attachments

This page explains how attachments work, storage rules, validation and ways to include them in messages.

Ways to Add Attachments

MethodEndpointUse CaseNotes
Inline URL shortcutPOST /messageQuick add of a single media via imageUrl / videoUrl / gifUrlCreates transient attachment objects (not persisted if saveOnServer=false).
JSON attachments arrayPOST /messageMultiple attachments or fine-grained controlProvide objects with mediaType + url OR attachmentUuid.
Uploaded file (multipart)POST /messageDirect file uploadReturns a message with linked stored attachment.
Reuse stored filePOST /messageReference existing attachmentUuidAvoids re-upload / re-download.

Uploading a File (Multipart Endpoint)

When you need to attach a binary file directly you can use the multipart endpoint instead of crafting an attachments array manually.

Endpoint: POST /message Open in API Reference ↗

Example:

curl -X POST http://localhost:3001/message \
-H "Authorization: Bearer zat_<raw-token>" \
-F "title=Invoice" \
-F "bucketId=<bucket-uuid>" \
-F "deliveryType=NORMAL" \
-F "attachment=@invoice.pdf"

Notes:

  • Booleans can be passed as true/false strings (they are transformed server-side).
  • You can still mix a JSON attachments array plus the uploaded file if you need multiple attachments.
  • To reuse a previously uploaded file, call the JSON endpoint with attachmentUuid instead.

Attachments API Reference

Use these endpoints when you want to upload or register files ahead of time and later reference them by attachmentUuid inside a message attachments array.

PurposeMethod & PathRefNotes
Upload file (multipart)POST /api/v1/attachments/uploadAPI ↗Form field: file; optional filename, mediaType (auto-detected if omitted).
Download & persist from URLPOST /api/v1/attachments/download-from-urlAPI ↗Server fetches remote file; optional filename, mediaType.
Get one (metadata)GET /api/v1/attachments/{id}API ↗Returns metadata (auth required).
Download (auth)GET /api/v1/attachments/{id}/downloadAPI ↗Binary stream (requires auth).
Download (public)GET /api/v1/attachments/{id}/download/publicAPI ↗Only for public attachments (linked to message or bucket ICON).
List by messageGET /api/v1/attachments/message/{messageId}API ↗Inspect attachments after message creation.
DeleteDELETE /api/v1/attachments/{id}API ↗Permanently removes attachment (breaks references).

Auth: All endpoints require Authorization: Bearer <jwt-access-token> or an access token (zat_...) except the explicit public download.

Upload Example

curl -X POST http://localhost:3001/api/v1/attachments/upload \
-H "Authorization: Bearer <jwt-access-token>" \
-F "file=@banner.png" \
-F "filename=banner.png" \
-F "mediaType=IMAGE"

Response (excerpt):

{
"id": "<attachment-uuid>",
"filename": "banner.png",
"mediaType": "IMAGE"
}

Download & Persist From Remote URL

curl -X POST http://localhost:3001/api/v1/attachments/download-from-url \
-H "Authorization: Bearer <jwt-access-token>" \
-H "Content-Type: application/json" \
-d '{"url":"https://example.com/image.png","filename":"promo.png","mediaType":"IMAGE"}'

Reference in a Message

{
"title": "Promo Available",
"bucketId": "<bucket-uuid>",
"deliveryType": "NORMAL",
"attachments": [
{ "attachmentUuid": "<attachment-uuid>", "mediaType": "IMAGE" }
]
}

Notes

  • If both url and attachmentUuid are provided in a single attachment object, attachmentUuid wins.
  • To persist a remote file inline (without pre-upload) you can use attachments[].url + saveOnServer=true directly in the message body.
  • Public download succeeds only for attachments considered public (linked to a message or bucket icon). Otherwise use the authenticated download endpoint.

Attachment Object

Either url or attachmentUuid must be provided (mutually exclusive).

FieldTypeRequiredDescription
mediaTypeenum MediaTypeYesOne of: VIDEO, IMAGE, GIF, AUDIO, ICON (ICON also fallback for generic/docs).
namestringNoFriendly display name (filename).
urlstringConditionalRemote URL to fetch/display. Can't be used with attachmentUuid.
attachmentUuidstringConditionalExisting stored attachment ID. Can't be used with url.
saveOnServerbooleanNoIf true with url, server downloads and persists a copy (requires attachments enabled).

Validation errors occur if both or neither of url and attachmentUuid are supplied.

Storage Layout

Files are persisted under a per-user, per-media-type, per-attachment folder structure:

/attachments/<userId>/<mediaType>/<attachmentId>/<attachmentId>.<ext>

Bucket icons may automatically be injected as an ICON attachment if present and not duplicated.

File Size & Types

Defaults (overridable by env):

  • Max size: ATTACHMENTS_MAX_FILE_SIZE (default 10MB)
  • Allowed MIME types: ATTACHMENTS_ALLOWED_MIME_TYPES (image/jpeg, image/png, image/gif, image/webp, video/mp4, video/webm, audio/mpeg, audio/wav, audio/ogg, application/pdf, text/plain)

If the MIME type or size fails validation a 400 is returned.

Public Access

Only attachments linked to a message OR bucket icon type (ICON) are publicly accessible through any public endpoint (if exposed). Others remain private.

Automatic URL Shortcuts

Shortcuts convert single URLs into implicit attachments:

  • imageUrl => IMAGE attachment
  • videoUrl => VIDEO attachment
  • gifUrl => GIF attachment

These are merged with explicitly provided attachments if both forms are used.

Download & Persist Remote URL

Set saveOnServer: true on a URL-based attachment to have the server fetch and store the file, replacing url with a generated attachmentUuid.

Reusing Attachments

To reuse a file in multiple messages:

  1. Upload once (multipart or URL + saveOnServer)
  2. Reference via attachmentUuid in subsequent message payloads

Cleanup

A background cleanup job can remove old attachments (excluding ICON) based on retention settings. Ensure you don't rely on very old unreferenced files.

Example Payload (Mixed)

{
"title": "Release Media",
"bucketId": "<bucket-uuid>",
"deliveryType": "NORMAL",
"attachments": [
{ "mediaType": "IMAGE", "url": "https://example.com/banner.png", "saveOnServer": true },
{ "mediaType": "AUDIO", "attachmentUuid": "<existing-audio-uuid>", "name": "Theme" }
],
"videoUrl": "https://cdn.example.com/teaser.mp4"
}

Troubleshooting

SymptomLikely CauseFix
400 both url & attachmentUuidProvided both fieldsRemove one of them
400 invalid mediaTypeTypo or unsupported valueUse an enum value exactly as listed
400 file size exceedsFile > max sizeIncrease env limit or compress file
Attachment not visibleNot linked to message and not ICONEnsure message linkage or mediaType ICON
Download timeoutRemote host slow/unreachableHost file on faster CDN or retry

Return to main notifications: Notifications Overview