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 個字元,只會顯示一次,請店家當下複製給你。

- 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:read | GET /media、GET /media/{id} | 媒體:名稱、類型、尺寸、長度、標籤、縮圖 |
media:files | (同上,要搭配 media:read) | 媒體多一個 fileUrl:原檔的短期網址 |
media:write | POST /media/uploads、POST /media/uploads/{id}/finalize(要搭配 media:read) | 上傳素材到店家的媒體庫 |
campaigns:read | GET /campaigns、GET /campaigns/{lineageId} | 活動;單筆含螢幕實際在播的內容 |
playlists:read | GET /playlists、GET /playlists/{id} | 播放清單,依播放順序 |
tags:read | GET /tags | 標籤 |
tags:write | POST /media/{id}/tags(要搭配 tags:read) | 替素材加標籤,只能加 |
有 media:write 或 tags:write 的 token 最長 90 天;只能讀的 token 最長一年。
上傳素材
檔案不經過 CMS:CMS 給你簽好名的網址,你直接 PUT 到儲存空間。整個流程是 requestUpload → PUT → finalize,之後可以再加標籤。
- 算出檔案的 SHA-256(小寫 hex)和位元組數;影片另外讀長度、寬高和編碼。最好也做一張 480 px 寬的 JPEG 縮圖(
hasThumbnail、thumbnailSize)。 - 自己產生一個 UUID(最好是 v7)當這個檔案的
id。重送同一個id是安全的,不會多出第二筆:網路斷了就用同一個id再送一次。 POST /media/uploads,拿到upload.url和upload.headers。- 15 分鐘內把檔案 PUT 到
upload.url,upload.headers的每一個標頭都原樣帶上(它們是簽名的一部分)。有縮圖的話用thumbnailUpload一樣做。 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(名稱和末四碼)上傳的。
分頁和篩選
列表端點(/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 | 什麼時候 |
|---|---|---|
| 400 | invalid_request | 查詢參數或 body 不對;body 不是 JSON、少了必填欄位 |
| 401 | unauthorized | 沒帶 token、token 不對、已到期或已撤銷,或店家停權、方案到期 |
| 403 | forbidden | token 沒有這個端點要的範圍;或店家的方案不允許(code: "plan") |
| 404 | not_found | 找不到,或那筆資料不屬於這家店(兩者回應一樣) |
| 405 | method_not_allowed | 方法不對:讀取只收 GET,寫入只收 POST(看 Allow 標頭) |
| 409 | conflict | storage_quota_exceeded:店家的儲存空間滿了;id_conflict:這個 id 已經是別的素材 |
| 413 | payload_too_large | body 超過 16 KB |
| 422 | unprocessable | 內容不被接受:檔案類型或大小不對、還沒 PUT 就 finalize、要移除標籤… |
| 429 | rate_limited | 超過限流,見下一節 |
| 500 | internal | 我們這邊出錯,請稍後再試 |
限流
每把 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。
- 每個人在 CMS「帳號 → AI」(
/account/ai)建立自己的 AI 金鑰(dcms_…)。 - 在 AI 工具裡加上 MCP 伺服器
https://cms.drmn.app/api/mcp,帶上這把金鑰。 - AI 能做的事跟這個人在店裡的角色一樣;發布、改螢幕設定這類操作要本人確認,有些操作 AI 一律不能做。
設定步驟和工具清單以 CMS 上的頁面為準(不用登入):
- 設定步驟和各工具的設定片段
- 工具清單:跟 MCP 的
tools/list同一份,永遠跟線上一致 - 給 AI 讀的說明:llms.txt、install.md
OpenAPI 檔
完整的格式定義在 openapi.json(OpenAPI 3.0),可以匯入 Postman、Insomnia,或拿來產生 SDK。API 參考就是從這個檔產生的。
沒有線上試打:在瀏覽器裡帶 token 打 API 會讓 token 留在瀏覽器,所以請用上面的 curl 範例。
