Skip to main content

UC-015 — Upload and Manage Media

FieldValue
IDUC-015
GoalUpload, list and remove media files from the library
ChannelRCS, WhatsApp
ComplexityBasic
Estimated time10 minutes
APIs involvedPOST /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"
}
]
Use the URL in RCS messages

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
  1. Validation: The gateway verifies the MIME type, file size and image resolution.
  2. Optimization: The image is compressed while maintaining visual quality (JPEG quality 85%) and converted to optimal formats for each channel.
  3. Storage: The file is saved in the media storage under key. Files uploaded through the API are private: url and thumbnailUrl are signed links that expire, and cdnUrl stays null.
  4. Thumbnail: A reduced version (300x300 px) is automatically generated for dashboard previews.
  5. 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
  1. Permanent deletion: The file is removed from the library and from the media storage. The operation cannot be undone.
  2. Messages already sent: They are not affected, because the media content was delivered at send time.
  3. 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.
  4. Refused deletions: 404 if the id is not in your library, 409 if the media is public or still used by a social media post, 400 if the file is still being uploaded.

Expected result​

StepActionResult
1POST /mediaFile uploaded, id, key and url returned
2GET /mediaPaginated media list with metadata
3DELETE /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​

References​