[私人測試版]{class="badge informative"}

獎勵定義指南 reward-definition-guide

目錄

開始應對忠誠度挑戰

AVAILABILITY
此功能目前在​ 私人測試版 ​中。 如需Journey Optimizer中發行週期與可用性階段的完整詳細資訊,請參閱發行週期

當挑戰任務、里程碑或挑戰完成​ 並設定了獎勵值 ​時,平台會呼叫您的獎勵提供者的HTTP端點並使用JSON裝載來發出獎勵。 獎勵定義​說明問題的獎勵,並提供JSONata運算式 — rewardJsonata — 以圖形化您的提供者所期望的確切裝載。

本指南涵蓋如何設定獎勵提供者、建立獎勵定義、撰寫rewardJsonata運算式,以及瞭解評估時可供使用的內容。

雙層模型

獎勵分為兩個層級:

Reward Provider  (endpoint, auth, headers)
└── Reward Definition  (denomination, rewardJsonata)
└── Reward Definition
└── ...

獎勵提供者​代表單一外部獎勵系統 — 它包含傳遞端點URL、驗證及任何自訂HTTP標頭。 一個提供者可以保留多個​獎勵定義,每個定義都描述該提供者提供的不同獎勵型別或面額(例如「50顆星」、「雙顆星」、「免費專案」)。

質詢會依據GUID參考提供者和定義。 當發出獎勵時,平台會評估定義的rewardJsonata運算式,並將結果POST至提供者的端點。

獎勵提供者與定義欄位

獎勵提供者欄位
table 0-row-4 1-row-4 2-row-4 3-row-4 4-row-4 5-row-4 6-row-4 7-row-4 8-row-4 html-authored
欄位 類型 必要 說明
guid String 否(系統指派) 唯一識別碼。 唯讀。
name String 顯示名稱,組織內唯一。
desc String 提供者可讀取的說明。
enabled Boolean false時,已針對此提供者下的所有定義暫停
獎勵傳遞。
url String 接收獎勵裝載的HTTP端點。
平台POST將評估過的
rewardJsonata輸出傳至此URL。
additionalHeaders Object 自訂HTTP標頭,可包含在每
個傳遞要求中(例如API金鑰、
內容型別覆寫)。
maxRatePerSecond Integer 選擇性的每個提供者速率限制(1-5000)。
Null表示無限制。
enableMTLS Boolean 端點是否需要雙向TLS。
獎勵定義欄位
table 0-row-4 1-row-4 2-row-4 3-row-4 4-row-4 5-row-4 6-row-4 7-row-4 html-authored
欄位 類型 必要 說明
guid String 否(系統指派) 唯一識別碼。 唯讀。
name String 顯示名稱,在提供者中唯一。
denomination String 獎勵的單位,用於顯示
,可在運算式中作為
reward.denomination
使用(例如"Stars""Points""Miles")。
desc String 獎勵的說明,可在運算式中以reward.desc形式取得
enabled Boolean false時,此定義為非使用中
且不會發出獎勵。
isDefault Boolean 將此專案標籤為沙箱範圍的預設
獎勵定義。 所有提供者一次只能有一個定義
是預設值;
設定新的預設值會清除上一個定義。
用於在發佈時自動填入
個人化挑戰的獎勵詳細資料。
rewardJsonata String JSONata運算式在
獎勵問題時間評估。 接收完整
獎勵內容,且必須將JSON
裝載傳回至POST給提供者。

獎勵內容

評估rewardJsonata時,它會收到包含獎勵事件所有已知內容的單一根物件。 運算式中的所有路徑都與此根相關。

{
  "rewardContext": {
    "rewardValue": "50",
    "source":      "challenge"
  },
  "reward": {
    "name":         "500 Stars",
    "desc":         "Issue 500 Stars to the member",
    "denomination": "Stars",
    "enabled":      true
  },
  "task": { ... },
  "milestone": { ... },
  "challenge": { ... },
  "timestamp": "2026-02-10T00:29:22.538+00:00"
}
內容欄位
table 0-row-2 1-row-2 2-row-2 3-row-2 4-row-2 5-row-2 6-row-2 7-row-2 8-row-2 9-row-2 10-row-2 11-row-2 12-row-2 13-row-2 14-row-2 15-row-2 16-row-2
欄位 說明
rewardContext.rewardValue 在觸發此發行的挑戰、任務或里程碑上設定的獎勵值字串。
rewardContext.source 觸發獎勵的專案: "task""challenge""milestone"
reward RewardDefinition本身 — namedescdenomination
task 完成的工作,包括其accumulatorsschedulereward
task.accumulators.spend 任務累積的合格總支出。
task.accumulators.qty 任務累積的合格專案總數。
task.accumulators.item_list 套用至任務的所有合格專案。 每個專案都有itemtransactionIdtimestamputcOffsetlocationId
task.accumulators.item_list[-1] 最近套用的專案(JSONata負索引)。 對於取得最後一個交易ID或時間戳記非常有用。
task.schedule.currentStreak 目前的連續造訪連續計數(針對連續挑戰)。
task.schedule.currentVisits 造訪總數(針對造訪挑戰)。
milestone 觸發此獎勵的里程碑;若不是里程碑獎勵,則為null。 包含countreward.rewardValue
challenge.profileId 成員的熟客ID。
challenge.kvpCustom 在挑戰設定的自訂索引鍵值配對。 傳遞行銷活動ID、產品名稱或提供者專用中繼資料的常見模式。
challenge.name 挑戰名稱。
challenge._id 挑戰ID。
timestamp 獎勵簽發的ISO 8601時間戳記。

撰寫rewardJsonata運算式

運算式會接收獎勵內容作為其輸入,且必須傳回JSON物件 — 裝載已對提供者的端點進行POST。 該物件的形狀完全取決於提供者的API;您可以將內容欄位對應到提供者期望的任何結構。

簡單固定裝載

最簡單的情況:提供者需要點數和成員ID,兩者都從內容中得知。

code language-jsonata
{
  "memberId":   challenge.profileId,
  "points":     $number(rewardContext.rewardValue),
  "currency":   reward.denomination
}

輸出:

code language-json
{
  "memberId": "ADB-0000030",
  "points":   50,
  "currency": "Stars"
}

rewardContext.rewardValue永遠是字串。 如果您的提供者需要數值,請使用$number()進行轉換。

針對提供者特定的中繼資料使用kvpCustom

提供者通常需要行銷活動ID或原始系統程式碼等欄位,這些欄位是每個挑戰執行所專屬。 編寫挑戰時將這些專案儲存在challenge.kvpCustom中,然後在運算式中參照它們 — 讓運算式可跨行銷活動重複使用。

code language-jsonata
{
  "memberId":         challenge.profileId,
  "points":           $number(rewardContext.rewardValue),
  "campaignId":       challenge.kvpCustom.campaignId,
  "transactionSource": "AJO"
}

您也可以將reward.kvpCustom用於固定特定獎勵型別(而非每個挑戰)的常數。

使用工作累計器資料

任務累計器會儲存每個合格事件的記錄。 使用item_list[-1]存取最近套用的專案 — 其transactionIdtimestamp對於提供者端的稽核追蹤和重複資料刪除很有用。

code language-jsonata
{
  "memberId":       challenge.profileId,
  "points":         $number(rewardContext.rewardValue),
  "transactionId":  task.accumulators.item_list[-1].transactionId,
  "transactionDate": task.accumulators.item_list[-1].timestamp
}
建構文字訊息

對於通知型提供者(Slack、簡訊、電子郵件),您可以使用JSONata的&串連運運算元直接建置訊息字串:

code language-jsonata
{
  "text": "You just earned " & rewardContext.rewardValue & " " & reward.denomination & "!"
}

輸出:

code language-json
{
  "text": "You just earned 50 Stars!"
}

範例

範例1 — 簡單點提供者

案例:​基本熟客點數API需要會員ID與點數。

獎勵定義:

code language-json
{
  "name":         "Standard Points",
  "denomination": "Points",
  "desc":         "Award loyalty points",
  "enabled":      true,
  "rewardJsonata": "{\"memberId\": challenge.profileId, \"pointQuantity\": $number(rewardContext.rewardValue), \"denomination\": reward.denomination}"
}

格式化運算式:

code language-jsonata
{
  "memberId":      challenge.profileId,
  "pointQuantity": $number(rewardContext.rewardValue),
  "denomination":  reward.denomination
}

裝載張貼至提供者:

code language-json
{
  "memberId":      "ADB-0000030",
  "pointQuantity": 50,
  "denomination":  "Points"
}
範例2 — 包含行銷活動中繼資料的提供者裝載

案例:​提供者需要包含稽核欄位、行銷活動參照和成員說明的結構化獎勵記錄。 行銷活動特定值儲存在challenge.kvpCustom中,因此相同的獎勵定義可在行銷活動間運作,而不需編輯運算式。

挑戰kvpCustom (在編寫挑戰時設定):

code language-json
{
  "parentCampaignId": "CAMP-2026-Q1",
  "productName":      "Loyalty Program"
}

獎勵定義:

code language-json
{
  "name":         "Stars — Campaign Award",
  "denomination": "Stars",
  "desc":         "Issue Stars for completing a qualifying purchase",
  "enabled":      true,
  "rewardJsonata": "{\"awardPoints\":[{\"idType\":\"externalId\",\"id\":challenge.profileId,\"transactionId\":task.accumulators.item_list[-1].transactionId,\"transactionDate\":task.accumulators.item_list[-1].timestamp,\"originalTransactionId\":task.accumulators.item_list[-1].transactionId,\"transactionSource\":\"AJO\",\"channelSource\":\"Web\",\"parentCampaignId\":challenge.kvpCustom.parentCampaignId,\"productName\":challenge.kvpCustom.productName,\"memberAwardDescription\":reward.desc,\"pointQuantity\":$number(rewardContext.rewardValue)}]}"
}

格式化運算式:

code language-jsonata
{
  "awardPoints": [
    {
      "idType":                "externalId",
      "id":                    challenge.profileId,
      "transactionId":         task.accumulators.item_list[-1].transactionId,
      "transactionDate":       task.accumulators.item_list[-1].timestamp,
      "originalTransactionId": task.accumulators.item_list[-1].transactionId,
      "transactionSource":     "AJO",
      "channelSource":         "Web",
      "parentCampaignId":      challenge.kvpCustom.parentCampaignId,
      "productName":           challenge.kvpCustom.productName,
      "memberAwardDescription": reward.desc,
      "pointQuantity":         $number(rewardContext.rewardValue)
    }
  ]
}

裝載張貼至提供者:

code language-json
{
  "awardPoints": [
    {
      "idType":                "externalId",
      "id":                    "ADB-0000030",
      "transactionId":         "b4fa0e89-f4bb-41ce-b370-fb97f9c52f1a",
      "transactionDate":       "2026-02-08T00:12:00.000+00:00",
      "originalTransactionId": "b4fa0e89-f4bb-41ce-b370-fb97f9c52f1a",
      "transactionSource":     "AJO",
      "channelSource":         "Web",
      "parentCampaignId":      "CAMP-2026-Q1",
      "productName":           "Loyalty Program",
      "memberAwardDescription": "Issue Stars for completing a qualifying purchase",
      "pointQuantity":         50
    }
  ]
}
範例3 — 里程碑獎勵

案例: Streak挑戰會每隔N次造訪發出里程碑獎勵。 運算式包含里程碑計數以及提供者端內容的目前連結。

格式化運算式:

code language-jsonata
{
  "memberId":       challenge.profileId,
  "points":         $number(rewardContext.rewardValue),
  "milestoneCount": milestone.count,
  "currentStreak":  task.schedule.currentStreak,
  "denomination":   reward.denomination,
  "source":         rewardContext.source
}

裝載已發佈至提供者 (在第2次造訪里程碑時):

code language-json
{
  "memberId":       "ADB-0000030",
  "points":         20,
  "milestoneCount": 2,
  "currentStreak":  2,
  "denomination":   "Stars",
  "source":         "milestone"
}

rewardContext.source"milestone"時,milestone物件會填入countreward.rewardValue。 當來源是"task""challenge"時,milestonenull

API 參考

獎勵提供者
code language-http
POST   /loyalty/metadata/config/rewards/providers
GET    /loyalty/metadata/config/rewards/providers
GET    /loyalty/metadata/config/rewards/providers/{providerId}
PUT    /loyalty/metadata/config/rewards/providers/{providerId}
DELETE /loyalty/metadata/config/rewards/providers/{providerId}

所有要求都需要x-gw-ims-org-idx-sandbox-name標頭。

建立提供者:

code language-http
POST /loyalty/metadata/config/rewards/providers
x-gw-ims-org-id: {ORG_ID}
x-sandbox-name: {SANDBOX}
Content-Type: application/json

{
  "name":    "My Points Provider",
  "desc":    "Issues loyalty points via REST",
  "enabled": true,
  "url":     "https://rewards.example.com/award",
  "additionalHeaders": {
    "x-api-key": "YOUR_API_KEY"
  }
}
獎勵定義
code language-http
POST   /loyalty/metadata/config/rewards/definitions/{providerId}
GET    /loyalty/metadata/config/rewards/definitions/{providerId}
GET    /loyalty/metadata/config/rewards/definitions/{providerId}/{rewardId}
PUT    /loyalty/metadata/config/rewards/definitions/{providerId}/{rewardId}
DELETE /loyalty/metadata/config/rewards/definitions/{providerId}/{rewardId}

建立獎勵定義:

code language-http
POST /loyalty/metadata/config/rewards/definitions/{providerId}
x-gw-ims-org-id: {ORG_ID}
x-sandbox-name: {SANDBOX}
Content-Type: application/json

{
  "name":         "50 Stars",
  "denomination": "Stars",
  "desc":         "Award 50 Stars on task completion",
  "enabled":      true,
  "rewardJsonata": "{ \"memberId\": challenge.profileId, \"points\": $number(rewardContext.rewardValue) }"
}

運算式驗證

rewardJsonata運算式已在發佈時針對語法進行驗證。 如果運算式無效,API會傳回422錯誤,其中包含剖析失敗的描述。

若要在發佈之前開發和測試運算式,請使用JSONata Exerciser。 將獎勵內容JSON貼上為輸入檔案和您的運算式,以驗證輸出符合您的提供者期望。 每個觸發程式型別(taskmilestonechallenge)的代表性獎勵內容會顯示在上面的範例中。

常見錯誤

錯誤
效果
修正
rewardContext.rewardValue已用為數字但未轉換
如果提供者驗證欄位為數值,則型別不符
$number(rewardContext.rewardValue)換行
challenge.kvpCustom.someKey傳回null
編寫時挑戰未設定金鑰
確保在使用這個定義的每個挑戰上kvpCustom中都存在金鑰
task.accumulators.item_list[-1]為null
未套用任何專案後才簽發獎勵(非購買事件)
以條件式保全,或改用內容中的timestamp
milestone在來源為"task""challenge"時存取
milestone為空;運算式擲回或產生null欄位
存取milestone前請先檢查rewardContext.source,或僅在附加至里程碑獎勵的定義中使用milestone
運算式傳回陣列而非物件
提供者接收未預期的裝載結構
在外部物件中換行傳回陣列的運算式: { "items": [...] }
recommendation-more-help
journey-optimizer-help