Implementera en webhook på SaaS-tjänsten

När du skapar ett transakterbart SaaS-erbjudande i Partnercenter tillhandahåller partnern den webhook-URL för Anslut ion som ska användas som EN HTTP-slutpunkt. Den här webhooken anropas av Microsoft med hjälp av POST HTTP-anropet för att meddela utgivaren om följande händelser som inträffar på Microsoft-sidan:

Webhook-händelse 1. När den tas emot 2. Om det godkänns 3. Om avvisas
ChangePlan Svara med HTTP 200 PATCH med framgång (den här händelsen är valfri och accepteras automatiskt om 10 sekunder) PATCH med fel ELLER svara med 4xx (inom 10 sekunder)
ChangeQuantity Svara med HTTP 200 PATCH med framgång (den här händelsen är valfri och accepteras automatiskt om 10 sekunder) PATCH med fel ELLER svara med 4xx (inom 10 sekunder)
Renew Svara med HTTP 200 Ej tillämpligt Ej tillämpligt
Suspend Svara med HTTP 200 Ej tillämpligt Ej tillämpligt
Unsubscribe Svara med HTTP 200 Ej tillämpligt Ej tillämpligt
Reinstate Svara med HTTP 200 Inte tillämpligt Inte tillämpligt (anropa borttagnings-API för att utlösa borttagning om det inte går att acceptera återinträde)

Utgivaren måste implementera en webhook i SaaS-tjänsten för att saaS-prenumerationsstatusen ska vara konsekvent med Microsoft-sidan. SaaS-tjänsten krävs för att anropa API:et Hämta åtgärd för att verifiera och auktorisera webhook-anropet och nyttolastdata innan du vidtar åtgärder baserat på webhooksmeddelandet. Utgivaren bör returnera HTTP 200 till Microsoft så snart webhookens anrop bearbetas. Det här värdet bekräftar att webhook-anropet har tagits emot av utgivaren.

Viktigt!

Webhook-URL-tjänsten måste vara igång 24 x 7 och vara redo att ta emot nya samtal från Microsoft hela tiden. Microsoft har en återförsöksprincip för webhook-anropet (500 återförsök under åtta timmar), men om utgivaren inte accepterar anropet och returnerar ett svar kommer åtgärden som webhooken meddelar om till slut att misslyckas på Microsoft-sidan.

Viktigt!

ISV:er bör undvika strikt deserialisering av Webhook-schemat. Microsoft förbehåller sig rätten att utöka schemat i framtiden.

Viktigt!

ISV:er måste verifiera Microsoft Entra-token (JWT-token) på deras webhook-slutpunkt från begärandehuvudet. Detta är en standard ägartoken och ger ISV-information om vem anroparen är. Läs mer om hur du verifierar token i den här artikeln. learn.microsoft.com/azure/active-directory/develop/access-tokens

Webhook-nyttolastexempel på 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
}

Webhook-nyttolastexempel på ChangeQuantity-händelse:


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

Webhook-nyttolastexempel på en händelse för att återställa prenumerationen:

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

Webhook-nyttolastexempel på en förnyelsehändelse:

// 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,
}

Webhook-nyttolastexempel på en paushändelse:


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

Webhook-nyttolastexempel på en avprenumerationshändelse:

Det här är en händelse som endast meddelas. Det går inte att skicka till ACK för den här händelsen.


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

Skydda dina Webhooks

Du måste skydda dina Webhooks så att ingen annan än Microsoft-slutpunkter gör sådana Webhook-anrop. Du kan använda valfri teknik för att implementera dina Webhooks, men webhooks-implementeringen måste följa följande säkerhetsriktlinjer.

  • Microsoft anropar dina Webhooks med auktoriseringshuvuden som innehåller nödvändig information för att verifiera anropen. Du måste aktivera webhooks för att kunna ta emot auktoriseringsrubrikerna. (Lägg inte till auktoriseringsinformation eller säkerhetstoken som SAS-token direkt i Webhook-URL:erna. Sådana Webhooks kan misslyckas med att hämta de auktoriseringshuvuden som Microsoft skickar när du anropar dina Webhooks).

  • JWT Bearer-token som skickades i auktoriseringshuvudet innehåller följande data i nyttolasten som du kan använda för att skydda dina slutpunkter.

  • "aud": "det här är Microsoft Entra Identity-program-ID:t som du lägger till i erbjudandets tekniska konfiguration i Microsoft Partner Center"

  • "appid" eller "azp": Det här är det resurs-ID som du använder när du skapar auktoriseringstoken för utgivare för att anropa Api:er för SaaS-uppfyllande. Beroende på programkonfigurationen kan du se det här resurs-ID-värdet i antingen "appid" eller "azp". Token har något av de två anspråken och du måste reagera i enlighet med koden.

  • "tid": "det här är det Microsoft Entra-klient-ID som du lägger till i erbjudandets tekniska konfiguration i Microsoft Partner Center"

  • Du kan kontrollera mot ovanstående skickade fält för att se till att Webhook-anropet är giltigt.

Viktigt!

Microsoft börjar kräva att ISV:er skapar sina Webhooks på ett säkert sätt och accepterar auktoriseringshuvuden. Om din aktuella Webhook-implementering inte kan acceptera auktoriseringshuvuden måste du uppdatera dina Webhooks och skydda sådana slutpunkter (med hjälp av riktlinjerna ovan) för att undvika avbrott.

Utveckling och testning

För att starta utvecklingsprocessen rekommenderar vi att du skapar dummy-API-svar på utgivarsidan. Dessa svar kan baseras på exempelsvar som tillhandahålls i den här artikeln.

När utgivaren är redo för testning från slutpunkt till slutpunkt:

  • Publicera ett SaaS-erbjudande till en begränsad förhandsversionspublik och håll det i förhandsversionsfasen.
  • Ställ in planpriset på noll för att undvika att utlösa faktiska faktureringskostnader vid testning. Ett annat alternativ är att ange ett icke-nollpris och avbryta alla testköp inom 24 timmar.
  • Se till att alla flöden anropas från slutpunkt till slutpunkt för att simulera ett verkligt kundscenario.
  • Om partnern vill testa ett fullständigt inköps- och faktureringsflöde gör du det med ett erbjudande som är prissatt över 0 USD. Köpet faktureras och en faktura genereras.

Ett inköpsflöde kan utlösas från Azure-portalen eller Microsoft AppSource-webbplatser, beroende på var erbjudandet publiceras.

Åtgärder för ändringsplan, ändringskvantitet och avprenumerering testas från utgivarens sida. Från Microsoft-sidan kan avprenumerering utlösas från både Azure-portalen och Administrationscenter (portalen där Microsoft AppSource-köp hanteras). Ändringskvantitet och plan kan endast utlösas från administrationscentret.

Få support

Se Support för det kommersiella marketplace-programmet i Partnercenter för supportalternativ för utgivare.

Nästa steg