DRMN Developers

把你的系統接上 DigiCMS

DigiCMS 是 DRMN 的數位看板管理系統。第三方系統可以用整合 API 讀取一家店的媒體、活動和標籤,也可以上傳素材;人也可以用 AI 工具(MCP)直接操作 CMS。

兩種接法

先選對接法:系統對系統用整合 API;人透過 AI 工具操作用 MCP。

整合 API(整合 token dcmi_…)AI 工具(MCP,個人 AI 金鑰 dcms_…)
給誰第三方系統:EC、POS、報表、合作夥伴用 Claude、ChatGPT、Cursor 這類 AI 工具操作 CMS 的人
屬於店家;建立的人離開也照常可以用個人帳號;人離開店家就失效
誰建立、在哪裡擁有者或管理員,CMS「設定 → 整合」每個人自己,CMS「帳號 → AI」(/account/ai)
權限只有勾選的範圍;寫入只有上傳素材、加標籤跟這個人在店裡的角色一樣,但有些操作 AI 一律不能做(例如發 token、刪標籤),發布要本人確認
入口https://cms.drmn.app/api/integrations/v1/…(REST、JSON)https://cms.drmn.app/api/mcp(MCP)

開始使用

1. 請店家建立整合 token

整合 token 由店家發,不是由你自己申請。店家的擁有者或管理員到 CMS 的「設定 → 整合」,填名稱(例如「團購 EC」)、勾範圍、選有效期,按「建立 token」。token 是 dcmi_ 加 43 個字元,只會顯示一次,請店家當下複製給你。

CMS「設定 → 整合」建立 token 的畫面
CMS「設定 → 整合」:勾了上傳素材和加標籤的 token,有效期最長 90 天。
  • token 屬於店家,不屬於建立它的人;那個人離開店家,token 照常可以用。
  • 到期、被撤銷,或店家停權、方案到期時,token 會失效。
  • 一家店最多 10 把有效的 token。
  • token 等同密碼:放在伺服器端的設定或 secret,不要放進網頁、App 或版本庫。

2. 打第一個請求

每個請求都帶 Authorization: Bearer dcmi_…。網址裡不用、也不能指定店家:token 是哪家店的,就只讀得到那家店的資料。回傳一律是 JSON。

export DIGICMS_INTEGRATION_TOKEN='dcmi_…'   # the token the merchant gave you
curl -s "https://cms.drmn.app/api/integrations/v1/media?limit=20" \
  -H "Authorization: Bearer $DIGICMS_INTEGRATION_TOKEN"

範圍

token 只能做建立時勾選的事。沒有某個範圍,呼叫對應的端點會得到 403,訊息會寫出缺哪個範圍。

範圍端點內容
media:readGET /media、GET /media/{id}媒體:名稱、類型、尺寸、長度、標籤、縮圖
media:files(同上,要搭配 media:read)媒體多一個 fileUrl:原檔的短期網址
media:writePOST /media/uploads、POST /media/uploads/{id}/finalize(要搭配 media:read)上傳素材到店家的媒體庫
campaigns:readGET /campaigns、GET /campaigns/{lineageId}活動;單筆含螢幕實際在播的內容
playlists:readGET /playlists、GET /playlists/{id}播放清單,依播放順序
tags:readGET /tags標籤
tags:writePOST /media/{id}/tags(要搭配 tags:read)替素材加標籤,只能加

有 media:write 或 tags:write 的 token 最長 90 天;只能讀的 token 最長一年。

上傳素材

檔案不經過 CMS:CMS 給你簽好名的網址,你直接 PUT 到儲存空間。整個流程是 requestUpload → PUT → finalize,之後可以再加標籤。

  1. 算出檔案的 SHA-256(小寫 hex)和位元組數;影片另外讀長度、寬高和編碼。最好也做一張 480 px 寬的 JPEG 縮圖(hasThumbnail、thumbnailSize)。
  2. 自己產生一個 UUID(最好是 v7)當這個檔案的 id。重送同一個 id 是安全的,不會多出第二筆:網路斷了就用同一個 id 再送一次。
  3. POST /media/uploads,拿到 upload.url 和 upload.headers。
  4. 15 分鐘內把檔案 PUT 到 upload.url,upload.headers 的每一個標頭都原樣帶上(它們是簽名的一部分)。有縮圖的話用 thumbnailUpload 一樣做。
  5. POST /media/uploads/{id}/finalize。CMS 檢查檔案真的到了、大小對,素材就變成可以播放。
# 1. Start the upload: your own id, the file's size and SHA-256
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":"9f86d0…","width":1920,"height":1080}'

# 2. PUT the bytes to upload.url, with every header in upload.headers, unchanged
curl -sS -f -X PUT --data-binary @autumn-menu.jpg "$UPLOAD_URL" \
  -H "content-type: image/jpeg" -H "content-length: 245760"   # …and the rest of upload.headers

# 3. Finalize: the item becomes ready and is returned as GET /media/{id} shows it
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"

# 4. Tag it, e.g. with the campaign it is for
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"]}'

POST /media/uploads 的回傳:

{
  "mediaId": "0192f0c4-7a3c-7b1d-9e2f-3a4b5c6d7e8f",
  "duplicateOf": null,
  "upload": { "url": "https://…", "headers": { "content-type": "image/jpeg", "content-length": "245760", "…": "…" } },
  "thumbnailUpload": null,
  "warnings": []
}
  • duplicateOf 不是 null:店家已經有一模一樣的檔案,mediaId 就是那一筆,不用上傳也不用 finalize。
  • warnings:影片在店家的螢幕上可能會卡(解析度、位元率、編碼),不會擋上傳,請轉告店家。
  • 圖片 image/jpeg、image/png、image/webp 最大 50 MB;影片 video/mp4、video/webm 最大 2 GB。
  • 上傳的素材算店家的儲存空間;滿了會得到 409、code: "storage_quota_exceeded"。
  • 店家的操作紀錄會記下是哪一把 token(名稱和末四碼)上傳的。

加標籤

POST /media/{id}/tags,body 是 {"add": [名稱…]},一次最多 10 個。店家已經有的標籤(不分大小寫、忽略多餘空白)直接沿用,沒有的就建立。

  • 回傳的 added 是這次真的新加上去的數量;已經有的不會重複加,所以重送是安全的。
  • 只能加:body 裡有 remove 或 drop 會得到 422。要移除標籤,請店家在 CMS 裡做。
  • 常見的用法:上傳後加上活動名稱的標籤,店家在 CMS 用標籤就能找到這批素材。

分頁和篩選

列表端點(/media、/campaigns、/playlists、/tags)都可以用:

參數說明
limit每頁幾筆,1–200,預設 50
cursor上一頁回傳的 nextCursor;nextCursor 是 null 就是最後一頁
q文字搜尋,不分大小寫。媒體比對名稱和說明,其他比對名稱
tag標籤 id(從 GET /tags 拿),只有 /media、/campaigns 可用。可以重複,表示每個標籤都要有

不認得的參數、格式不對的參數會得到 400,不會被默默忽略。

錯誤

錯誤的格式都一樣:error 是固定的代碼,message 給人看;寫入端點可能多一個 code,說明同一個狀態碼裡是哪一種原因。

{ "error": "conflict", "message": "plan limit reached (storage 1950/2000 MB)", "code": "storage_quota_exceeded" }
狀態碼error什麼時候
400invalid_request查詢參數或 body 不對;body 不是 JSON、少了必填欄位
401unauthorized沒帶 token、token 不對、已到期或已撤銷,或店家停權、方案到期
403forbiddentoken 沒有這個端點要的範圍;或店家的方案不允許(code: "plan")
404not_found找不到,或那筆資料不屬於這家店(兩者回應一樣)
405method_not_allowed方法不對:讀取只收 GET,寫入只收 POST(看 Allow 標頭)
409conflictstorage_quota_exceeded:店家的儲存空間滿了;id_conflict:這個 id 已經是別的素材
413payload_too_largebody 超過 16 KB
422unprocessable內容不被接受:檔案類型或大小不對、還沒 PUT 就 finalize、要移除標籤…
429rate_limited超過限流,見下一節
500internal我們這邊出錯,請稍後再試

限流

每把 token 每分鐘最多 120 次;其中寫入(三個 POST)另外算,每分鐘最多 30 次。超過會得到 429,Retry-After 標頭寫著還要等幾秒。

  • 定時同步就好,例如每 1–5 分鐘拉一次列表,不要每個網頁請求都打 API。
  • 縮圖和原檔網址 15 分鐘後失效,要顯示前再拿新的,或自己存一份。
  • 上傳很多檔案時一個一個來,被 429 就照 Retry-After 等。

版本政策

  • /api/integrations/v1 只加不改:新的欄位、新的端點、新的範圍會直接加進來,不會改名、不會刪除,也不會改變既有欄位的意思。
  • 所以請忽略你不認得的欄位,不要因為多了一個欄位就失敗。
  • 需要不相容的改動時,才會開 /v2,並且讓 /v1 繼續運作一段時間。

AI 工具(MCP)

如果是「人」要用 Claude、ChatGPT、Cursor 這類 AI 工具操作 CMS,例如用對話排播、整理素材、看播放紀錄,請用 MCP,不要用整合 token。

  1. 每個人在 CMS「帳號 → AI」(/account/ai)建立自己的 AI 金鑰(dcms_…)。
  2. 在 AI 工具裡加上 MCP 伺服器 https://cms.drmn.app/api/mcp,帶上這把金鑰。
  3. AI 能做的事跟這個人在店裡的角色一樣;發布、改螢幕設定這類操作要本人確認,有些操作 AI 一律不能做。

設定步驟和工具清單以 CMS 上的頁面為準(不用登入):

OpenAPI 檔

完整的格式定義在 openapi.json(OpenAPI 3.0),可以匯入 Postman、Insomnia,或拿來產生 SDK。API 參考就是從這個檔產生的。

沒有線上試打:在瀏覽器裡帶 token 打 API 會讓 token 留在瀏覽器,所以請用上面的 curl 範例。