UC-015 — Upload and Manage Media
| Field | Value |
|---|---|
| ID | UC-015 |
| Goal | Upload, list and remove media files from the library |
| Channel | RCS, WhatsApp |
| Complexity | Basic |
| Estimated time | 10 minutes |
| APIs involved | POST /api/partner-gateway/v1/media, GET /api/partner-gateway/v1/media, DELETE /api/partner-gateway/v1/media/{id} |
Real-world scenarios
- Upload image for RCS: FashionOutlet uploads images of the new collection to send them via RCS Rich Card.
- Manage media library: The TravelDream marketing team organizes its library of promotional images, checking which are still in use.
- Delete obsolete media: At the end of a campaign, the team removes seasonal images to keep the library tidy.
Media management flow
The diagram shows the media file lifecycle: upload, listing and removal.
Prerequisites
- Active API Key with media management permissions
- Image file in a supported format (JPEG, PNG, GIF -- max 5 MB)
- For RCS: recommended dimensions 1440x1440 px (square images) or 1440x720 px (landscape)
Step 1 — Upload a media file
Send the file via multipart form-data.
curl -X POST https://api.qlara.ai/api/partner-gateway/v1/media \
-H "X-Api-Key: YOUR_API_KEY" \
-F "file=@/path/to/promo-estate-2026.jpg" \
-F "name=promo-estate-2026" \
-F "description=Banner promozione estate 2026 - Collezione mare"
Response — Media uploaded
The response is an array with the created media:
[
{
"id": 5821,
"key": "5b0e72c4/3f9a1d7e6c2b48a59e0d1f7c8b6a4e21.jpg",
"thumbnailKey": "5b0e72c4/a7c4e19b2d5f40c3961e8b0d2f4a6c13.jpg",
"companyId": 1287,
"userId": 3410,
"name": "promo-estate-2026",
"description": "Banner promozione estate 2026 - Collezione mare",
"filename": "promo-estate-2026.jpg",
"size": 245760,
"type": "IMAGE",
"mimeType": "image/jpeg",
"source": 1,
"metadata": null,
"folderId": null,
"userEmail": null,
"userFirstName": null,
"userMiddleName": null,
"userLastName": null,
"url": "https://storage.example.com/5b0e72c4/3f9a1d7e6c2b48a59e0d1f7c8b6a4e21.jpg?X-Amz-Date=20260409T090000Z&X-Amz-Expires=3600&X-Amz-Signature=2bbf02e2c8274379a166bb6eb376bcbdb161455399b552eabd3c566b31777738",
"thumbnailUrl": "https://storage.example.com/5b0e72c4/a7c4e19b2d5f40c3961e8b0d2f4a6c13.jpg?X-Amz-Date=20260409T090000Z&X-Amz-Expires=3600&X-Amz-Signature=e9c171c6c46a3a250b4e2ba18f76cb7950e31017e7d87092c7cde91d4540d08b",
"cdnUrl": null,
"cdnThumbnailUrl": null,
"public": false,
"creationDate": "2026-04-09 09:00:00.000+0000",
"lastUpdateDate": "2026-04-09 09:00:00.000+0000"
}
]
The url field is a signed link to the file: pass it right away as mediaUrl in an RCS Rich Card, but don't save it in your CMS, because it expires. Save the id instead: when you need the link again, take the url of the same media from GET /media, which signs a new one at every call.
Behind the scenes — File processing
- Validation: The gateway verifies the MIME type, file size and image resolution.
- Optimization: The image is compressed while maintaining visual quality (JPEG quality 85%) and converted to optimal formats for each channel.
- Storage: The file is saved in the media storage under
key. Files uploaded through the API are private:urlandthumbnailUrlare signed links that expire, andcdnUrlstaysnull. - Thumbnail: A reduced version (300x300 px) is automatically generated for dashboard previews.
- Scanning: The file is analyzed to verify the absence of malicious content (malware scan).
Step 2 — List uploaded media
Retrieve the list of files in your media library. The list is paginated (page, limit, 10 items by default) and sorted by id in ascending order, unless you pass sortBy and sortOrder.
curl -X GET https://api.qlara.ai/api/partner-gateway/v1/media \
-H "X-Api-Key: YOUR_API_KEY"
Response — Media list
{
"data": [
{
"id": 5478,
"key": "5b0e72c4/c2e8f05a7d3b41f69a8e0c5d7b2f9e14.png",
"thumbnailKey": "5b0e72c4/e91b4d7c0a3f42e8b6d5c1a9f0e7d3b2.png",
"companyId": 1287,
"userId": 3410,
"name": "logo-brand-2026",
"description": null,
"filename": "logo-brand-2026.png",
"size": 52480,
"type": "IMAGE",
"mimeType": "image/png",
"source": 1,
"metadata": null,
"folderId": 214,
"userEmail": "chiara.verdi@example.it",
"userFirstName": "Chiara",
"userMiddleName": null,
"userLastName": "Verdi",
"url": "https://storage.example.com/5b0e72c4/c2e8f05a7d3b41f69a8e0c5d7b2f9e14.png?X-Amz-Date=20260409T093000Z&X-Amz-Expires=3600&X-Amz-Signature=6a23f4aaac740c71ca1c46aff614fe18db294e3fbbf2358db3a5a2c71d9ed24c",
"thumbnailUrl": "https://storage.example.com/5b0e72c4/e91b4d7c0a3f42e8b6d5c1a9f0e7d3b2.png?X-Amz-Date=20260409T093000Z&X-Amz-Expires=3600&X-Amz-Signature=ab09a190584dbfe3036f6817bab4c3ee15b5b5c3d878e63ddea5ab3098700ed6",
"cdnUrl": null,
"cdnThumbnailUrl": null,
"public": false,
"creationDate": "2026-03-15 08:30:00.000+0000",
"lastUpdateDate": "2026-03-15 08:30:00.000+0000"
},
{
"id": 5821,
"key": "5b0e72c4/3f9a1d7e6c2b48a59e0d1f7c8b6a4e21.jpg",
"thumbnailKey": "5b0e72c4/a7c4e19b2d5f40c3961e8b0d2f4a6c13.jpg",
"companyId": 1287,
"userId": 3410,
"name": "promo-estate-2026",
"description": "Banner promozione estate 2026 - Collezione mare",
"filename": "promo-estate-2026.jpg",
"size": 245760,
"type": "IMAGE",
"mimeType": "image/jpeg",
"source": 1,
"metadata": null,
"folderId": null,
"userEmail": "chiara.verdi@example.it",
"userFirstName": "Chiara",
"userMiddleName": null,
"userLastName": "Verdi",
"url": "https://storage.example.com/5b0e72c4/3f9a1d7e6c2b48a59e0d1f7c8b6a4e21.jpg?X-Amz-Date=20260409T093000Z&X-Amz-Expires=3600&X-Amz-Signature=a475228f13f075b0f51ce1615bc4eb5c3b8a46eb56551701cc70d82af0e15898",
"thumbnailUrl": "https://storage.example.com/5b0e72c4/a7c4e19b2d5f40c3961e8b0d2f4a6c13.jpg?X-Amz-Date=20260409T093000Z&X-Amz-Expires=3600&X-Amz-Signature=a3ac2131d57c6d2fcc79029fe246d9604f13e35c13711a19bcf689bc5f856c5e",
"cdnUrl": null,
"cdnThumbnailUrl": null,
"public": false,
"creationDate": "2026-04-09 09:00:00.000+0000",
"lastUpdateDate": "2026-04-09 09:00:00.000+0000"
}
],
"page": 0,
"limit": 10,
"totalCount": 2,
"totalPages": 1
}
Step 3 — Delete obsolete media
Remove a file from the library when it is no longer needed, using its id.
curl -X DELETE https://api.qlara.ai/api/partner-gateway/v1/media/5478 \
-H "X-Api-Key: YOUR_API_KEY"
Response — Media deleted
The API answers 204 No Content, with an empty body.
Behind the scenes — Deletion
- Permanent deletion: The file is removed from the library and from the media storage. The operation cannot be undone.
- Messages already sent: They are not affected, because the media content was delivered at send time.
- Future references: Any message or campaign that still references the deleted media will fail to resolve the file. Before deleting, make sure it is not used by a scheduled campaign or by a template that has not been sent yet.
- Refused deletions:
404if theidis not in your library,409if the media is public or still used by a social media post,400if the file is still being uploaded.
Expected result
| Step | Action | Result |
|---|---|---|
| 1 | POST /media | File uploaded, id, key and url returned |
| 2 | GET /media | Paginated media list with metadata |
| 3 | DELETE /media/{id} | Media removed, 204 No Content |
Complete end-to-end example
Scenario FashionOutlet: upload an image and use it in an RCS Rich Card.
# 1. Upload the promotional image
MEDIA_URL=$(curl -s -X POST https://api.qlara.ai/api/partner-gateway/v1/media \
-H "X-Api-Key: YOUR_API_KEY" \
-F "file=@./summer-collection.jpg" \
-F "name=summer-collection-2026" | jq -r '.[0].url')
echo "Media URL: $MEDIA_URL"
# 2. Verify it is in the library (newest first)
curl -s -X GET "https://api.qlara.ai/api/partner-gateway/v1/media?sortBy=id&sortOrder=desc" \
-H "X-Api-Key: YOUR_API_KEY" | jq '.data[] | select(.name == "summer-collection-2026")'
# 3. Use the URL in the RCS Rich Card right away (see UC-002): the link is signed and expires
echo "Ready for RCS sending with mediaUrl: $MEDIA_URL"
Variants
Upload a video
For channels that support video (RCS), upload MP4 files (max 10 MB):
curl -X POST https://api.qlara.ai/api/partner-gateway/v1/media \
-H "X-Api-Key: YOUR_API_KEY" \
-F "file=@/path/to/promo-video.mp4" \
-F "name=promo-video-estate" \
-F "description=Video promozionale 15 secondi"
Common errors
413 Payload Too Large — File too large
{
"status": "fail",
"data": {
"file": "File size exceeds maximum allowed (5 MB for images, 10 MB for videos)"
}
}
Solution: Compress the image or reduce its resolution. For RCS Rich Cards, 1440px width is sufficient.
415 Unsupported Media Type — Unsupported format
{
"status": "fail",
"data": {
"file": "Unsupported media type. Allowed: image/jpeg, image/png, image/gif, video/mp4"
}
}
Solution: Convert the file to one of the supported formats before uploading.
Next steps
- UC-002 — Send RCS Rich Card: Use the uploaded media in an RCS Rich Card
- UC-003 — Send WhatsApp Template: Associate media with WhatsApp templates
- UC-014 — API Key Management: Manage access keys