Implémentation d’un webhook sur le service SaaS
Lors de la création d’une offre SaaS transactionnelle dans l’Espace partenaires, le partenaire fournit le webhook connexion URL à utiliser comme point de terminaison HTTP. Ce webhook est appelé par Microsoft à l’aide de l’appel HTTP POST pour notifier le côté éditeur des événements suivants qui se produisent côté Microsoft :
Événement webhook | 1. Lorsqu’il est reçu | 2. S’il est accepté | 3. S’il est rejeté |
---|---|---|---|
ChangePlan |
Répondre avec HTTP 200 | PATCH avec succès (cet événement est facultatif et autoaccepté en 10 secondes) | PATCH avec échec OU répondre avec 4xx (dans les 10 secondes) |
ChangeQuantity |
Répondre avec HTTP 200 | PATCH avec succès (cet événement est facultatif et autoaccepté en 10 secondes) | PATCH avec échec OU répondre avec 4xx (dans les 10 secondes) |
Renew |
Répondre avec HTTP 200 | Sans objet | Sans objet |
Suspend |
Répondre avec HTTP 200 | Sans objet | Sans objet |
Unsubscribe |
Répondre avec HTTP 200 | Sans objet | Sans objet |
Reinstate |
Répondre avec HTTP 200 | Sans objet | Non applicable (l’API de suppression d’appel pour déclencher la suppression si la restauration ne peut pas être acceptée) |
L’éditeur doit implémenter un webhook dans le service SaaS pour maintenir l’état de l’abonnement SaaS cohérent avec le côté Microsoft. Le service SaaS est requis pour appeler l’API Get Operation pour valider et autoriser les données d’appel de webhook et de charge utile avant de prendre des mesures en fonction de la notification webhook. L’éditeur doit retourner HTTP 200 à Microsoft dès que l’appel de webhook est traité. Cette valeur reconnaît que l’appel de webhook a été reçu avec succès par l’éditeur.
Important
Le service d’URL du webhook doit être opérationnel 24 x 7 et prêt à recevoir de nouveaux appels de Microsoft à tout moment. Microsoft a une stratégie de nouvelle tentative pour l’appel de webhook (500 nouvelles tentatives sur huit heures), mais si l’éditeur n’accepte pas l’appel et retourne une réponse, l’opération sur laquelle le webhook avertit échouera finalement côté Microsoft.
Important
Les éditeurs de logiciels indépendants doivent éviter une désérialisation stricte du schéma webhook. Microsoft se réserve le droit d’étendre le schéma à l’avenir.
Important
Les éditeurs de logiciels indépendants doivent valider le jeton Microsoft Entra (jeton JWT) sur leur point de terminaison webhook à partir de l’en-tête de requête. Il s’agit d’un jeton de porteur standard et donne des détails sur la personne de l’appelant. Découvrez comment valider le jeton dans cet article. learn.microsoft.com/azure/active-directory/develop/access-tokens
exemple de charge utile webhook de ChangePlan :
{
"id": "<guid>",
"activityId": "<guid>",
"publisherId": "XXX",
"offerId": "YYY",
"planId": "plan2",
"quantity": 10,
"subscriptionId": "<guid>",
"timeStamp": "2023-02-10T18:48:58.4449937Z",
"action": "ChangePlan",
"status": "InProgress",
"operationRequestSource": "Azure",
"subscription":
{
"id": "<guid>",
"name": "Test",
"publisherId": "XXX",
"offerId": "YYY",
"planId": "plan1",
"quantity": 10,
"beneficiary":
{
"emailId": XX@outlook.com,
"objectId": "<guid>",
"tenantId": "<guid>",
"puid": "1234567890",
},
"purchaser":
{
"emailId": XX@outlook.com,
"objectId": "<guid>",
"tenantId": "<guid>",
"puid": "1234567890",
},
"allowedCustomerOperations": ["Delete", "Update", "Read"],
"sessionMode": "None",
"isFreeTrial": false,
"isTest": false,
"sandboxType": "None",
"saasSubscriptionStatus": "Subscribed",
"term":
{
"startDate": "2022-02-10T00:00:00Z",
"endDate": "2022-03-12T00:00:00Z",
"termUnit": "P1M",
"chargeDuration": null,
},
"autoRenew": true,
"created": "2022-01-10T23:15:03.365988Z",
"lastModified": "2022-02-14T20:26:04.5632549Z",
},
"purchaseToken": null
}
exemple de charge utile webhook de l’événement ChangeQuantity :
{
"id": "<guid>",
"activityId": "<guid>",
"publisherId": "XXX",
"offerId": "YYY",
"planId": "plan1",
"quantity": 20,
"subscriptionId": "<guid>",
"timeStamp": "2023-02-10T18:54:00.6158973Z",
"action": "ChangeQuantity",
"status": "InProgress",
"operationRequestSource": "Azure",
"subscription": {
"id": "<guid>",
"name": "Test",
"publisherId": "XXX",
"offerId": "YYY",
"planId": "plan1",
"quantity": 10,
"beneficiary":
{
"emailId": XX@outlook.com,
"objectId": "<guid>",
"tenantId": "<guid>",
"puid": "1234567890",
},
"purchaser":
{
"emailId": XX@outlook.com,
"objectId": "<guid>",
"tenantId": "<guid>",
"puid": "1234567890",
},
"allowedCustomerOperations": ["Delete", "Update", "Read"],
"sessionMode": "None",
"isFreeTrial": false,
"isTest": false,
"sandboxType": "None",
"saasSubscriptionStatus": "Subscribed",
"term":
{
"startDate": "2022-02-10T00:00:00Z",
"endDate": "2022-03-12T00:00:00Z",
"termUnit": "P1M",
"chargeDuration": null,
},
"autoRenew": true,
"created": "2022-01-10T23:15:03.365988Z",
"lastModified": "2022-02-14T20:26:04.5632549Z",
},
"purchaseToken": null
}
exemple de charge utile webhook d’un événement de rétablissement d’abonnement :
// end user's payment instrument became valid again, after being suspended, and the SaaS subscription is being reinstated
{
"id": "<guid>",
"activityId": "<guid>",
"publisherId": "XXX",
"offerId": "YYY",
"planId": "plan1",
"quantity": 100,
"subscriptionId": "<guid>",
"timeStamp": "2023-02-11T11:38:10.3508619Z",
"action": "Reinstate",
"status": "InProgress",
"operationRequestSource": "Azure",
"subscription":
{
"id": "<guid>",
"name": "Test",
"publisherId": "XXX",
"offerId": "YYY",
"planId": "plan1",
"quantity": 100,
"beneficiary":
{
"emailId": XX@outlook.com,
"objectId": "<guid>",
"tenantId": "<guid>",
"puid": "1234567890",
},
"purchaser":
{
"emailId": XX@outlook.com,
"objectId": "<guid>",
"tenantId": "<guid>",
"puid": "1234567890",
},
"allowedCustomerOperations": ["Delete", "Update", "Read"],
"sessionMode": "None",
"isFreeTrial": false,
"isTest": false,
"sandboxType": "None",
"saasSubscriptionStatus": "Suspended",
"term":
{
"startDate": "2022-02-10T00:00:00Z",
"endDate": "2022-03-12T00:00:00Z",
"termUnit": "P1M",
"chargeDuration": null,
},
"autoRenew": true,
"created": "2022-01-10T23:15:03.365988Z",
"lastModified": "2022-02-14T20:26:04.5632549Z",
},
"purchaseToken": null
}
exemple de charge utile webhook d’un événement de renouvellement :
// end user's subscription renewal
{
"id": "<guid>",
"activityId": "<guid>",
"publisherId": "XXX",
"offerId": "YYY",
"planId": "plan1",
"quantity": 100,
"subscriptionId": "<guid>",
"timeStamp": "2023-02-10T08:49:01.8613208Z",
"action": "Renew",
"status": "Succeeded",
"operationRequestSource": "Azure",
"subscription":
{
"id": "<guid>",
"name": "Test",
"publisherId": "XXX",
"offerId": "YYY",
"planId": "plan1",
"quantity": 100,
"beneficiary":
{
"emailId": XX@outlook.com,
"objectId": "<guid>",
"tenantId": "<guid>",
"puid": "1234567890",
},
"purchaser":
{
"emailId": XX@outlook.com,
"objectId": "<guid>",
"tenantId": "<guid>",
"puid": "1234567890",
},
"allowedCustomerOperations": ["Delete", "Update", "Read"],
"sessionMode": "None",
"isFreeTrial": false,
"isTest": false,
"sandboxType": "None",
"saasSubscriptionStatus": "Subscribed",
"term":
{
"startDate": "2022-02-10T00:00:00Z",
"endDate": "2022-03-12T00:00:00Z",
"termUnit": "P1M",
"chargeDuration": null,
},
"autoRenew": true,
"created": "2022-01-10T23:15:03.365988Z",
"lastModified": "2022-02-14T20:26:04.5632549Z",
},
"purchaseToken": null,
}
exemple de charge utile webhook d’un événement de suspension :
{
"id": "<guid>",
"activityId": "<guid>",
"publisherId": "XXX",
"offerId": "YYY",
"planId": "plan1",
"quantity": 100,
"subscriptionId": "<guid>",
"timeStamp": "2023-02-10T08:49:01.8613208Z",
"action": "Suspend",
"status": "Succeeded",
"operationRequestSource": "Azure",
"subscription":
{
"id": "<guid>",
"name": "Test",
"publisherId": "XXX",
"offerId": "YYY",
"planId": "plan1",
"quantity": 100,
"beneficiary":
{
"emailId": XX@outlook.com,
"objectId": "<guid>",
"tenantId": "<guid>",
"puid": "1234567890",
},
"purchaser":
{
"emailId": XX@outlook.com,
"objectId": "<guid>",
"tenantId": "<guid>",
"puid": "1234567890",
},
"allowedCustomerOperations": ["Delete", "Update", "Read"],
"sessionMode": "None",
"isFreeTrial": false,
"isTest": false,
"sandboxType": "None",
"saasSubscriptionStatus": "Suspended",
"term":
{
"startDate": "2022-02-10T00:00:00Z",
"endDate": "2022-03-12T00:00:00Z",
"termUnit": "P1M",
"chargeDuration": null,
},
"autoRenew": true,
"created": "2022-01-10T23:15:03.365988Z",
"lastModified": "2022-02-14T20:26:04.5632549Z",
},
"purchaseToken": null,
}
exemple de charge utile webhook d’un événement de désabonnement :
Il s’agit d’un événement de notification uniquement. Il n’y a pas d’envoi à ACK pour cet événement.
{
"id": "<guid>",
"activityId": "<guid>",
"publisherId": "XXX",
"offerId": "YYY",
"planId": "plan1",
"quantity": 100,
"subscriptionId": "<guid>",
"timeStamp": "2023-02-10T08:49:01.8613208Z",
"action": "Unsubscribe",
"status": "Succeeded",
"operationRequestSource": "Azure",
"subscription":
{
"id": "<guid>",
"name": "Test",
"publisherId": "XXX",
"offerId": "YYY",
"planId": "plan1",
"quantity": 100,
"beneficiary":
{
"emailId": XX@outlook.com,
"objectId": "<guid>",
"tenantId": "<guid>",
"puid": "1234567890",
},
"purchaser":
{
"emailId": XX@outlook.com,
"objectId": "<guid>",
"tenantId": "<guid>",
"puid": "1234567890",
},
"allowedCustomerOperations": ["Delete", "Update", "Read"],
"sessionMode": "None",
"isFreeTrial": false,
"isTest": false,
"sandboxType": "None",
"saasSubscriptionStatus": "Unsubscribed",
"term":
{
"startDate": "2022-02-10T00:00:00Z",
"endDate": "2022-03-12T00:00:00Z",
"termUnit": "P1M",
"chargeDuration": null,
},
"autoRenew": true,
"created": "2022-01-10T23:15:03.365988Z",
"lastModified": "2022-02-14T20:26:04.5632549Z",
},
"purchaseToken": null,
}
Sécurisation de vos webhooks
Vous devez sécuriser vos Webhooks afin que personne d’autre que les points de terminaison Microsoft n’effectue de tels appels webhook. Vous pouvez utiliser n’importe quelle technologie pour implémenter vos Webhooks, mais votre implémentation de Webhook doit suivre les instructions de sécurité suivantes (Consultez le didacticiel).
Microsoft appelle vos Webhooks avec des en-têtes d’autorisation qui contiennent les informations nécessaires pour valider les appels. Vous devez autoriser vos Webhooks à recevoir les en-têtes d’autorisation. (n’ajoutez pas de détails d’autorisation ou de jetons de sécurité tels que des jetons SAP directement dans les URL webhook. Ces Webhooks peuvent ne pas récupérer les en-têtes d’autorisation que Microsoft envoie lors de l’appel de vos Webhooks).
Le jeton du porteur JWT transmis dans l’en-tête d’autorisation contient les données suivantes dans la charge utile que vous pouvez utiliser pour sécuriser vos points de terminaison.
« aud » : « il s’agit de l’ID d’application Microsoft Entra Identity que vous ajoutez à la configuration technique de votre offre dans l’Espace partenaires Microsoft »
« appid » ou « azp » : il s’agit de l’ID de ressource que vous utilisez lorsque vous créez un jeton d’autorisation d’éditeur pour appeler les API de traitement SaaS. En fonction de la configuration de l’application, vous pouvez voir cette valeur d’ID de ressource dans « appid » ou « azp ». Le jeton a l’une des deux revendications et vous devez réagir en conséquence dans votre code.
« tid » : « il s’agit de l’ID de locataire Microsoft Entra que vous ajoutez à la configuration technique de votre offre dans l’Espace partenaires Microsoft »
Vous pouvez vérifier par rapport aux champs passés ci-dessus pour vous assurer que l’appel webhook est valide.
Important
Microsoft commence à exiger que les éditeurs de logiciels indépendants créent leurs webhooks de manière sécurisée et acceptent les en-têtes d’autorisation. Si votre implémentation de Webhook actuelle ne peut pas accepter d’en-têtes d’autorisation, vous devez mettre à jour vos Webhooks et sécuriser ces points de terminaison (à l’aide des instructions ci-dessus) pour éviter toute interruption.
Développement et test
Pour démarrer le processus de développement, nous vous recommandons de créer des réponses d’API factices côté éditeur. Ces réponses peuvent être basées sur des exemples de réponses fournis dans cet article.
Lorsque l’éditeur est prêt pour le test de bout en bout :
- Publiez une offre SaaS sur un public en préversion limitée et conservez-la en préversion.
- Définissez le prix du plan sur zéro pour éviter de déclencher les dépenses de facturation réelles lors du test. Une autre option consiste à définir un prix différent de zéro et à annuler tous les achats de test dans les 24 heures.
- Vérifiez que tous les flux sont appelés de bout en bout pour simuler un scénario client réel.
- Si le partenaire souhaite tester le flux complet d’achat et de facturation, faites-le avec une offre qui est facturée au-dessus de 0 $. L’achat est facturé et une facture sera générée.
Un flux d’achat peut être déclenché à partir du portail Azure ou des sites Microsoft AppSource, en fonction de l’emplacement de publication de l’offre.
de plan de modification, modifier la quantitéet annuler actions sont testées du côté de l’éditeur. Du côté microsoft, se désabonner peut être déclenché à partir du portail Azure et du Centre d’administration (le portail sur lequel les achats Microsoft AppSource sont gérés). Modifier la quantité et le plan ne peuvent être déclenchés qu’à partir du Centre d’administration.
Obtenir du support
Consultez prise en charge du programme de la Place de marché commerciale dans l’Espace partenaires pour les options de support de l’éditeur.
Contenu connexe
- Consultez les API de service de contrôle de la place de marché commerciale pour plus d’options pour les offres SaaS sur la place de marché commerciale.
- Passez en revue et utilisez les clients pour différents langages de programmation et exemples.
- Regardez les didacticiels vidéo suivants: