Implementazione di un webhook nel servizio SaaS
Quando si crea un'offerta SaaS transazionabile nel Centro per i partner, il partner fornisce l'URL del webhook di connessione da usare come endpoint HTTP. Questo webhook viene chiamato da Microsoft usando la chiamata HTTP POST per notificare al lato editore gli eventi seguenti che si verificano sul lato Microsoft:
Evento webhook | 1. Quando ricevuto | 2. Se accettato | 3. Se rifiutato |
---|---|---|---|
ChangePlan |
Rispondere con HTTP 200 | PATCH con esito positivo (questo evento è facoltativo e autoaccepted in 10 secondi) | PATCH con errore O rispondere con 4xx (entro 10 secondi) |
ChangeQuantity |
Rispondere con HTTP 200 | PATCH con esito positivo (questo evento è facoltativo e autoaccepted in 10 secondi) | PATCH con errore O rispondere con 4xx (entro 10 secondi) |
Renew |
Rispondere con HTTP 200 | Non applicabile | Non applicabile |
Suspend |
Rispondere con HTTP 200 | Non applicabile | Non applicabile |
Unsubscribe |
Rispondere con HTTP 200 | Non applicabile | Non applicabile |
Reinstate |
Rispondere con HTTP 200 | Non applicabile | Non applicabile (chiamare l'API delete per attivare l'eliminazione se non è possibile accettare la reintegrazione) |
Il server di pubblicazione deve implementare un webhook nel servizio SaaS per mantenere lo stato della sottoscrizione SaaS coerente con il lato Microsoft. Il servizio SaaS è necessario per chiamare l'API Get Operation per convalidare e autorizzare i dati di chiamata e payload del webhook prima di intervenire in base alla notifica del webhook. Il server di pubblicazione deve restituire HTTP 200 a Microsoft non appena viene elaborata la chiamata webhook. Questo valore riconosce che la chiamata webhook è stata ricevuta correttamente dal server di pubblicazione.
Importante
Il servizio URL del webhook deve essere attivo e in esecuzione 24 x 7 e pronto a ricevere sempre nuove chiamate da Microsoft. Microsoft dispone di un criterio di ripetizione dei tentativi per la chiamata webhook (500 tentativi oltre otto ore), ma se l'editore non accetta la chiamata e restituisce una risposta, l'operazione che il webhook notifica alla fine avrà esito negativo sul lato Microsoft.
Importante
Gli ISV devono evitare una rigorosa deserializzazione dello schema webhook. Microsoft si riserva il diritto di espandere lo schema in futuro.
Importante
Gli ISV devono convalidare il token Microsoft Entra (token JWT) nell'endpoint webhook dall'intestazione della richiesta. Si tratta di un token di connessione standard e consentirà agli ISV di specificare chi è il chiamante. Altre informazioni su come convalidare il token in questo articolo. learn.microsoft.com/azure/active-directory/develop/access-tokens
Esempio di payload del webhook di 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
}
Esempio di payload del webhook dell'evento 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
}
Esempio di payload del webhook di un evento di reintegrazione della sottoscrizione:
// 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
}
Esempio di payload del webhook di un evento di rinnovo:
// 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,
}
Esempio di payload del webhook di un evento suspend:
{
"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,
}
Esempio di payload del webhook di un evento di annullamento della sottoscrizione:
Si tratta di un evento di sola notifica. Non è disponibile alcun invio a ACK per questo evento.
{
"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,
}
Protezione dei webhook
È necessario proteggere i webhook in modo che nessuno degli endpoint Microsoft eseseguono chiamate webhook di questo tipo. È possibile usare qualsiasi tecnologia per implementare i webhook, tuttavia l'implementazione del webhook deve seguire le linee guida di sicurezza seguenti (vedere Esercitazione).
Microsoft chiama i webhook con intestazioni di autorizzazione che contengono le informazioni necessarie per convalidare le chiamate. È necessario abilitare i webhook per poter ricevere le intestazioni di autorizzazione. Non aggiungere dettagli di autorizzazione o token di sicurezza come token di firma di accesso condiviso direttamente negli URL del webhook. Tali webhook potrebbero non riuscire a recuperare le intestazioni di autorizzazione inviate da Microsoft durante la chiamata dei webhook.
Il token di connessione JWT passato nell'intestazione authorization contiene i dati seguenti nel payload che è possibile usare per proteggere gli endpoint.
"aud": "this is the Microsoft Entra Identity application ID you add to your offer's technical configuration in Microsoft Partner Center"
"appid" o "azp": si tratta dell'ID risorsa usato quando si crea il token di autorizzazione dell'editore per chiamare le API di evasione SaaS. A seconda dell'installazione dell'applicazione, è possibile che questo valore dell'ID risorsa venga visualizzato in "appid" o "azp". Il token ha una delle due attestazioni ed è necessario reagire di conseguenza nel codice.
"tid": "this is the Microsoft Entra tenant ID you add to your offer's technical configuration in Microsoft Partner Center"
È possibile controllare i campi passati sopra per assicurarsi che la chiamata webhook sia valida.
Importante
Microsoft inizierà a richiedere agli ISV di creare i webhook in modo sicuro e di accettare le intestazioni di autorizzazione. Se l'implementazione del webhook corrente non può accettare intestazioni di autorizzazione, è necessario aggiornare i webhook e proteggere tali endpoint (usando le linee guida precedenti) per evitare interruzioni.
Sviluppo e test
Per avviare il processo di sviluppo, è consigliabile creare risposte fittizie all'API sul lato editore. Queste risposte possono essere basate su risposte di esempio fornite in questo articolo.
Quando l'editore è pronto per il test end-to-end:
- Pubblicare un'offerta SaaS in un gruppo di destinatari di anteprima limitato e mantenerla nella fase di anteprima.
- Impostare il prezzo del piano su zero per evitare di attivare spese di fatturazione effettive durante il test. Un'altra opzione consiste nell'impostare un prezzo diverso da zero e annullare tutti gli acquisti di test entro 24 ore.
- Assicurarsi che tutti i flussi vengano richiamati end-to-end per simulare uno scenario reale del cliente.
- Se il partner vuole testare il flusso di acquisto e fatturazione completo, eseguire questa operazione con un prezzo superiore a $0. L'acquisto viene fatturato e verrà generata una fattura.
Un flusso di acquisto può essere attivato dai siti portale di Azure o Microsoft AppSource, a seconda della posizione in cui viene pubblicata l'offerta.
Il piano di modifica, la quantità di modifiche e le azioni di annullamento della sottoscrizione vengono testate dal lato editore. Dal lato Microsoft, la sottoscrizione può essere attivata sia dal portale di Azure che dall'interfaccia di amministrazione (il portale in cui vengono gestiti gli acquisti di Microsoft AppSource). La quantità e il piano di modifica possono essere attivati solo dall'interfaccia di amministrazione.
Ottenere supporto
Per le opzioni di supporto per gli editori, vedere Supporto per il programma del marketplace commerciale nel Centro per i partner.
Contenuto correlato
- Per altre opzioni per le offerte SaaS nel marketplace commerciale, vedere le API del servizio di misurazione del marketplace commerciale.
- Esaminare e usare i client per linguaggi di programmazione e esempi diversi.
- Guardare le esercitazioni video seguenti: