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

NameInTypeDescription
cursorquerystringThe nextCursor of the previous page.
limitqueryinteger1–200, default 50
tagquerystring (uuid)[]A tag id from GET /tags. Repeat it to require every tag listed.
qquerystringMatches 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

FieldTypeDescription
itemsMedia[]required
nextCursorstring | nullrequiredPass 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

StatusWhen
400 Bad RequestA query parameter is not valid.
401 UnauthorizedThe token is missing, unknown, expired or revoked, or its merchant is suspended or its plan has ended.
403 ForbiddenThe token lacks the scope this endpoint needs; the message names it.
429 Too Many RequestsMore 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

NameInTypeDescription
idpath (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

FieldTypeDescription
idstring (uuid)required
namestringrequired
type"image" | "video" | "web"required
widthinteger | nullrequiredPixels; null when unknown (and for web pages).
heightinteger | nullrequiredPixels; null when unknown (and for web pages).
durationSecondsnumber | nullrequiredA video's length; null for images and web pages.
tagsTag[]required
thumbnailUrlstring (uri) | nullrequiredA signed URL that stops working 15 minutes after the response; null when there is no thumbnail.
createdAtstring (date-time)required
fileUrlstring (uri) | nulloptionalOnly 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

StatusWhen
401 UnauthorizedThe token is missing, unknown, expired or revoked, or its merchant is suspended or its plan has ended.
403 ForbiddenThe token lacks the scope this endpoint needs; the message names it.
404 Not FoundNo such item in the token's merchant.
429 Too Many RequestsMore 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

NameInTypeDescription
cursorquerystringThe nextCursor of the previous page.
limitqueryinteger1–200, default 50
tagquerystring (uuid)[]A tag id from GET /tags. Repeat it to require every tag listed.
qquerystringMatches 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

FieldTypeDescription
itemsCampaign[]required
nextCursorstring | nullrequiredPass 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

StatusWhen
400 Bad RequestA query parameter is not valid.
401 UnauthorizedThe token is missing, unknown, expired or revoked, or its merchant is suspended or its plan has ended.
403 ForbiddenThe token lacks the scope this endpoint needs; the message names it.
429 Too Many RequestsMore 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

NameInTypeDescription
lineageIdpath (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

FieldTypeDescription
lineageIdstring (uuid)requiredThe campaign's stable id: it stays the same across versions.
namestringrequired
status"running" | "upcoming" | "draft" | "ended" | "withdrawn"requiredrunning, upcoming or ended while live; else draft (never published) or withdrawn.
flightobjectrequiredThe live version's flight, else the newest version's.
tagsTag[]required
mediaIdsstring (uuid)[]requiredThe media the live version plays (landscape and portrait), in play order, each once; empty when nothing is live.
contentobject | nullrequiredThe 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

StatusWhen
401 UnauthorizedThe token is missing, unknown, expired or revoked, or its merchant is suspended or its plan has ended.
403 ForbiddenThe token lacks the scope this endpoint needs; the message names it.
404 Not FoundNo such item in the token's merchant.
429 Too Many RequestsMore 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

NameInTypeDescription
cursorquerystringThe nextCursor of the previous page.
limitqueryinteger1–200, default 50
qquerystringMatches 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

FieldTypeDescription
itemsPlaylist[]required
nextCursorstring | nullrequiredPass 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

StatusWhen
400 Bad RequestA query parameter is not valid.
401 UnauthorizedThe token is missing, unknown, expired or revoked, or its merchant is suspended or its plan has ended.
403 ForbiddenThe token lacks the scope this endpoint needs; the message names it.
429 Too Many RequestsMore 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

NameInTypeDescription
idpath (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

FieldTypeDescription
idstring (uuid)required
namestringrequired
createdAtstring (date-time)required
updatedAtstring (date-time)required
totalDurationSecondsnumberrequired
itemsPlayItem[]requiredIn 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

StatusWhen
401 UnauthorizedThe token is missing, unknown, expired or revoked, or its merchant is suspended or its plan has ended.
403 ForbiddenThe token lacks the scope this endpoint needs; the message names it.
404 Not FoundNo such item in the token's merchant.
429 Too Many RequestsMore 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

FieldTypeDescription
idstring (uuid)requiredYour id for this file, a UUID (v7 is best). Sending the same id again is a safe retry: it never adds a second item.
namestringrequiredThe name shown in the media library. (at most 200 characters)
fileNamestringrequiredat most 500 characters
mimeTypestringrequiredimage/jpeg, image/png, image/webp, video/mp4 or video/webm.
fileSizeintegerrequiredBytes. Images up to 50 MB, videos up to 2 GB.
checksumstringrequiredThe file's SHA-256, lower-case hex.
durationnumber | nulloptionalA video's length in seconds.
widthinteger | nulloptional
heightinteger | nulloptional
hasThumbnailbooleanoptionalTrue when you will PUT a JPEG thumbnail (480 px wide is best) too.
thumbnailSizeinteger | nulloptionalThe thumbnail's bytes, at most 1 MB; required with hasThumbnail.
codecstring | nulloptionalA 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

FieldTypeDescription
mediaIdstring (uuid)requiredThe item's id: yours, or the existing item's when duplicateOf is set.
duplicateOfobject | nullrequiredSet when the merchant already has this exact file: nothing to upload or finalize, use mediaId.
uploadobject | nullrequiredWhere to PUT the file; null for a duplicate.
thumbnailUploadobject | nullrequiredWhere to PUT the thumbnail; null without one.
warningsobject[]requiredVideo 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

StatusWhen
400 Bad RequestThe body is not valid JSON or not what this endpoint takes; the message names the fields.
401 UnauthorizedThe token is missing, unknown, expired or revoked, or its merchant is suspended or its plan has ended.
403 ForbiddenThe token lacks the scope this endpoint needs, or the merchant's plan does not allow it (code: plan).
409 Conflictcode: storage_quota_exceeded: the merchant's storage is full. code: id_conflict: the id is another item's.
413 Payload Too LargeThe body is larger than 16 KB.
422 UnprocessableThe file is not accepted: type, size, checksum or name; the message says which.
429 Too Many RequestsMore 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

NameInTypeDescription
idpath (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

FieldTypeDescription
idstring (uuid)required
namestringrequired
type"image" | "video" | "web"required
widthinteger | nullrequiredPixels; null when unknown (and for web pages).
heightinteger | nullrequiredPixels; null when unknown (and for web pages).
durationSecondsnumber | nullrequiredA video's length; null for images and web pages.
tagsTag[]required
thumbnailUrlstring (uri) | nullrequiredA signed URL that stops working 15 minutes after the response; null when there is no thumbnail.
createdAtstring (date-time)required
fileUrlstring (uri) | nulloptionalOnly 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

StatusWhen
400 Bad RequestThe body is not valid JSON or not what this endpoint takes; the message names the fields.
401 UnauthorizedThe token is missing, unknown, expired or revoked, or its merchant is suspended or its plan has ended.
403 ForbiddenThe token lacks the scope this endpoint needs, or the merchant's plan does not allow it (code: plan).
404 Not FoundNo such upload in the token's merchant.
413 Payload Too LargeThe body is larger than 16 KB.
422 UnprocessableThe file was not stored, or not with the declared size; PUT it again.
429 Too Many RequestsMore 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

NameInTypeDescription
idpath (required)string (uuid)A media id.

Request body AddTagsRequest

FieldTypeDescription
addstring[]requiredTag 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

FieldTypeDescription
mediaIdstring (uuid)required
tagsTag[]requiredThe tags the names resolved to.
addedintegerrequiredHow 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

StatusWhen
400 Bad RequestThe body is not valid JSON or not what this endpoint takes; the message names the fields.
401 UnauthorizedThe token is missing, unknown, expired or revoked, or its merchant is suspended or its plan has ended.
403 ForbiddenThe token lacks the scope this endpoint needs, or the merchant's plan does not allow it (code: plan).
404 Not FoundNo such media item in the token's merchant.
413 Payload Too LargeThe body is larger than 16 KB.
422 UnprocessableThe body asks to remove tags, or the item would have too many tags.
429 Too Many RequestsMore 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

NameInTypeDescription
cursorquerystringThe nextCursor of the previous page.
limitqueryinteger1–200, default 50
qquerystringMatches 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

FieldTypeDescription
itemsTag[]required
nextCursorstring | nullrequiredPass as cursor for the next page; null on the last page.
{
  "items": [
    {
      "id": "0192f0c4-7a3c-7b1d-9e2f-3a4b5c6d7e8f",
      "name": "Autumn menu"
    }
  ],
  "nextCursor": null
}

Errors

StatusWhen
400 Bad RequestA query parameter is not valid.
401 UnauthorizedThe token is missing, unknown, expired or revoked, or its merchant is suspended or its plan has ended.
403 ForbiddenThe token lacks the scope this endpoint needs; the message names it.
429 Too Many RequestsMore than 120 requests in a minute with this token.

Shared objects

Media

FieldTypeDescription
idstring (uuid)required
namestringrequired
type"image" | "video" | "web"required
widthinteger | nullrequiredPixels; null when unknown (and for web pages).
heightinteger | nullrequiredPixels; null when unknown (and for web pages).
durationSecondsnumber | nullrequiredA video's length; null for images and web pages.
tagsTag[]required
thumbnailUrlstring (uri) | nullrequiredA signed URL that stops working 15 minutes after the response; null when there is no thumbnail.
createdAtstring (date-time)required
fileUrlstring (uri) | nulloptionalOnly 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

FieldTypeDescription
idstring (uuid)required
namestringrequired

Campaign

FieldTypeDescription
lineageIdstring (uuid)requiredThe campaign's stable id: it stays the same across versions.
namestringrequired
status"running" | "upcoming" | "draft" | "ended" | "withdrawn"requiredrunning, upcoming or ended while live; else draft (never published) or withdrawn.
flightobjectrequiredThe live version's flight, else the newest version's.
tagsTag[]required

CampaignDetail

FieldTypeDescription
lineageIdstring (uuid)requiredThe campaign's stable id: it stays the same across versions.
namestringrequired
status"running" | "upcoming" | "draft" | "ended" | "withdrawn"requiredrunning, upcoming or ended while live; else draft (never published) or withdrawn.
flightobjectrequiredThe live version's flight, else the newest version's.
tagsTag[]required
mediaIdsstring (uuid)[]requiredThe media the live version plays (landscape and portrait), in play order, each once; empty when nothing is live.
contentobject | nullrequiredThe live version's content in play order; null when nothing is live.

CampaignContent

FieldTypeDescription
playlistIdstring (uuid) | nullrequiredThe playlist it was published from (GET /playlists/{id}); null when that playlist was deleted since.
itemsPlayItem[]requiredIn play order, as frozen at publish: what screens play now.

Playlist

FieldTypeDescription
idstring (uuid)required
namestringrequired
createdAtstring (date-time)required
updatedAtstring (date-time)required

PlaylistDetail

FieldTypeDescription
idstring (uuid)required
namestringrequired
createdAtstring (date-time)required
updatedAtstring (date-time)required
totalDurationSecondsnumberrequired
itemsPlayItem[]requiredIn play order.

PlayItem

FieldTypeDescription
mediaIdstring (uuid)required
type"image" | "video" | "web"required
durationSecondsnumberrequiredHow long it plays, in seconds: the item's own setting, else the media's length or the default.

PresignedUpload

FieldTypeDescription
urlstring (uri)requiredPUT the bytes here within 15 minutes.
headersobjectrequiredSend every one of these headers unchanged: they are part of the signature.

Error

FieldTypeDescription
error"invalid_request" | "unauthorized" | "forbidden" | "not_found" | "method_not_allowed" | "conflict" | "payload_too_large" | "unprocessable" | "rate_limited" | "internal"required
messagestringrequired
codestringoptionalWhich reason behind the status: for a 409 storage_quota_exceeded or id_conflict; for a 403 plan; for a 422 invalid.