RIDM Apps 部署指南
RIDM Apps 是連結 GitHub 儲存庫後自動建置、部署,並以 <name>.ridm.ai 公開的託管服務。請在主控台的 我的應用程式 申請,價格請見 價格頁面。使用條件由 服務條款 第3章(韓文) 規定。想一眼看懂包含哪些功能,請見 應用程式託管介紹。
部署流程
- 申請 — 在「我的應用程式」選擇方案與網址(子網域)。網址之後無法變更。
- 連結 GitHub — 在應用程式畫面安裝 GitHub App
ridm-apps-builder,選擇儲存庫與分支。權限只有儲存庫的讀取權。 - Push — 每次 push 到連結的分支都會開始建置。建置紀錄與失敗日誌會顯示在應用程式畫面上。
- 首次部署 — 建置成功後會經過自動檢查,隨即公開(見下文)。之後的 push 也會自動反映。
Dockerfile 需求
- 儲存庫根目錄必須有
Dockerfile。沒有的話建置會失敗。 - 應用程式必須在連接埠 3000 以 HTTP 回應。
PORT=3000、HOSTNAME=0.0.0.0一律強制設定。容器啟動後須在 30 秒內回應/的請求(狀態碼不限)。若未在時間內回應,會視為啟動失敗;如果是新版本,會繼續由前一版本提供服務。 - 若設定健康檢查路徑(應用程式畫面的「健康檢查路徑」,例如:
/api/health),會改為確認該路徑,須以 2xx、3xx、404 回應才算啟動成功(5xx 或其他 4xx 則失敗)。使用連資料庫都會確認的路徑,只開了連接埠卻無法正常運作的版本就不會上線。留空則套用上述規則。 - 新版本公開後若在 5 分鐘內重新啟動 3 次以上(程序持續當掉),會自動還原到前一個正常運作的版本一次,並以電子郵件通知您(附上應用程式最後留下的日誌)。若還原後的版本也持續當掉,就不再還原、維持原狀,請修正程式碼後再 push。
- 容器以使用者 1000:1000 執行。應用程式的檔案必須能被這個使用者讀取(
node:*-alpine映像檔的node使用者就是 1000)。 - 檔案系統為唯讀。可寫入的位置只有
/tmp與/app/.next/cache(兩者都在記憶體中,重新啟動就會消失)。需要永久保存的資料請存進資料庫。 - 建置以 x86_64(amd64)進行。建置時間上限為 20 分鐘。
- 若在儲存庫中發現機密值,就會停止建置:AWS 存取金鑰、GitHub token、Stripe 正式環境金鑰、私密金鑰區塊、含密碼的 PostgreSQL URL。機密值請放進 環境變數。
Next.js 入門範本
在 next.config.js 加入 output: 'standalone',並把下面的 Dockerfile 放在儲存庫根目錄。若沒有 public 資料夾,請刪除那一行。
FROM node:22-alpine AS deps
WORKDIR /app
COPY package.json package-lock.json ./
RUN npm ci
FROM node:22-alpine AS build
WORKDIR /app
COPY --from=deps /app/node_modules ./node_modules
COPY . .
RUN npm run build
FROM node:22-alpine
WORKDIR /app
ENV NODE_ENV=production
COPY --from=build --chown=1000:1000 /app/public ./public
COPY --from=build --chown=1000:1000 /app/.next/standalone ./
COPY --from=build --chown=1000:1000 /app/.next/static ./.next/static
USER 1000
EXPOSE 3000
CMD ["node", "server.js"]
不是 Next.js 也可以。只要是在連接埠 3000 回應的容器,任何技術堆疊都能運作。
執行環境
- 免費方案在有人造訪時啟動,15 分鐘沒有請求就會停止。停止後的第一次造訪可能會慢幾秒。搜尋爬蟲、監控請求、HEAD 請求不會喚醒應用程式。
- 付費方案常時執行。應用程式當掉時會自動重新啟動。
- 超過記憶體上限時,應用程式會被強制終止。Node.js 的 heap 上限設為方案記憶體的 75%。
- WebSocket 可在付費方案使用(免費方案的升級請求會回傳
403)。應用程式只要照常在連接埠 3000 接受Upgrade: websocket即可(路徑、子協定、Origin、X-Forwarded-For、CF-Connecting-IP都會原樣傳遞;應用程式不升級而回傳的 403、429 等回應,也會原樣送到訪客端)。上限如下:- 每個應用程式同時連線 120 個。超過時,新連線會以
503(Retry-After: 10)拒絕。 - 每則訊息(所有分段合計)64KB。超過時,該連線會以
1009關閉。不使用壓縮擴充(permessage-deflate)。 - 訊息數上限為每個應用程式每個方向每秒 2,000 則,單一訪客連線送出的訊息每秒 60 則。超過的部分不會丟棄,而是延後傳送。
- 沒有任何訊框經過 100 秒,中間的邊緣節點(Cloudflare)就會切斷連線。請讓應用程式或用戶端以更短的間隔送出 ping。
- 只允許同一應用程式的 Origin:瀏覽器連線只有在
Origin是該應用程式的網址(appname.ridm.ai或連結到該應用程式的網域)時才會開啟。來自其他應用程式或其他網站的連線,即使是同一合作夥伴的應用程式,也會回傳403。不同應用程式之間無法直接以 WebSocket 連線。 - 非瀏覽器的用戶端(伺服器、應用程式、CLI)可以不帶
Origin連線,但此時Cookie不會傳給應用程式。請改用標頭(Authorization)或查詢字串中的 token 進行驗證。 - 連線開啟期間,應用程式不會休眠。部署新版本或平台重新啟動時,連線會以
1001關閉,請讓用戶端能自動重新連線。
- 每個應用程式同時連線 120 個。超過時,新連線會以
- 可以對外發出 HTTPS 請求。寄信用的連接埠(SMTP)與內部網路已封鎖。寄送通知信請以
HRUM_API_KEY呼叫 應用程式郵件寄送 API,或使用提供 HTTPS API 的郵件服務。 - 為了安全,會依應用程式記錄其對外連線的對象:連線的位址與連接埠、應用程式查詢的網域名稱、首次與最後一次看到的時間、連線次數。不記錄請求與回應的內容及完整 URL。這些紀錄保存 3 個月後刪除。只有在調查安全事故或禁止行為(條款 第26條(韓文)),或依法令要求時才會查閱。
- 應用程式日誌(stdout、stderr)在處理故障時可能由營運人員查閱;在離開主機之前,環境變數的值、資料庫密碼、token、電子郵件等都會被遮蔽(條款 第20條)。
Cookie
由於許多合作夥伴的應用程式都在 ridm.ai 底下,閘道會把 Cookie 只綁定在各應用程式自己的網址。應用程式的程式碼照常使用 Cookie 即可。不過請注意:
- Cookie 一律為
Secure、Path=/,Domain屬性會被忽略。 - Cookie 名稱須在 57 個字元以內。名稱更長的 Cookie 會被捨棄。
- 用瀏覽器 JavaScript(
document.cookie)建立的 Cookie 不會傳到伺服器。伺服器需要讀取的 Cookie,請由伺服器回應的Set-Cookie建立。
資料庫
每個應用程式都會建立專屬的 PostgreSQL 資料庫,連線資訊以環境變數提供:DATABASE_URL(必須使用 SSL)以及 PGHOST、PGPORT、PGDATABASE、PGUSER、PGPASSWORD、PGSSLMODE。容量上限依方案而不同,使用量會顯示在應用程式畫面上。
資料庫連線使用連憑證都會完整驗證的 TLS。憑證簽發機構(Amazon RDS)的憑證已預先安裝在容器中(NODE_EXTRA_CA_CERTS、PGSSLROOTCERT),程式碼中不需要另外加 SSL 選項 — new Pool({ connectionString: process.env.DATABASE_URL, max: 2 }) 就夠了。每個應用程式最多 3 個連線,因此連線池大小請設在 2 以下。
- 每個應用程式同時最多 3 個連線,單一查詢最長 10 秒,在交易中閒置超過 60 秒的連線會被切斷。
- 使用量超過 80% 或超過容量時,會以電子郵件通知您。
- 超過容量的狀態持續 24 小時(超過 150% 則立即),資料庫會變成唯讀。若要刪除資料,請先在該連線執行
SET default_transaction_read_only = off。 - 在唯讀狀態下超過 110% 時,會切斷資料庫連線。資料不會被刪除,也仍可繼續建立 備份。
- 降到容量的 90% 以下,或改用更大的方案,5 分鐘內就會解除限制。
環境變數
- 在應用程式畫面的「環境變數」新增或刪除。儲存的值會加密保管,之後無法再次檢視(只顯示名稱)。要變更請用新值覆寫。
- 儲存後,應用程式會以新值重新啟動。
- 名稱只能使用英文大寫、數字、底線(不可以數字開頭,最多 64 個字元),值為單行且 2KB 以內,每個應用程式最多 50 個。
- 平台使用的名稱無法設定:
PORT、HOSTNAME、NODE_OPTIONS、DATABASE_URL,以及以RIDM_、PG開頭的名稱。 - 平台提供的值:
RIDM_COMMIT(部署之 commit 的完整 SHA)、RIDM_COMMIT_SHORT(前 7 個字元)、RIDM_DEPLOYED_AT(該版本的部署時間,ISO UTC)— 例如可在/api/health顯示目前執行中的版本。還原到先前的版本時,會使用該版本的值。 HRUM_API_KEY:放入在主控台「API 金鑰」核發的金鑰。開啟「AI 連結」的應用程式由平台自動設定,無法自行設定;若已自行設定值,請在開啟「AI 連結」前刪除。其他帳號的金鑰或應用程式專用金鑰無法使用。- 已解約的應用程式無法變更環境變數。
- 值無法透過任何畫面或 API 讀回。清單與 API 回應中只會顯示名稱。若遺失了值,請到原本的簽發單位(付款服務商、外部服務的主控台等)重新取得,再以相同名稱重新儲存。
在主控台加入機密金鑰(由人操作)
任何名稱都可以由人在主控台加入。AI 工具無法設定的名稱(見下文)也用這個方法加入。
- 登入 console.hrum.ai,打開左側選單的我的應用程式。
- 把應用程式卡片往下捲,找到環境變數區塊。已儲存的名稱會以
••••••••代替值顯示。 - 在第一欄名稱(例如:STRIPE_SECRET_KEY)輸入名稱。小寫或其他字元會在輸入時自動轉成大寫與底線。
- 在第二欄值貼上值。這個欄位會像密碼一樣隱藏顯示。
- 按下儲存,會顯示變數已儲存、應用程式即將重新啟動的確認訊息。以相同名稱再次儲存即可變更值。
- 要刪除時,按該列的刪除,再在確認視窗按刪除。刪除後應用程式會重新啟動,值無法復原。
搬移值的時候請注意:
- 從密碼管理工具或 macOS 的「鑰匙圈存取」複製值後立即貼上。不要先寫在記事本、聊天、郵件、文件中再轉貼。
- 貼上後請清空剪貼簿(macOS 終端機:
pbcopy < /dev/null,或隨便複製一段文字也可以)。 - 瀏覽器詢問是否要把值儲存為密碼時,請拒絕。
- 螢幕分享或錄影時請不要輸入。
用 AI 加入機密金鑰(AI 營運 token)
要讓 AI 程式開發工具代替人設定環境變數,需要 AI 營運 token。這是在核發主控台管理 token(hrum_cm_…,請見 用 AI 管理主控台)時,由人勾選 hosting_ops 權限的 token。有了這個權限,工具就不必每次作業都重新取得同意。為了不讓值經過 AI 模型,設定環境變數的功能沒有放進 HRUM MCP,請使用下面的 HTTP 路徑。
可透過 AI 途徑設定的名稱,只有以 _KEY、_SECRET、_TOKEN、_PASSWORD、_PASSWD、_PASS、_SALT、_CLIENT_ID 結尾的名稱(例如:STRIPE_SECRET_KEY、MASTER_KEY)。其中,會改變執行環境或連線位址的名稱也會被拒絕:以 _URL、_URI、_ENDPOINT、_HOST、_PROXY 結尾的名稱,以 NODE_、LD_、DYLD_、PYTHON、JAVA_、_JAVA_、JDK_、RUBY、PERL、GIT_、NPM_CONFIG_、GLOBAL_AGENT_、AWS_ENDPOINT_URL 開頭的名稱,以及 HTTP_PROXY、HTTPS_PROXY、NODE_TLS_REJECT_UNAUTHORIZED、SSL_CERT_FILE、PATH、OPENAI_API_BASE 等名稱。其他名稱(例如:ADMIN_PATH、SMTP_HOST)請由人 在主控台 加入。刪除也可以透過 AI 途徑進行(保留名稱除外)。
取得 token — 有效期間 30 天。
- AI 不需驗證,直接對
POST https://api.hrum.ai/api/v1/partners/v1/console-ai/consents送出{"action":"token_issue","payload":{"scopes":["hosting_ops"],"label":"My app ops"}}。回應的data中會有consentUrl、userCode(8 碼)、code、pollSecret。 - AI 只向使用者顯示
consentUrl與 8 碼代碼,不顯示pollSecret。 - 由人在 10 分鐘內,用已登入主控台的瀏覽器打開連結,在確認碼欄位輸入 AI 工具畫面上的 8 碼代碼,勾選
hosting_ops後按下同意。按下前請先閱讀勾選框下方的警告(token 外洩時,他人可能覆寫環境變數、部署、重新啟動)。 - AI 帶著
X-Consent-Poll-Secret標頭呼叫GET …/console-ai/consents/{code},在核准後的第一次回應中,會從data.token.value取得 token,僅此一次。請不要顯示在畫面上,直接存進機密儲存區(鑰匙圈、權限 600 的檔案等)。 - 不再需要時,在主控台 API 金鑰 畫面的「AI 主控台管理 token」按下撤銷,即刻失效。每個帳號有效的 token 最多 10 個。
呼叫 — 基本網址為 https://api.hrum.ai,標頭為 Authorization: Bearer hrum_cm_…。應用程式 ID 是 GET /api/v1/partners/v1/console-ai/hosting 回應中的 data.apps[].id(UUID)。
| 作業 | 請求 | 回應 |
|---|---|---|
| 名稱清單 | GET /api/v1/partners/v1/console-ai/hosting/apps/{appId}/env | {"success":true,"data":{"env":{"names":[…]}}} — 不含值 |
| 新增、變更 | PUT …/hosting/apps/{appId}/env/{NAME},內容 {"value":"…"} | 更新後的名稱清單。應用程式會重新啟動 |
| 刪除 | DELETE …/hosting/apps/{appId}/env/{NAME} | 更新後的名稱清單。應用程式會重新啟動 |
範例(bash 或 zsh)。值與 token 不以命令列參數傳遞,值以標準輸入送出。$APP_ID 與鑰匙圈項目名稱請換成您自己的。
# 1) Read secrets into shell variables (nothing is printed)
HRUM_CM_TOKEN=$(security find-generic-password -s hrum-console-ops -w)
VALUE=$(security find-generic-password -s myapp-STRIPE_SECRET_KEY -w)
# 2) Value goes through stdin, token through a header file: neither shows up in ps or shell history
printf '%s' "$VALUE" | jq -Rs '{value: .}' | curl -s -X PUT \
-H @<(printf 'Authorization: Bearer %s' "$HRUM_CM_TOKEN") \
-H 'Content-Type: application/json' --data-binary @- \
"https://api.hrum.ai/api/v1/partners/v1/console-ai/hosting/apps/$APP_ID/env/STRIPE_SECRET_KEY" \
| jq '.data.env.names // .'
# 3) Forget the value
unset VALUE
儲存完成後,回應只會顯示名稱清單。請打開應用程式網址,確認應用程式已用新值重新啟動。
用 AI 部署與查看日誌(AI 營運 token)
用同一個 AI 營運 token(hosting_ops),不必進入網站,就能開始部署、查看部署狀態與應用程式輸出的日誌。
從 HRUM MCP 0.3.3 起,也能用 MCP 工具做同樣的事:hrum_hosting_deploy(開始部署)、hrum_hosting_deploys(部署狀態)、hrum_hosting_logs(執行日誌)。先用 hrum_ai_connect 取得具 hosting_ops 權限的 token 再呼叫,應用程式 ID 可在 hrum_hosting_status 查看。不使用 MCP 的工具請用下面的 HTTP 路徑。
| 作業 | 請求 | 回應 |
|---|---|---|
| 開始部署 | POST …/hosting/apps/{appId}/deploy,內容 {} 或 {"commit":"40-char sha"} | {"deployId","commitSha","retried","status":"queued"}。與主控台的「立即部署」相同,建置所連結分支的最新 commit(首次部署審查與方案規則也相同)。commit 只接受該最新 commit — 舊的 commit 目前還不支援(400 COMMIT_NOT_BRANCH_HEAD)。每分鐘最多 2 次 |
| 部署狀態 | GET …/hosting/apps/{appId}/deploys?limit=20 | 由新到舊:id、commitSha、status、queuedAt、startedAt、finishedAt、liveAt、failReason、scanFindings(僅列出機密值掃描命中的檔案、行數、規則)、logTail(建置日誌的結尾)、startFailReason、startFailLog |
| 請求日誌 | POST …/hosting/apps/{appId}/logs,內容 {"lines":100}(1–200) | 202 {"requestId"} |
| 取得日誌 | GET …/hosting/apps/{appId}/logs/{requestId} | status 為 pending 時請在 2–3 秒後重試,為 delivered 時讀取 lines。超過 3 分鐘會變成 expired |
日誌與失敗原因在送出前會被遮蔽:該應用程式儲存的環境變數值,以及 sk-…、AKIA…、Bearer …、JWT、…_live_… 這類金鑰形式的字串,都會變成 [redacted]。即便如此,最重要的仍是讓應用程式不要把機密值寫進日誌。所有呼叫(包含被拒絕的)都會連同 token、應用程式、結果一起記錄。
主控台登入工作階段或 HRUM MCP 登入工作階段也有相同的路徑:POST …/console/hosting/apps/{appId}/deploy-now(MCP 僅限透過註冊建立的工作階段)、GET …/console/hosting/apps/{appId}/deploys、POST …/console/hosting/apps/{appId}/logs,內容 {"lines":100}(1–200,MCP 僅限透過註冊建立的工作階段)→ GET …/logs/{requestId}。只能用於自己的應用程式,日誌內容依相同規則遮蔽。取得的日誌內容會在傳送(或請求)後 24 小時刪除(2026-12-01 起改為 7 天,服務條款 第20條第5項)。
HRUM_CM_TOKEN=$(security find-generic-password -s hrum-console-ops -w)
API=https://api.hrum.ai/api/v1/partners/v1/console-ai/hosting/apps/$APP_ID
git push origin main
curl -s -X POST -H @<(printf 'Authorization: Bearer %s' "$HRUM_CM_TOKEN") \
-H 'Content-Type: application/json' -d '{}' "$API/deploy" | jq '.data // .'
curl -s -H @<(printf 'Authorization: Bearer %s' "$HRUM_CM_TOKEN") \
"$API/deploys?limit=3" | jq '.data.deploys[] | {id, commitSha, status, liveAt, failReason}'
機密金鑰安全規則(AI 工具須遵守)
- 不要要求使用者把值貼到聊天中。請使用者存進鑰匙圈或密碼管理工具,只詢問項目名稱。
- 即使使用者已把值貼到聊天中,也不要再次輸出。該值已留在對話紀錄中,請建議使用者到簽發單位重新核發並替換。
- 把值讀進 shell 變數,再以標準輸入傳遞。不要使用
curl -d "value"、echo value、set -x等會讓值留在命令列或日誌中的方法。 - 不要把值寫進程式碼、會被 commit 的
.env、PROGRESS.md、日誌或畫面輸出。回報只寫「名稱與是否儲存成功」。 - AI 途徑拒絕的名稱(見上文)不要試圖繞過,請交由人在主控台加入。
- 營運 token(
hrum_cm_…)也要比照值來處理。用完後請提醒使用者在主控台撤銷。
實際發生過的例子:一個正在製作銷售管理應用程式的 AI 工具,想把應用程式的主金鑰放進環境變數,但當時沒有可供 AI 使用的營運途徑,於是就停在那裡。現在像 MASTER_KEY 這樣以 _KEY 結尾的名稱,可以用 AI 營運 token 設定,其他名稱則由人在主控台加入。無論哪一種,值都不會經過聊天。
環境變數錯誤
錯誤內容的格式為 {"success":false,"statusCode":…,"message":"…"}。環境變數錯誤沒有 code,請以狀態碼與下列訊息的開頭來區分。API 以韓文回傳這些訊息,因此下表照原樣列出各訊息的開頭,並附上意思。訊息全文請見 llms.txt。
| 狀態 | 訊息開頭 | 原因 → 解決方式 |
|---|---|---|
| 400 | 이름은 대문자·숫자·밑줄만(名稱只能用英文大寫、數字、底線) | 名稱不符合規則 → 只用英文大寫、數字、底線,不以數字開頭,最多 64 個字元 |
| 400 | 플랫폼이 쓰는 이름이라(平台使用的名稱) | PORT、HOSTNAME、NODE_OPTIONS、DATABASE_URL,或以 RIDM_ / PG 開頭的名稱 → 請改用其他名稱 |
| 400 | AI 연결이 자동으로 넣는 이름이라(由 AI 連結自動設定) | HRUM_API_KEY → 此應用程式已開啟 AI 連結,由平台設定。若要自行設定,請關閉 AI 連結 |
| 400 | 이 계정에서 발급한 API 키만 넣을 수 있어요(只能使用此帳號核發的金鑰) | 請使用在您自己主控台「API 金鑰」核發的金鑰 |
| 400 | AI 연결이 앱마다 만든 키는 넣을 수 없어요(不能使用 AI 連結為各應用程式建立的金鑰) | 請使用在主控台「API 金鑰」核發的金鑰 |
| 400 | 값을 입력해 주세요(請輸入值) | 值是空的 |
| 400 | 값에 줄바꿈을 넣을 수 없(值不能包含換行) | 多行的值(PEM 私密金鑰等)→ 轉成單行 base64 放入,在應用程式中解碼使用 |
| 400 | 값은 2048바이트까지(值最多 2048 位元組) | 值超過 2KB → 較大的值請存在資料庫或外部機密儲存區 |
| 400 | 실행 환경을 바꾸는 이름이라 AI 경로(會改變執行環境的名稱,AI 途徑不可用) | AI 途徑拒絕的名稱 → 由人在主控台加入 |
| 400 | AI 경로(AI 운영 토큰·MCP)로는 _KEY(AI 途徑只能用 _KEY… 等結尾) | 不是機密名稱的結尾 → 更改名稱,或由人在主控台加入 |
| 400 | Validation failed (uuid is expected) | 應用程式 ID 不是 UUID → 請使用 GET /console-ai/hosting 的 apps[].id |
| 401 | MGMT_TOKEN_INVALID | 沒有 token,或已過期、已撤銷 → 重新核發 |
| 403 | MGMT_SCOPE_DENIED (scope: "hosting_ops") | token 沒有 hosting_ops → 勾選後重新核發 |
| 404 | 앱을 찾을 수 없(找不到應用程式) | 其他帳號的應用程式或已刪除的應用程式 → 確認應用程式 ID |
| 404 | 없는 환경변수(不存在的環境變數) | 要刪除的名稱不存在 → 確認名稱清單 |
| 409 | 해지된 앱은 환경변수를 바꿀 수 없(已解約的應用程式) | 應用程式正在解約中 → 無法變更 |
| 409 | 환경변수는 앱당 50개까지(每個應用程式最多 50 個) | 刪除不用的名稱後再試一次 |
| 429 | — | 新增與刪除每分鐘最多 30 次 → 稍候再試 |
| 503 | 환경변수 저장소가 준비되지 않(環境變數儲存區尚未就緒) | 伺服器端的問題 → 稍候再試,持續發生請與我們聯絡 |
AI 連結
這是由平台放入僅供此應用程式使用的 API 金鑰,讓應用程式可以呼叫八字 API 與 AI API 的功能。所有帳號都可以使用。
- 開啟 — 在主控台的 應用程式 打開應用程式詳細資料,開啟「使用 AI 連結」。系統會建立應用程式專用金鑰並放入環境變數
HRUM_API_KEY,應用程式會重新啟動。 - 呼叫 — 在應用程式的伺服器程式碼中讀取
process.env.HRUM_API_KEY,放進X-Partner-Api-Key標頭。金鑰的值在主控台也看不到。請不要放進會送到瀏覽器的程式碼。
開啟期間無法自行設定 HRUM_API_KEY。若已自行設定值,請在開啟前刪除(不刪除的話,會出現要求先刪除既有 HRUM_API_KEY 環境變數的錯誤)。用這個金鑰產生的費用會從您的點數扣除,達到在應用程式詳細資料中設定的每日使用上限後,當天就會停止。關閉後金鑰立即失效,再次開啟會建立新的金鑰。這個金鑰無法呼叫付款 API — 在應用程式中收款 請使用在主控台核發的金鑰。
在應用程式中收款
可以透過 HRUM 付款頁面向應用程式的使用者收款。以賣家(個人、個人事業、法人)身分登記並通過核准後,即可開始銷售。賣家登記請在主控台的 結算 進行。條件由 服務條款 第32–39條(韓文) 規定。免費方案的應用程式也可以銷售。不過,在達到每月傳輸量上限或遭停權而停止公開的期間,開啟新付款會以 409 APP_NOT_SERVING 拒絕。已開啟的付款、訂單查詢與退款仍可照常使用。
- 放入 API 金鑰 — 把在主控台 API 金鑰 核發的金鑰放進 環境變數(例如:
HRUM_PARTNER_KEY)。「AI 連結」放入的HRUM_API_KEY無法呼叫付款 API。金鑰只在伺服器程式碼中使用,絕對不要送到瀏覽器。 - 登記商品 —
POST /api/v1/partners/v1/storefront/skus,內容{"appId","name","priceWon"}。付款只會以這裡登記的價格進行。 - 開啟付款 — 從伺服器以內容
{"appId","skuId","qty","returnUrl"}送出POST /api/v1/partners/v1/storefront/checkouts,並把使用者導向回應中的checkoutUrl。returnUrl只能是此應用程式的 https 網址(<name>.ridm.ai或連結的網域)。 - 確認結果 — 付款完成後,使用者會回到
returnUrl?orderId=…。請在伺服器以GET /api/v1/partners/v1/storefront/orders/{orderId}確認status為paid後再提供商品。不要只相信網址上附帶的值。
所有請求都需要 X-Partner-Api-Key 標頭。需要退款時,請附上訂單編號寄信至 [email protected]。退款後,訂單的 status 會變為 canceled 或 partial_canceled。
const res = await fetch("https://api.hrum.ai/api/v1/partners/v1/storefront/checkouts", {
method: "POST",
headers: { "Content-Type": "application/json", "X-Partner-Api-Key": process.env.HRUM_PARTNER_KEY },
body: JSON.stringify({ appId, skuId, qty: 1, returnUrl: "https://myapp.ridm.ai/paid" }),
});
const { checkoutUrl } = (await res.json()).data;
各金鑰權限可呼叫的項目
建立金鑰時可以選擇權限。呼叫所選權限以外的路徑會回傳 403 KEY_SCOPE_MISSING。未選擇權限的既有金鑰仍可呼叫所有路徑。完整路徑請見 OpenAPI 文件。
payments— 登記商品POST /storefront/skus、開啟付款POST /storefront/checkoutsorders.read— 查詢訂單GET /storefront/orders/{orderId}refunds— 退款結果透過訂單的status與order.refundedWebhook 取得settlement.read— 結算資料GET /settlement/sales·/settlement/payouts·/settlement/summarywebhooks— 賣家 Webhook 的網址登記與傳送紀錄
結算資料 API
可以從伺服器取得與 主控台 → 結算 畫面相同的數字。金鑰只能看到您自己的資料。期間 from / to 以韓國日期(YYYY-MM-DD,含首尾兩天)指定,留空則為本月。一次最多 366 天。
GET /api/v1/partners/v1/settlement/sales?from=&to=&skuId=&limit=&cursor=— 每筆銷售的付款金額(paidWon)、HRUM 銷售手續費(salesCommissionWon,含 VAT)、每筆付款手續費(perOrderFeeWon)、刷卡手續費(pgFeeWon)、應撥款金額(sellerWon)、退款(refundedWon)。皆為扣除退款後的值。totals不是這一頁,而是整個期間的合計。GET /api/v1/partners/v1/settlement/payouts?from=&to=&status=scheduled|completed|unpaid— 每筆撥款的grossWon= 匯出金額(amountWon)+ 撥款手續費(feeWon)+ 其 VAT(feeVatWon)+ 個人賣家扣繳稅款 3.3%(withholdingWon)。期間以撥款日為準。GET /api/v1/partners/v1/settlement/summary?from=&to=— 一次取得銷售合計、預定撥款與已撥款合計,以及目前的撥款手續費。
const res = await fetch("https://api.hrum.ai/api/v1/partners/v1/settlement/summary?from=2026-11-01&to=2026-11-30", {
headers: { "X-Partner-Api-Key": process.env.HRUM_PARTNER_KEY },
});
const { sales, payouts, payoutFee } = (await res.json()).data;
賣家 Webhook
發生付款完成、退款、撥款時,會通知您的伺服器。網址只接受 https://(連接埠 443、8443),無法登記私有或內部位址。
- 登記網址 —
PUT /api/v1/partners/v1/webhooks/endpoint,內容{"url":"https://myapp.ridm.ai/hrum/webhook"}。回應中的secret(whsec_…)只在此時顯示一次。請立即放進伺服器環境變數HRUM_WEBHOOK_SECRET。要重新核發請送出{"url": …, "rotateSecret": true}。 - 事件 —
order.paid(付款完成)、order.refunded(一筆退款)、payout.scheduled(預定撥款)、payout.completed(撥款完成)、webhook.test(POST /webhooks/test)。內容為{"id","type","created","data"},不含購買者資訊。同一件事只會以相同的id建立一次,請以id排除重複。 - 平台副本 — 以平台金鑰登記網址時,也會收到在該平台開立的賣家訂單之
order.paid、order.refunded副本。標頭與簽章相同,id與賣家端不同。data中另外含有sellerId、spaceId。 - 驗證簽章 — 標頭為
Hrum-Signature: t=<unix seconds>,v1=<hex>。v1是以機密值計算(t + "." + the raw body as received)的 HMAC-SHA256。請拒絕超過 5 分鐘的t。 - 重新傳送 — 若未在 10 秒內以 2xx 回應,會在 1 分鐘、5 分鐘、30 分鐘、2 小時、12 小時後重新傳送(最多 6 次)。傳送紀錄可用
GET /webhooks/deliveries查看,重新傳送請用POST /webhooks/deliveries/{eventId}/redeliver。
const crypto = require("node:crypto");
function verifyHrumWebhook(rawBody, header, secret, toleranceSec = 300) {
const parts = Object.fromEntries(String(header || "").split(",").map((p) => p.trim().split("=")));
const t = Number(parts.t);
if (!Number.isInteger(t) || Math.abs(Date.now() / 1000 - t) > toleranceSec) return false;
const want = crypto.createHmac("sha256", secret).update(`${t}.${rawBody}`).digest();
const got = Buffer.from(parts.v1 || "", "hex");
return got.length === want.length && crypto.timingSafeEqual(got, want);
}
// Express: verify the raw body before parsing it as JSON
app.post("/hrum/webhook", express.raw({ type: "application/json" }), (req, res) => {
const raw = req.body.toString("utf8");
if (!verifyHrumWebhook(raw, req.get("Hrum-Signature"), process.env.HRUM_WEBHOOK_SECRET)) return res.sendStatus(400);
const event = JSON.parse(raw); // if event.id was already handled, just return 200
res.sendStatus(200);
});
首次部署與自動檢查
第一次建置成功後,會經過自動檢查並自動核准,網址隨即公開。第一次部署公開之前,不會扣除付費方案的費用。儲存庫中含有機密值(金鑰、token、密碼)時,建置會失敗。即使發現新的對外連線對象、新的危險模式,或儲存庫擁有者變更,部署仍會自動反映,相關內容會被記錄。所有自動核准與檢查結果都會記錄,並由營運人員事後確認,若有問題可能會停止公開。停止公開時,會以電子郵件與應用程式畫面通知原因。禁止行為請見 條款 第26條(韓文)。
價格與上限
各方案的價格、記憶體、資料庫、每月傳輸量請見 價格頁面。付費方案的費用每月從儲值的點數中扣除。扣款日餘額不足時應用程式會停止,儲值後會自動恢復。每月傳輸量是傳給訪客的回應與應用程式對外送出的流量(包含呼叫外部 API、上傳、寫入資料庫)的合計。WebSocket 收送的訊框兩個方向都會計入。達到上限時,開啟中的 WebSocket 也會以 1008 關閉。達到上限時,公開與應用程式執行會一起停止(次月 1 日恢復);付費方案可在應用程式畫面購買傳輸量區塊,幾分鐘內就能恢復。達到 80% 與達到上限時,會以電子郵件通知您。
備份與解約
- 可在應用程式畫面的「資料庫備份」建立資料庫傾印。會產生有效 1 小時的下載連結,每天最多建立 3 次。
- 解約後,付費方案會在已付款期間結束當天停止,之後 30 天內仍可下載資料或還原。超過 30 天,應用程式與資料庫會被刪除,無法復原。已扣除的費用不會退還。
聯絡我們:contact@float.do