店內媒體顯示器 API(Display API)的使用方式
API
Display
媒體
Android
數位看板
配對
零售媒體
曝光
本指南的目的
本文彙整使用 ReceiptRoller 的店內媒體顯示器 API(Display API),在店頭 Android 端末播放媒體循環(圖片、影片)的應用程式實作步驟。這是一份為了在 POS 端末兼用的電子看板,或專用的數位看板機(壁掛平板等),播送 ReceiptRoller 的零售媒體與宣傳影片的指南。
前提
- 不預期在 Android 端末端啟動瀏覽器的 OAuth 流程。各端末以長期有效的裝置權杖進行驗證
- 裝置權杖以「配對(Pairing)」流程取得。店鋪擁有者在管理畫面產生的 6 位數代碼輸入至 Android 應用程式後,即會為各端末發行權杖
- 基底 URL:
https://receiptroller.io
端點一覽
| 端點 | 用途 | 驗證 |
|---|---|---|
POST /api/v1/displays/pair | 將 6 位數的配對代碼交換為裝置權杖 | 不需要(代碼即為驗證) |
POST /api/v1/displays/{displayId}/heartbeat | 端末的存活通知(用於線上/離線判定) | 裝置權杖 |
GET /api/v1/displays/{displayId}/playlist | 取得應播放媒體的排序清單 | 裝置權杖 |
POST /api/v1/displays/{displayId}/impressions | 以批次回報播放實績(play) | 裝置權杖 |
配對流程
各端末只進行 1 次配對。權杖在 Android 端持久化,之後所有的請求都在 Authorization: Bearer {token} 標頭附上。
- 店鋪擁有者在管理畫面登錄新的顯示器時,會顯示 6 位數的配對代碼(有效期間 10 分鐘、僅限 1 次)
- 在 Android 應用程式的初次啟動畫面輸入代碼
- Android 呼叫
POST /api/v1/displays/pair,接收權杖與displayId - Android 將權杖與 displayId 持久化至本地(建議加密)
請求範例:
POST /api/v1/displays/pair
Content-Type: application/json
User-Agent: RRDisplay/1.0 (Android 14; Pixel Tablet)
{
"code": "123456",
"screenWidth": 1920,
"screenHeight": 1080,
"supportsVideo": true,
"supportsAudio": false
}
回應範例(200):
{
"displayId": "a1b2c3d4-...",
"organizationId": "7d325d1d-...",
"deviceToken": "dvc_3f9c1a8b7e2d6f4a1b8c5d2e9f7a3b6c"
}
錯誤回應:
400 missing_code— 未指定 code 欄位401 invalid_or_expired_code— 代碼錯誤、超過 10 分鐘的有效期限,或已被使用
重要:
- 權杖只能在回應中取得。伺服器端僅保存雜湊,因此遺失時請在管理畫面刪除顯示器,再重新配對
- 1 個配對代碼只能使用 1 次。重新配對時請發行新的代碼
心跳
向伺服器傳達端末處於線上。管理畫面的「線上/離線」顯示以此時間戳為基準(若距最後一次心跳在 5 分鐘以內則視為線上)。
POST /api/v1/displays/{displayId}/heartbeat
Authorization: Bearer dvc_3f9c1a8b...
User-Agent: RRDisplay/1.0 (Android 14; Pixel Tablet)
回應範例(200):
{
"ok": true,
"serverTimeUtc": "2026-06-03T05:21:30Z",
"nextHeartbeatSeconds": 60
}
建議的呼叫間隔: 請依回應的 nextHeartbeatSeconds(目前為 60 秒)。由於伺服器端可能會依輪詢負載變更此值,建議不要寫死,而是參照回應。
播放清單取得
端末取得應播放媒體的排序清單。各項目中含有已 SAS 簽章的直接存取 URL(有效 1 小時)。
GET /api/v1/displays/{displayId}/playlist
Authorization: Bearer dvc_3f9c1a8b...
回應範例(200):
{
"displayId": "a1b2c3d4-...",
"generatedAt": "2026-06-03T05:21:30Z",
"pollIntervalSeconds": 60,
"items": [
{
"creativeId": "creative-001",
"name": "夏の新商品キャンペーン",
"type": "Image",
"mediaUrl": "https://strprdomnicon.blob.core.windows.net/creatives/...?sv=...&sig=...",
"durationSeconds": 10,
"hashHint": "creative-001_638549812340000000"
},
{
"creativeId": "creative-002",
"name": "新メニュー紹介動画",
"type": "Video",
"mediaUrl": "https://strprdomnicon.blob.core.windows.net/creatives/...?sv=...&sig=...",
"durationSeconds": 30,
"hashHint": "creative-002_638549812350000000"
}
]
}
運用指南:
- 播放順序 — 請依
items陣列的順序播放,播到最後後回到最前面循環播放 - 快取 — 只要
hashHint未變,媒體檔案就不需重新下載。建議使用本地快取。hashHint變更後請重新取得 - SAS URL 的有效期限 —
mediaUrl有效 1 小時。以過期的 URL 嘗試下載會回傳 403,因此請以pollIntervalSeconds間隔重新取得播放清單,取得新的 URL - durationSeconds — 圖片為 10 秒(預設),影片為實際長度。應用程式請以指定秒數切換至下一個項目
- 空的播放清單 — 若擁有者端尚未承認任何素材,
items為空陣列。為空時,建議顯示黑畫面或「準備中」佔位畫面
播放實績的回報(曝光)
針對播放的每個時段,將「何時、播放了哪個素材、播放了多久」從 Android 批次傳送至伺服器。Phase 3 / t-e9a2f501。
POST /api/v1/displays/{displayId}/impressions
Authorization: Bearer dvc_3f9c1a8b...
Content-Type: application/json
{
"events": [
{
"eventId": "a1b2c3d4-e5f6-7890-1234-567890abcdef",
"creativeId": "creative-001",
"campaignId": "camp-001",
"placementId": "place-001",
"playedAtUtc": "2026-06-03T05:20:00Z",
"durationPlayedMs": 10000,
"completed": true
},
{
"eventId": "b2c3d4e5-f678-9012-3456-7890abcdef01",
"creativeId": "creative-002",
"campaignId": "camp-001",
"placementId": "place-001",
"playedAtUtc": "2026-06-03T05:20:10Z",
"durationPlayedMs": 30000,
"completed": true
}
]
}
回應範例(200):
{
"accepted": 2,
"duplicates": 0,
"rejected": 0,
"errors": []
}
運用指南:
- 傳送頻率 — 建議每 60 秒傳送一次。若每播放 1 個時段就傳送會造成過度的網路負載
- 批次上限 — 一次請求最多 500 筆。超過時會回傳
400 batch_too_large - eventId 由用戶端產生 — 建議使用 UUID v4。伺服器端以此 ID 保證冪等性。即使離線後重送相同批次,伺服器也會靜默地將第二次計為
duplicates - completed 旗標 — 若播完整個時段則為
true,中途切換至下一個則為false。用於完成率的分析 - 離線因應 — 網路失敗時請保存於本地佇列,恢復後再重送。由於具備冪等性,重複傳送是安全的
- placementId / campaignId 為選填 — 播放清單項目中並未直接包含,但若 Android 應用程式已理解 Phase 2 的播放清單結構,附上可提升分析的粒度。留空也會被 accepted
回應欄位:
accepted— 新記錄的筆數duplicates— 已處理過的筆數(重送造成的重複)rejected— 因必填欄位缺漏等而無法處理的筆數errors— 拒絕理由的陣列(供除錯用,內容可能隨版本變更)
典型的實作流程(Android)
- 初次啟動 — 若本地不存在權杖則顯示配對畫面。輸入代碼 →
POST /pair→ 取得權杖 → 保存 - 常時執行迴圈
- 啟動時及其後每 60 秒呼叫
GET /playlist hashHint與前次不同的項目重新下載,相同的項目從快取讀取- 依取得順序全螢幕播放圖片/影片,每個
durationSeconds切到下一個 - 播到最後一個項目後回到開頭
- 啟動時及其後每 60 秒呼叫
- 並行 — 每 60 秒呼叫
POST /heartbeat向伺服器傳達存活 - 並行 — 針對每個播放的時段記錄至本地佇列,每 60 秒以
POST /impressions批次傳送 - 錯誤處理
401— 權杖無效。回到重新配對畫面403— 權杖與路徑上的 displayId 不一致(Bug)。取得日誌後重新配對- 網路失敗 — 繼續播放最後取得的播放清單,保持曝光佇列並以退避重試
安全性
- 裝置權杖為長期有效。請保存於 Android Keystore 等端末的加密儲存區
- 伺服器端僅保存權杖的 SHA-256 雜湊。遺失的權杖可在管理畫面刪除顯示器再重新配對來失效
- 1 個權杖 = 1 個顯示器。若在多個端末重複使用同一權杖,管理畫面的「最後心跳」「目前解析度」會被各端末覆寫而混亂
這個 API 的未來
目前的播放清單支援「依活動 × 版位進行時段、店鋪定向與加權循環」。今後的功能會追加以下項目:
- 店鋪擁有者用播放實績儀表板(曝光數、完成率、各顯示器分帳)
- 頻率上限的實效化(版位的
frequencyCapPerHour目前可設定,但在 Phase 5 實作前為無作用)
API 綱要維持向前相容 — 既有 4 個端點的回應格式今後也不會變更(可能會追加欄位)。
相關資訊
發布日: 2026-06-03
更新日: 2026-07-06
標籤
API (22)
OAuth (15)
Android (10)
iOS (9)
Webhook (8)
api (7)
oauth (5)
POS串接 (4)
getting-started (4)
參考 (4)
相關文章
-
店鋪資訊 API(Store Information API)的使用方式說明如何以 REST API 取得、更新店鋪的基本資訊(店鋪名稱、店鋪類別、聯絡方式、地址)。可從員工應用程式等以權杖驗證的用戶端實作店鋪資訊的編輯畫面。
-
交易一覽 API(Transactions API:POS+OMS 整合摘要)的使用方式ReceiptRoller 的 Transactions API 是將收銀營業額(PosTransactions)與銷售管理訂單(OmsOrders)整合為單一摘要的唯讀 API。在 Android/iOS 應用程式中一覽顯示「整個商業帳戶的交易」時,即為入口。
-
營業額實績 API(Sales API)的使用方式彙整 ReceiptRoller 營業額實績 API(/api/v1/sales/*)的概要,以及依商業帳戶、店鋪、POS 端末、期間的篩選方法。這是一份涵蓋實際回應結構(KpiValue 巢狀型)與 averageTicket、權杖有效期限(8 小時)在內,為在 Android/iOS 行動應用程式或伺服器串接實作營業額儀表板的入門指南。
-
銷售管理 API(Orders / OMS API)的使用方式這是使用 ReceiptRoller 銷售管理 API(/api/v1/orders)對商業帳戶底下的訂單進行 CRUD 操作的指南。彙整訂單的建立、更新、狀態轉移(確認、處理中、取消)、刪除,以及適用於 Android/iOS 應用程式或伺服器串接的流程。
-
營業時間 API(Business Hours API)的使用方式ReceiptRoller 營業時間 API(/api/v1/stores/{storeId}/business-hours)的指南。解說每個星期的營業時間的取得與更新、特別營業日(臨時歇業、營業時間變更)的登錄、店鋪的可營業時間(排班建立時的上限業務時間)的設定,以及目前是否營業中的判定。