奖励定义指南 reward-definition-guide

在此页面上:​了解如何配置奖励提供者和奖励定义、编写奖励JSONata表达式以及了解用于生成履行有效负载的上下文。

当质询任务、里程碑或质询完成​ 并配置奖励值 ​时,平台将通过使用JSON有效负载调用奖励提供商的HTTP端点来发出奖励。 奖励定义​描述了问题的奖励,并提供了一个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表达式在
reward-issue时间进行计算。 接收完整的
奖励上下文,并且必须将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本身 — name、desc、denomination。
task 正在完成任务,包括其accumulators、schedule和reward。
task.accumulators.spend 任务累计的符合条件的总支出。
task.accumulators.qty 任务累计的合格项目总数。
task.accumulators.item_list 应用于任务的所有符合条件的项目。 每个条目都有item、transactionId、timestamp、utcOffset、locationId。
task.accumulators.item_list[-1] 应用的最新项目(JSONata负索引)。 对于来源补充最后一个交易ID或时间戳非常有用。
task.schedule.currentStreak 当前连续访问连续计数(针对连续挑战)。
task.schedule.currentVisits 总访问计数(针对访问挑战)。
milestone 触发此奖励的里程碑,或者null(如果不是里程碑奖励)。 包括count和reward.rewardValue。
challenge.profileId 成员的忠诚度ID。
challenge.kvpCustom 在挑战中配置的自定义键值对。 用于传递促销活动ID、产品名称或特定于提供商的元数据的常见模式。
challenge.name 质询名称。
challenge._id 挑战ID。
timestamp 奖励发放的ISO 8601时间戳。

编写rewardJsonata表达式

表达式接收奖励上下文作为其输入,并且必须返回一个JSON对象,该对象有效负载已发布到提供程序的端点。 该对象的形状完全取决于提供程序的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]访问最近应用的项 — 它的transactionId和timestamp对于提供程序端的审核跟踪和重复数据删除非常有用。

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对象已填充count和reward.rewardValue。 当源为"task"或"challenge"时,milestone为null。

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-id和x-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粘贴为输入文档和您的表达式,以验证输出是否与提供商的期望相匹配。 上述示例中显示了每个触发器类型(task、milestone、challenge)的代表性奖励上下文。

常见错误

错误
效果
修复
rewardContext.rewardValue用作无转换的数字
如果提供程序验证字段是否为数字,则类型不匹配
使用$number(rewardContext.rewardValue)换行
challenge.kvpCustom.someKey返回空值
创作时未对质询设置键
确保在使用此定义的每个质询上的kvpCustom中存在密钥
task.accumulators.item_list[-1]为空
在发放奖励之前没有应用任何项目(非购买事件)
带条件的护卫或改用上下文中的timestamp
milestone在源为"task"或"challenge"时访问
milestone为null;表达式抛出或生成null字段
在访问milestone之前检查rewardContext.source,或仅在附加到里程碑奖励的定义中使用milestone
表达式返回数组而不是对象
提供程序接收意外的负载结构
将返回数组的表达式包装在外对象中: { "items": [...] }

操作说明视频 video

➡️观看如何设置忠诚度奖励提供商

recommendation-more-help
journey-optimizer-help