API reference
Integrations API v1
Each endpoint's method, scope, parameters, response and errors, generated from openapi.json. The address is https://cms.drmn.app/api/integrations/v1; send Authorization: Bearer dcmi_… with every request.
List ready media, newest first
GET/mediaScope media:read
Needs the media:read scope. With media:files too, each media item carries fileUrl.
Parameters
| Name | In | Type | Description |
|---|---|---|---|
cursor | query | string | The nextCursor of the previous page. |
limit | query | integer | 1–200, default 50 |
tag | query | string (uuid)[] | A tag id from GET /tags. Repeat it to require every tag listed. |
q | query | string | Matches the media's name or description, ignoring case. (at most 200 characters) |
Example
curl -s https://cms.drmn.app/api/integrations/v1/media \
-H "Authorization: Bearer $DIGICMS_INTEGRATION_TOKEN"
Response 200 MediaPage
| Field | Type | Description | |
|---|---|---|---|
items | Media[] | required | |
nextCursor | string | null | required | Pass as cursor for the next page; null on the last page. |
{
"items": [
{
"id": "0192f0c4-7a3c-7b1d-9e2f-3a4b5c6d7e8f",
"name": "Autumn menu",
"type": "image",
"width": 1920,
"height": 1080,
"durationSeconds": 15,
"tags": [
{
"id": "0192f0c4-7a3c-7b1d-9e2f-3a4b5c6d7e8f",
"name": "Autumn menu"
}
],
"thumbnailUrl": "https://…",
"createdAt": "2026-10-17T08:00:00.000Z",
"fileUrl": "https://…"
}
],
"nextCursor": null
}
Errors
| Status | When |
|---|---|
400 Bad Request | A query parameter is not valid. |
401 Unauthorized | The token is missing, unknown, expired or revoked, or its merchant is suspended or its plan has ended. |
403 Forbidden | The token lacks the scope this endpoint needs; the message names it. |
429 Too Many Requests | More than 120 requests in a minute with this token. |
One media item
GET/media/{id}Scope media:read
Needs the media:read scope. With media:files too, each media item carries fileUrl.
Parameters
| Name | In | Type | Description |
|---|---|---|---|
id | path (required) | string (uuid) | A media id. |
Example
curl -s https://cms.drmn.app/api/integrations/v1/media/0192f0c4-7a3c-7b1d-9e2f-3a4b5c6d7e8f \
-H "Authorization: Bearer $DIGICMS_INTEGRATION_TOKEN"
Response 200 Media
| Field | Type | Description | |
|---|---|---|---|
id | string (uuid) | required | |
name | string | required | |
type | "image" | "video" | "web" | required | |
width | integer | null | required | Pixels; null when unknown (and for web pages). |
height | integer | null | required | Pixels; null when unknown (and for web pages). |
durationSeconds | number | null | required | A video's length; null for images and web pages. |
tags | Tag[] | required | |
thumbnailUrl | string (uri) | null | required | A signed URL that stops working 15 minutes after the response; null when there is no thumbnail. |
createdAt | string (date-time) | required | |
fileUrl | string (uri) | null | optional | Only with the media:files scope. The file itself: a signed URL that stops working 15 minutes after the response, or a web page's own address. Absent without that scope. |
{
"id": "0192f0c4-7a3c-7b1d-9e2f-3a4b5c6d7e8f",
"name": "Autumn menu",
"type": "image",
"width": 1920,
"height": 1080,
"durationSeconds": 15,
"tags": [
{
"id": "0192f0c4-7a3c-7b1d-9e2f-3a4b5c6d7e8f",
"name": "Autumn menu"
}
],
"thumbnailUrl": "https://…",
"createdAt": "2026-10-17T08:00:00.000Z",
"fileUrl": "https://…"
}
Errors
| Status | When |
|---|---|
401 Unauthorized | The token is missing, unknown, expired or revoked, or its merchant is suspended or its plan has ended. |
403 Forbidden | The token lacks the scope this endpoint needs; the message names it. |
404 Not Found | No such item in the token's merchant. |
429 Too Many Requests | More than 120 requests in a minute with this token. |
List campaigns (not archived), most recently changed first
GET/campaignsScope campaigns:read
Needs the campaigns:read scope.
Parameters
| Name | In | Type | Description |
|---|---|---|---|
cursor | query | string | The nextCursor of the previous page. |
limit | query | integer | 1–200, default 50 |
tag | query | string (uuid)[] | A tag id from GET /tags. Repeat it to require every tag listed. |
q | query | string | Matches the campaign's name, ignoring case. (at most 200 characters) |
Example
curl -s https://cms.drmn.app/api/integrations/v1/campaigns \
-H "Authorization: Bearer $DIGICMS_INTEGRATION_TOKEN"
Response 200 CampaignPage
| Field | Type | Description | |
|---|---|---|---|
items | Campaign[] | required | |
nextCursor | string | null | required | Pass as cursor for the next page; null on the last page. |
{
"items": [
{
"lineageId": "0192f0c4-1b2c-7d3e-8f4a-5b6c7d8e9f0a",
"name": "Autumn menu",
"status": "running",
"flight": {
"start": "Autumn",
"end": "Autumn"
},
"tags": [
{
"id": "0192f0c4-7a3c-7b1d-9e2f-3a4b5c6d7e8f",
"name": "Autumn menu"
}
]
}
],
"nextCursor": null
}
Errors
| Status | When |
|---|---|
400 Bad Request | A query parameter is not valid. |
401 Unauthorized | The token is missing, unknown, expired or revoked, or its merchant is suspended or its plan has ended. |
403 Forbidden | The token lacks the scope this endpoint needs; the message names it. |
429 Too Many Requests | More than 120 requests in a minute with this token. |
One campaign, with the media it plays
GET/campaigns/{lineageId}Scope campaigns:read
Needs the campaigns:read scope.
Parameters
| Name | In | Type | Description |
|---|---|---|---|
lineageId | path (required) | string (uuid) | A campaign's lineage id. |
Example
curl -s https://cms.drmn.app/api/integrations/v1/campaigns/0192f0c4-1b2c-7d3e-8f4a-5b6c7d8e9f0a \
-H "Authorization: Bearer $DIGICMS_INTEGRATION_TOKEN"
Response 200 CampaignDetail
| Field | Type | Description | |
|---|---|---|---|
lineageId | string (uuid) | required | The campaign's stable id: it stays the same across versions. |
name | string | required | |
status | "running" | "upcoming" | "draft" | "ended" | "withdrawn" | required | running, upcoming or ended while live; else draft (never published) or withdrawn. |
flight | object | required | The live version's flight, else the newest version's. |
tags | Tag[] | required | |
mediaIds | string (uuid)[] | required | The media the live version plays (landscape and portrait), in play order, each once; empty when nothing is live. |
content | object | null | required | The live version's content in play order; null when nothing is live. |
{
"lineageId": "0192f0c4-1b2c-7d3e-8f4a-5b6c7d8e9f0a",
"name": "Autumn menu",
"status": "running",
"flight": {
"start": "Autumn",
"end": "Autumn"
},
"tags": [
{
"id": "0192f0c4-7a3c-7b1d-9e2f-3a4b5c6d7e8f",
"name": "Autumn menu"
}
],
"mediaIds": [
"0192f0c4-7a3c-7b1d-9e2f-3a4b5c6d7e8f"
],
"content": {
"landscape": {
"playlistId": "0192f0c4-2c3d-7e4f-9a5b-6c7d8e9f0a1b",
"items": [
{
"mediaId": "0192f0c4-7a3c-7b1d-9e2f-3a4b5c6d7e8f",
"type": "image",
"durationSeconds": 15
}
]
},
"portrait": null
}
}
Errors
| Status | When |
|---|---|
401 Unauthorized | The token is missing, unknown, expired or revoked, or its merchant is suspended or its plan has ended. |
403 Forbidden | The token lacks the scope this endpoint needs; the message names it. |
404 Not Found | No such item in the token's merchant. |
429 Too Many Requests | More than 120 requests in a minute with this token. |
List shared playlists, most recently updated first
GET/playlistsScope playlists:read
Needs the playlists:read scope.
Parameters
| Name | In | Type | Description |
|---|---|---|---|
cursor | query | string | The nextCursor of the previous page. |
limit | query | integer | 1–200, default 50 |
q | query | string | Matches the playlist's name, ignoring case. (at most 200 characters) |
Example
curl -s https://cms.drmn.app/api/integrations/v1/playlists \
-H "Authorization: Bearer $DIGICMS_INTEGRATION_TOKEN"
Response 200 PlaylistPage
| Field | Type | Description | |
|---|---|---|---|
items | Playlist[] | required | |
nextCursor | string | null | required | Pass as cursor for the next page; null on the last page. |
{
"items": [
{
"id": "0192f0c4-7a3c-7b1d-9e2f-3a4b5c6d7e8f",
"name": "Autumn menu",
"createdAt": "2026-10-17T08:00:00.000Z",
"updatedAt": "2026-10-17T08:00:00.000Z"
}
],
"nextCursor": null
}
Errors
| Status | When |
|---|---|
400 Bad Request | A query parameter is not valid. |
401 Unauthorized | The token is missing, unknown, expired or revoked, or its merchant is suspended or its plan has ended. |
403 Forbidden | The token lacks the scope this endpoint needs; the message names it. |
429 Too Many Requests | More than 120 requests in a minute with this token. |
One playlist with its items in play order
GET/playlists/{id}Scope playlists:read
Needs the playlists:read scope.
Parameters
| Name | In | Type | Description |
|---|---|---|---|
id | path (required) | string (uuid) | A playlist id, e.g. a campaign's content.landscape.playlistId. |
Example
curl -s https://cms.drmn.app/api/integrations/v1/playlists/0192f0c4-7a3c-7b1d-9e2f-3a4b5c6d7e8f \
-H "Authorization: Bearer $DIGICMS_INTEGRATION_TOKEN"
Response 200 PlaylistDetail
| Field | Type | Description | |
|---|---|---|---|
id | string (uuid) | required | |
name | string | required | |
createdAt | string (date-time) | required | |
updatedAt | string (date-time) | required | |
totalDurationSeconds | number | required | |
items | PlayItem[] | required | In play order. |
{
"id": "0192f0c4-7a3c-7b1d-9e2f-3a4b5c6d7e8f",
"name": "Autumn menu",
"createdAt": "2026-10-17T08:00:00.000Z",
"updatedAt": "2026-10-17T08:00:00.000Z",
"totalDurationSeconds": 45,
"items": [
{
"mediaId": "0192f0c4-7a3c-7b1d-9e2f-3a4b5c6d7e8f",
"type": "image",
"durationSeconds": 15
}
]
}
Errors
| Status | When |
|---|---|
401 Unauthorized | The token is missing, unknown, expired or revoked, or its merchant is suspended or its plan has ended. |
403 Forbidden | The token lacks the scope this endpoint needs; the message names it. |
404 Not Found | No such item in the token's merchant. |
429 Too Many Requests | More than 120 requests in a minute with this token. |
Start uploading a file to the media library
POST/media/uploadsScope media:write
Needs the media:write scope. Then PUT the file (and thumbnail) to the returned URLs and call finalize. Uploading an exact file the merchant already has returns duplicateOf and nothing to upload.
Request body UploadRequest
| Field | Type | Description | |
|---|---|---|---|
id | string (uuid) | required | Your id for this file, a UUID (v7 is best). Sending the same id again is a safe retry: it never adds a second item. |
name | string | required | The name shown in the media library. (at most 200 characters) |
fileName | string | required | at most 500 characters |
mimeType | string | required | image/jpeg, image/png, image/webp, video/mp4 or video/webm. |
fileSize | integer | required | Bytes. Images up to 50 MB, videos up to 2 GB. |
checksum | string | required | The file's SHA-256, lower-case hex. |
duration | number | null | optional | A video's length in seconds. |
width | integer | null | optional | |
height | integer | null | optional | |
hasThumbnail | boolean | optional | True when you will PUT a JPEG thumbnail (480 px wide is best) too. |
thumbnailSize | integer | null | optional | The thumbnail's bytes, at most 1 MB; required with hasThumbnail. |
codec | string | null | optional | A video's codec (h264, hevc, …); only used for warnings. (at most 50 characters) |
Example
curl -s -X POST https://cms.drmn.app/api/integrations/v1/media/uploads \
-H "Authorization: Bearer $DIGICMS_INTEGRATION_TOKEN" \
-H "Content-Type: application/json" \
-d '{"id":"0192f0c4-7a3c-7b1d-9e2f-3a4b5c6d7e8f","name":"Autumn menu","fileName":"autumn-menu.jpg","mimeType":"image/jpeg","fileSize":245760,"checksum":"9f86d081884c7d659a2feaa0c55ad015a3bf4f1b2b0b822cd15d6c15b0f00a08","duration":15,"width":1920,"height":1080,"hasThumbnail":true,"thumbnailSize":18432,"codec":"h264"}'
Response 200 UploadTicket
| Field | Type | Description | |
|---|---|---|---|
mediaId | string (uuid) | required | The item's id: yours, or the existing item's when duplicateOf is set. |
duplicateOf | object | null | required | Set when the merchant already has this exact file: nothing to upload or finalize, use mediaId. |
upload | object | null | required | Where to PUT the file; null for a duplicate. |
thumbnailUpload | object | null | required | Where to PUT the thumbnail; null without one. |
warnings | object[] | required | Video compatibility warnings for the merchant's screens. Never blocking. |
{
"mediaId": "0192f0c4-7a3c-7b1d-9e2f-3a4b5c6d7e8f",
"duplicateOf": {
"id": "0192f0c4-7a3c-7b1d-9e2f-3a4b5c6d7e8f",
"name": "Autumn menu",
"type": "image"
},
"upload": null,
"thumbnailUpload": null,
"warnings": [
{
"code": "Autumn",
"message": "This token does not have the media:write scope this endpoint needs."
}
]
}
Errors
| Status | When |
|---|---|
400 Bad Request | The body is not valid JSON or not what this endpoint takes; the message names the fields. |
401 Unauthorized | The token is missing, unknown, expired or revoked, or its merchant is suspended or its plan has ended. |
403 Forbidden | The token lacks the scope this endpoint needs, or the merchant's plan does not allow it (code: plan). |
409 Conflict | code: storage_quota_exceeded: the merchant's storage is full. code: id_conflict: the id is another item's. |
413 Payload Too Large | The body is larger than 16 KB. |
422 Unprocessable | The file is not accepted: type, size, checksum or name; the message says which. |
429 Too Many Requests | More than 30 writes in a minute with this token (counted apart from reads). |
Finish an upload: the item becomes ready
POST/media/uploads/{id}/finalizeScope media:write
Needs the media:write scope. Checks that the file was stored with the declared size. Returns the item as GET /media/{id} does. Finalizing a ready item again returns it.
Parameters
| Name | In | Type | Description |
|---|---|---|---|
id | path (required) | string (uuid) | The mediaId from POST /media/uploads. |
Example
curl -s -X POST https://cms.drmn.app/api/integrations/v1/media/uploads/0192f0c4-7a3c-7b1d-9e2f-3a4b5c6d7e8f/finalize \
-H "Authorization: Bearer $DIGICMS_INTEGRATION_TOKEN"
Response 200 Media
| Field | Type | Description | |
|---|---|---|---|
id | string (uuid) | required | |
name | string | required | |
type | "image" | "video" | "web" | required | |
width | integer | null | required | Pixels; null when unknown (and for web pages). |
height | integer | null | required | Pixels; null when unknown (and for web pages). |
durationSeconds | number | null | required | A video's length; null for images and web pages. |
tags | Tag[] | required | |
thumbnailUrl | string (uri) | null | required | A signed URL that stops working 15 minutes after the response; null when there is no thumbnail. |
createdAt | string (date-time) | required | |
fileUrl | string (uri) | null | optional | Only with the media:files scope. The file itself: a signed URL that stops working 15 minutes after the response, or a web page's own address. Absent without that scope. |
{
"id": "0192f0c4-7a3c-7b1d-9e2f-3a4b5c6d7e8f",
"name": "Autumn menu",
"type": "image",
"width": 1920,
"height": 1080,
"durationSeconds": 15,
"tags": [
{
"id": "0192f0c4-7a3c-7b1d-9e2f-3a4b5c6d7e8f",
"name": "Autumn menu"
}
],
"thumbnailUrl": "https://…",
"createdAt": "2026-10-17T08:00:00.000Z",
"fileUrl": "https://…"
}
Errors
| Status | When |
|---|---|
400 Bad Request | The body is not valid JSON or not what this endpoint takes; the message names the fields. |
401 Unauthorized | The token is missing, unknown, expired or revoked, or its merchant is suspended or its plan has ended. |
403 Forbidden | The token lacks the scope this endpoint needs, or the merchant's plan does not allow it (code: plan). |
404 Not Found | No such upload in the token's merchant. |
413 Payload Too Large | The body is larger than 16 KB. |
422 Unprocessable | The file was not stored, or not with the declared size; PUT it again. |
429 Too Many Requests | More than 30 writes in a minute with this token (counted apart from reads). |
Add tags to a media item
POST/media/{id}/tagsScope tags:write
Needs the tags:write scope. Up to 10 names a call. Only adds: taking tags off is not offered.
Parameters
| Name | In | Type | Description |
|---|---|---|---|
id | path (required) | string (uuid) | A media id. |
Request body AddTagsRequest
| Field | Type | Description | |
|---|---|---|---|
add | string[] | required | Tag names. A name the merchant already has (ignoring case and spacing) reuses that tag; others are created. (1–10 items) |
Example
curl -s -X POST https://cms.drmn.app/api/integrations/v1/media/0192f0c4-7a3c-7b1d-9e2f-3a4b5c6d7e8f/tags \
-H "Authorization: Bearer $DIGICMS_INTEGRATION_TOKEN" \
-H "Content-Type: application/json" \
-d '{"add":["Autumn","Group buy"]}'
Response 200 AddTagsResult
| Field | Type | Description | |
|---|---|---|---|
mediaId | string (uuid) | required | |
tags | Tag[] | required | The tags the names resolved to. |
added | integer | required | How many of them the item did not have yet. |
{
"mediaId": "0192f0c4-7a3c-7b1d-9e2f-3a4b5c6d7e8f",
"tags": [
{
"id": "0192f0c4-7a3c-7b1d-9e2f-3a4b5c6d7e8f",
"name": "Autumn menu"
}
],
"added": 1
}
Errors
| Status | When |
|---|---|
400 Bad Request | The body is not valid JSON or not what this endpoint takes; the message names the fields. |
401 Unauthorized | The token is missing, unknown, expired or revoked, or its merchant is suspended or its plan has ended. |
403 Forbidden | The token lacks the scope this endpoint needs, or the merchant's plan does not allow it (code: plan). |
404 Not Found | No such media item in the token's merchant. |
413 Payload Too Large | The body is larger than 16 KB. |
422 Unprocessable | The body asks to remove tags, or the item would have too many tags. |
429 Too Many Requests | More than 30 writes in a minute with this token (counted apart from reads). |
List tags by name
GET/tagsScope tags:read
Needs the tags:read scope.
Parameters
| Name | In | Type | Description |
|---|---|---|---|
cursor | query | string | The nextCursor of the previous page. |
limit | query | integer | 1–200, default 50 |
q | query | string | Matches the tag's name, ignoring case. (at most 200 characters) |
Example
curl -s https://cms.drmn.app/api/integrations/v1/tags \
-H "Authorization: Bearer $DIGICMS_INTEGRATION_TOKEN"
Response 200 TagPage
| Field | Type | Description | |
|---|---|---|---|
items | Tag[] | required | |
nextCursor | string | null | required | Pass as cursor for the next page; null on the last page. |
{
"items": [
{
"id": "0192f0c4-7a3c-7b1d-9e2f-3a4b5c6d7e8f",
"name": "Autumn menu"
}
],
"nextCursor": null
}
Errors
| Status | When |
|---|---|
400 Bad Request | A query parameter is not valid. |
401 Unauthorized | The token is missing, unknown, expired or revoked, or its merchant is suspended or its plan has ended. |
403 Forbidden | The token lacks the scope this endpoint needs; the message names it. |
429 Too Many Requests | More than 120 requests in a minute with this token. |
Shared objects
Media
| Field | Type | Description | |
|---|---|---|---|
id | string (uuid) | required | |
name | string | required | |
type | "image" | "video" | "web" | required | |
width | integer | null | required | Pixels; null when unknown (and for web pages). |
height | integer | null | required | Pixels; null when unknown (and for web pages). |
durationSeconds | number | null | required | A video's length; null for images and web pages. |
tags | Tag[] | required | |
thumbnailUrl | string (uri) | null | required | A signed URL that stops working 15 minutes after the response; null when there is no thumbnail. |
createdAt | string (date-time) | required | |
fileUrl | string (uri) | null | optional | Only with the media:files scope. The file itself: a signed URL that stops working 15 minutes after the response, or a web page's own address. Absent without that scope. |
Tag
| Field | Type | Description | |
|---|---|---|---|
id | string (uuid) | required | |
name | string | required |
Campaign
| Field | Type | Description | |
|---|---|---|---|
lineageId | string (uuid) | required | The campaign's stable id: it stays the same across versions. |
name | string | required | |
status | "running" | "upcoming" | "draft" | "ended" | "withdrawn" | required | running, upcoming or ended while live; else draft (never published) or withdrawn. |
flight | object | required | The live version's flight, else the newest version's. |
tags | Tag[] | required |
CampaignDetail
| Field | Type | Description | |
|---|---|---|---|
lineageId | string (uuid) | required | The campaign's stable id: it stays the same across versions. |
name | string | required | |
status | "running" | "upcoming" | "draft" | "ended" | "withdrawn" | required | running, upcoming or ended while live; else draft (never published) or withdrawn. |
flight | object | required | The live version's flight, else the newest version's. |
tags | Tag[] | required | |
mediaIds | string (uuid)[] | required | The media the live version plays (landscape and portrait), in play order, each once; empty when nothing is live. |
content | object | null | required | The live version's content in play order; null when nothing is live. |
CampaignContent
| Field | Type | Description | |
|---|---|---|---|
playlistId | string (uuid) | null | required | The playlist it was published from (GET /playlists/{id}); null when that playlist was deleted since. |
items | PlayItem[] | required | In play order, as frozen at publish: what screens play now. |
Playlist
| Field | Type | Description | |
|---|---|---|---|
id | string (uuid) | required | |
name | string | required | |
createdAt | string (date-time) | required | |
updatedAt | string (date-time) | required |
PlaylistDetail
| Field | Type | Description | |
|---|---|---|---|
id | string (uuid) | required | |
name | string | required | |
createdAt | string (date-time) | required | |
updatedAt | string (date-time) | required | |
totalDurationSeconds | number | required | |
items | PlayItem[] | required | In play order. |
PlayItem
| Field | Type | Description | |
|---|---|---|---|
mediaId | string (uuid) | required | |
type | "image" | "video" | "web" | required | |
durationSeconds | number | required | How long it plays, in seconds: the item's own setting, else the media's length or the default. |
PresignedUpload
| Field | Type | Description | |
|---|---|---|---|
url | string (uri) | required | PUT the bytes here within 15 minutes. |
headers | object | required | Send every one of these headers unchanged: they are part of the signature. |
Error
| Field | Type | Description | |
|---|---|---|---|
error | "invalid_request" | "unauthorized" | "forbidden" | "not_found" | "method_not_allowed" | "conflict" | "payload_too_large" | "unprocessable" | "rate_limited" | "internal" | required | |
message | string | required | |
code | string | optional | Which reason behind the status: for a 409 storage_quota_exceeded or id_conflict; for a 403 plan; for a 422 invalid. |
