Implementowanie elementu webhook w usłudze SaaS

Podczas tworzenia transakcyjnej oferty SaaS w Centrum partnerskim partner udostępnia adres URL elementu webhook Połączenie ion, który ma być używany jako punkt końcowy HTTP. Ten element webhook jest wywoływany przez firmę Microsoft przy użyciu wywołania HTTP POST, aby powiadomić wydawcę o następujących zdarzeniach występujących po stronie firmy Microsoft:

Zdarzenie elementu webhook 1. Po odebraniu 2. Jeśli zaakceptowano 3. W przypadku odrzucenia
ChangePlan Odpowiadanie za pomocą protokołu HTTP 200 PATCH z powodzeniem (to zdarzenie jest opcjonalne i automatycznie inicjowane w ciągu 10 sekund) PATCH z błędem LUB odpowiada z 4xx (w ciągu 10 sekund)
ChangeQuantity Odpowiadanie za pomocą protokołu HTTP 200 PATCH z powodzeniem (to zdarzenie jest opcjonalne i automatycznie inicjowane w ciągu 10 sekund) PATCH z błędem LUB odpowiada z 4xx (w ciągu 10 sekund)
Renew Odpowiadanie za pomocą protokołu HTTP 200 Nie dotyczy Nie dotyczy
Suspend Odpowiadanie za pomocą protokołu HTTP 200 Nie dotyczy Nie dotyczy
Unsubscribe Odpowiadanie za pomocą protokołu HTTP 200 Nie dotyczy Nie dotyczy
Reinstate Odpowiadanie za pomocą protokołu HTTP 200 Nie dotyczy Nie dotyczy (wywołanie interfejsu API usuwania w celu wyzwolenia usunięcia, jeśli nie można zaakceptować)

Wydawca musi zaimplementować element webhook w usłudze SaaS, aby zapewnić spójność stanu subskrypcji SaaS ze stroną firmy Microsoft. Usługa SaaS jest wymagana do wywołania interfejsu API get operation w celu zweryfikowania i autoryzowania wywołania i ładunku elementu webhook przed podjęciem akcji na podstawie powiadomienia elementu webhook. Wydawca powinien zwrócić http 200 do firmy Microsoft zaraz po przetworzeniu wywołania elementu webhook. Ta wartość potwierdza, że wywołanie elementu webhook zostało pomyślnie odebrane przez wydawcę.

Ważne

Usługa adresu URL elementu webhook musi być uruchomiona 24 x 7 i gotowa do odbierania nowych połączeń od firmy Microsoft przez cały czas. Firma Microsoft ma zasady ponawiania próby dla wywołania elementu webhook (500 ponownych prób w ciągu ośmiu godzin), ale jeśli wydawca nie akceptuje wywołania i zwraca odpowiedź, operacja, o którą powiadamia element webhook, ostatecznie zakończy się niepowodzeniem po stronie firmy Microsoft.

Ważne

Niezależne dostawcy oprogramowania powinni unikać ścisłej deserializacji schematu elementu webhook. Firma Microsoft zastrzega sobie prawo do rozszerzenia schematu w przyszłości.

Ważne

Dostawcy oprogramowania muszą zweryfikować token entra firmy Microsoft (token JWT) w punkcie końcowym elementu webhook z nagłówka żądania. Jest to standardowy token elementu nośnego i będzie zawierać szczegółowe informacje o tym, kim jest obiekt wywołujący. Dowiedz się więcej na temat weryfikowania tokenu w tym artykule. learn.microsoft.com/azure/active-directory/develop/access-tokens

Przykład ładunku elementu webhook w programie 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
}

Przykład ładunku elementu webhook zdarzenia 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
}

Przykład ładunku elementu webhook zdarzenia przywrócenia subskrypcji:

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

Przykład ładunku elementu webhook zdarzenia odnawiania:

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

Przykład ładunku elementu webhook zdarzenia wstrzymania:


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

Przykład ładunku elementu webhook zdarzenia anulowania subskrypcji:

Jest to zdarzenie tylko do powiadamiania. Dla tego zdarzenia nie ma wysyłania do usługi ACK.


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

Zabezpieczanie elementów webhook

Należy zabezpieczyć elementy webhook, aby nikt inny niż punkty końcowe firmy Microsoft nie robił takich wywołań elementu webhook. Aby zaimplementować elementy webhook, możesz użyć dowolnej technologii, jednak implementacja elementu webhook musi być zgodna z poniższymi wytycznymi dotyczącymi zabezpieczeń.

  • Firma Microsoft wywołuje elementy webhook z nagłówkami autoryzacji zawierającymi niezbędne informacje w celu zweryfikowania wywołań. Aby móc odbierać nagłówki autoryzacji, należy włączyć elementy webhook. (Nie należy dodawać szczegółów autoryzacji ani tokenów zabezpieczających, takich jak tokeny SAS bezpośrednio w adresach URL elementu webhook. Takie elementy webhook mogą nie pobrać nagłówków autoryzacji wysyłanych przez firmę Microsoft podczas wywoływania elementów webhook).

  • Token elementu nośnego JWT przekazany w nagłówku autoryzacji zawiera następujące dane w ładunku, którego można użyć do zabezpieczenia punktów końcowych.

  • "aud": "to jest identyfikator aplikacji Microsoft Entra Identity dodawalny do konfiguracji technicznej oferty w Centrum partnerskim firmy Microsoft"

  • "appid" lub "azp": jest to identyfikator zasobu używany podczas tworzenia tokenu autoryzacji wydawcy do wywoływania interfejsów API realizacji SaaS. W zależności od konfiguracji aplikacji może być widoczna ta wartość identyfikatora zasobu w ciągu "appid" lub "azp". Token zawiera jeden z dwóch oświadczeń i należy odpowiednio zareagować w kodzie.

  • "tid": "jest to identyfikator dzierżawy firmy Microsoft Entra dodany do konfiguracji technicznej oferty w Centrum partnerskim firmy Microsoft"

  • Możesz sprawdzić powyższe przekazane pola, aby upewnić się, że wywołanie elementu webhook jest prawidłowe.

Ważne

Firma Microsoft zacznie wymagać od niezależnych dostawców oprogramowania tworzenia elementów webhook w bezpieczny sposób i akceptowania nagłówków autoryzacji. Jeśli bieżąca implementacja elementu webhook nie może zaakceptować nagłówków autoryzacji, należy zaktualizować elementy webhook i zabezpieczyć takie punkty końcowe (przy użyciu powyższych wytycznych), aby uniknąć zakłóceń.

Tworzenie i testowanie

Aby rozpocząć proces programowania, zalecamy utworzenie fikcyjnych odpowiedzi interfejsu API po stronie wydawcy. Odpowiedzi te mogą być oparte na przykładowych odpowiedziach podanych w tym artykule.

Gdy wydawca jest gotowy do zakończenia testowania:

  • Opublikuj ofertę SaaS dla ograniczonej grupy odbiorców wersji zapoznawczej i zachowaj ją na etapie wersji zapoznawczej.
  • Ustaw cenę planu na zero, aby uniknąć wyzwalania rzeczywistych wydatków rozliczeniowych podczas testowania. Inną opcją jest ustawienie ceny niezerowej i anulowanie wszystkich zakupów testowych w ciągu 24 godzin.
  • Upewnij się, że wszystkie przepływy są wywoływane na końcu, aby symulować rzeczywisty scenariusz klienta.
  • Jeśli partner chce przetestować pełny przepływ zakupów i rozliczeń, zrób to za pomocą oferty, która jest wyceniana powyżej 0 USD. Zakup jest rozliczany, a faktura zostanie wygenerowana.

Przepływ zakupu można wyzwolić z witryny Azure Portal lub witryny microsoft AppSource, w zależności od tego, gdzie oferta jest publikowana.

Akcje zmiany planu, zmiany ilości i anulowania subskrypcji są testowane po stronie wydawcy. Po stronie firmy Microsoft można wyzwolić anulowanie subskrypcji zarówno z witryny Azure Portal, jak i centrum Administracja (portal, w którym są zarządzane zakupy w usłudze Microsoft AppSource). Zmiana ilości i planu może być wyzwalana tylko z centrum Administracja.

Uzyskiwanie pomocy technicznej

Aby uzyskać informacje o opcjach pomocy technicznej wydawcy, zobacz Pomoc techniczna dla programu marketplace komercyjnego w Centrum partnerskim.

Następne kroki