[Private Beta]{class="badge informative"}

Guide de définition de la récompense reward-definition-guide

Table des matières

Prise en main des défis de fidélité

AVAILABILITY
Cette fonctionnalité est actuellement en version bêta privée. Pour plus d’informations sur le cycle de publication et les phases de disponibilité dans Journey Optimizer, voir cycle de publication.

Lorsqu’une tâche de défi, un jalon ou un défi se termine et qu’une valeur de récompense est configurée, la plateforme émet une récompense en appelant le point d’entrée HTTP du fournisseur de récompense avec une payload JSON. Une Définition de récompense décrit la récompense à émettre et fournit une expression JSONata, rewardJsonata, qui définit la payload exacte attendue par votre fournisseur.

Ce guide explique comment configurer un fournisseur de récompense, créer des définitions de récompense, écrire l’expression de rewardJsonata et comprendre le contexte disponible au moment de l’évaluation.

Modèle à deux niveaux

Les récompenses sont organisées sur deux niveaux :

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

Un fournisseur de récompenses représente un système de récompenses externe unique ; il contient l’URL du point d’entrée de diffusion, l’authentification et tous les en-têtes HTTP personnalisés. Un fournisseur peut détenir plusieurs Définitions de récompense, chacune décrivant un type de récompense ou une dénomination distinct offert par ce fournisseur (par exemple, « 50 étoiles », « étoiles doubles », « article gratuit »).

Un défi fait référence au fournisseur et à la définition par GUID. Lorsqu’une récompense est émise, la plateforme évalue l’expression de rewardJsonata de la définition et envoie le résultat au point d’entrée du fournisseur.

Fournisseur de récompense et champs de définition

Champs du fournisseur de récompense
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
Champ Type Obligatoire Description
guid String Non (affecté par le système) Identifiant unique. Lecture seule.
name String Oui Nom d’affichage, unique au sein de l’organisation.
desc String Non Description lisible par l’utilisateur du fournisseur.
enabled Boolean Non Lorsqu’elle est false, la diffusion de récompense est
suspendue pour toutes les définitions sous ce fournisseur.
url String Oui Point d’entrée HTTP qui reçoit la payload de récompense.
La plateforme PUBLIE la sortie évaluée
rewardJsonata sur cette URL.
additionalHeaders Object Non En-têtes HTTP personnalisés à inclure dans chaque requête
diffusion (par exemple, clés d’API, remplacements de type
contenu).
maxRatePerSecond Integer Non Limite de taux par fournisseur facultative (1-5 000).
Null signifie illimitée.
enableMTLS Boolean Non Indique si le point d’entrée nécessite un TLS mutuel.
Champs de définition de la récompense
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
Champ Type Obligatoire Description
guid String Non (affecté par le système) Identifiant unique. Lecture seule.
name String Oui Nom d’affichage, unique au sein du fournisseur.
denomination String Non Unité de la récompense, utilisée en affichage
et disponible dans les expressions comme
reward.denomination
(par exemple "Stars", "Points", "Miles").
desc String Non Description de la récompense, disponible
expressions selon les reward.desc.
enabled Boolean Non Lorsqu’elle est false, cette définition est inactive
et n’émettra pas de récompenses.
isDefault Boolean Non Le marque comme la définition de récompense
par défaut à l’échelle du sandbox. Une seule définition
pour tous les fournisseurs peut être définie par défaut à la fois ;
définir une nouvelle valeur par défaut efface la précédente.
Utilisé pour renseigner automatiquement les détails de récompense sur les défis personnalisés
moment de la publication.
rewardJsonata String Oui Expression JSONata évaluée au moment de l’émission
récompense. Reçoit le contexte
récompense complet et doit renvoyer la payload JSON
à POST au fournisseur.

Le contexte de récompense

Lorsque rewardJsonata est évalué, il reçoit un seul objet racine contenant tout ce qui est connu sur l’événement de récompense. Tous les chemins d’accès de votre expression sont relatifs à cette racine.

{
  "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"
}
Champs contextuels
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
Champ Description
rewardContext.rewardValue Chaîne de valeur de récompense configurée sur le défi, la tâche ou le jalon qui a déclenché cet événement.
rewardContext.source Ce qui a déclenché la récompense : "task", "challenge" ou "milestone".
reward La RewardDefinition elle-même : name, desc, denomination.
task Tâche d’achèvement, y compris ses accumulators, schedule et reward.
task.accumulators.spend Total des dépenses admissibles accumulées par la tâche.
task.accumulators.qty Nombre total d’éléments admissibles cumulé par la tâche.
task.accumulators.item_list Tous les éléments admissibles appliqués à la tâche. Chaque entrée a item, transactionId, timestamp, utcOffset, locationId.
task.accumulators.item_list[-1] Élément le plus récent appliqué (index négatif JSONata). Utile pour sourcer l’identifiant ou l’horodatage de la dernière transaction.
task.schedule.currentStreak Nombre actuel de séries de visites consécutives (pour les défis de série).
task.schedule.currentVisits Nombre total de visites (pour les défis de visite).
milestone Jalon ayant déclenché cette récompense, ou null s’il ne s’agit pas d’une récompense jalonnée. Inclut count et reward.rewardValue.
challenge.profileId ID de fidélité du membre.
challenge.kvpCustom Paires clé-valeur personnalisées configurées pour le défi. Modèle courant de transmission des identifiants de campagne, des noms de produit ou des métadonnées spécifiques au fournisseur.
challenge.name Nom du défi.
challenge._id Identifiant du défi.
timestamp Date et heure ISO 8601 de l’émission de la récompense.

Écrire l’expression rewardJsonata

L’expression reçoit le contexte de récompense en tant qu’entrée et doit renvoyer un objet JSON , la payload POSTed au point d’entrée du fournisseur. La forme de cet objet dépend entièrement de l’API du fournisseur ; vous mappez les champs de contexte sur la structure attendue par le fournisseur.

Payload fixe simple

Le cas le plus simple : le fournisseur a besoin d’un nombre de points et d’un identifiant de membre, tous deux connus du contexte.

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

Output:

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

rewardContext.rewardValue est toujours une chaîne. Utilisez $number() pour le convertir si votre fournisseur attend une valeur numérique.

Utilisation de kvpCustom pour les métadonnées spécifiques au fournisseur

Les fournisseurs ont souvent besoin de champs tels que les identifiants de campagne ou les codes système source spécifiques à chaque exécution de défi. Stockez-les en challenge.kvpCustom lors de la création du défi, puis référencez-les dans l’expression pour que l’expression reste réutilisable dans toutes les campagnes.

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

Vous pouvez également utiliser des reward.kvpCustom pour les constantes qui sont fixes pour un type de récompense donné plutôt que par défi.

Utilisation des données de l’accumulateur de tâches

Les accumulateurs de tâches conservent un enregistrement de chaque événement admissible. Utilisez item_list[-1] pour accéder à l’élément le plus récemment appliqué. Ses transactionId et timestamp sont utiles pour les pistes d’audit et la déduplication du côté fournisseur.

code language-jsonata
{
  "memberId":       challenge.profileId,
  "points":         $number(rewardContext.rewardValue),
  "transactionId":  task.accumulators.item_list[-1].transactionId,
  "transactionDate": task.accumulators.item_list[-1].timestamp
}
Construire un message texte

Pour les fournisseurs basés sur les notifications (Slack, SMS, e-mail), vous pouvez créer une chaîne de message directement à l’aide de l’opérateur de concaténation & de JSONata :

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

Output:

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

Exemples

Exemple 1 — Fournisseur de points simples

Scénario : une API de points de fidélité de base exige un ID de membre et un montant de point.

Définition de la récompense :

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}"
}

Expression formatée :

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

Payload POSTed to provider:

code language-json
{
  "memberId":      "ADB-0000030",
  "pointQuantity": 50,
  "denomination":  "Points"
}
Exemple 2 : payload du fournisseur avec métadonnées de campagne

Scénario : le fournisseur a besoin d’un enregistrement d’attribution structuré qui inclut les champs d’audit, les références de campagne et la description du membre. Les valeurs spécifiques à une campagne sont stockées dans challenge.kvpCustom afin que la même définition de récompense fonctionne dans toutes les campagnes sans modifier l’expression.

kvpCustomdu défi (défini lors de la création du défi) :

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

Définition de la récompense :

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)}]}"
}

Expression formatée :

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)
    }
  ]
}

Payload POSTed to provider:

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
    }
  ]
}
Exemple 3 — Récompense jalonnée

Scénario : un défi en série délivre une récompense jalonnée chaque fois que l’organisation effectue une visite. L’expression inclut le nombre de jalons et la série actuelle pour le contexte côté fournisseur.

Expression formatée :

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

Payload POSTed to provider (à la 2e étape de visite) :

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

Lorsque rewardContext.source est "milestone", l’objet milestone est renseigné avec count et reward.rewardValue. Lorsque la source est "task" ou "challenge", milestone est null.

Référence d’API

Fournisseurs de récompenses
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}

Toutes les requêtes nécessitent des en-têtes x-gw-ims-org-id et x-sandbox-name.

Créer un fournisseur :

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"
  }
}
Définitions de récompense
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}

Créer une définition de récompense :

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) }"
}

Validation de l’expression

La syntaxe des expressions rewardJsonata est validée au moment de la publication. Si l’expression n’est pas valide, l’API renvoie une erreur 422 avec une description de l’échec de l’analyse.

Pour développer et tester une expression avant sa publication, utilisez l’Exercice JSONata. Collez le fichier JSON du contexte de récompense comme document d’entrée et votre expression pour vérifier que la sortie correspond à ce que votre fournisseur attend. Un contexte de récompense représentatif pour chaque type de déclencheur (task, milestone, challenge) est illustré dans les exemples ci-dessus.

Erreurs courantes

Erreur
Effet
Corriger
rewardContext.rewardValue utilisé comme nombre sans conversion
Erreur de correspondance de type si le fournisseur valide le champ en tant que numérique
Envelopper avec $number(rewardContext.rewardValue)
challenge.kvpCustom.someKey renvoie null.
Clé non définie au moment de la création
Assurez-vous que la clé est présente dans kvpCustom pour chaque défi qui utilise cette définition
task.accumulators.item_list[-1] est nul
Aucun article n’a été appliqué avant l’émission de la récompense (événement sans achat)
Protégez avec une condition ou utilisez plutôt timestamp depuis le contexte.
milestone accessible lorsque la source est "task" ou "challenge"
milestone est nul ; l’expression renvoie ou produit des champs nuls.
Vérifiez les rewardContext.source avant d’accéder aux milestone ou utilisez uniquement les milestone dans les définitions jointes aux récompenses jalonnées
L’expression renvoie un tableau au lieu d’un objet .
Le fournisseur reçoit une structure de payload inattendue
Encapsulez les expressions renvoyant un tableau dans un objet externe : { "items": [...] }
recommendation-more-help
journey-optimizer-help