Freigeben über


Microsoft Store-Übermittlungs-API für MSI- oder EXE-App

Verwenden Sie die Microsoft Store-Übermittlungs-API für MSI- oder EXE-App zum programmgesteuerten Abfragen und Erstellen von Übermittlungen für MSI- oder EXE-Apps für das Partner Center-Konto Ihrer Organisation. Diese API ist nützlich, wenn Ihr Konto viele Apps verwaltet und Sie den Übermittlungsvorgang für diese Objekte automatisieren und optimieren möchten. Diese API verwendet Azure Active Directory (Azure AD) zum Autorisieren der Aufrufe von Ihrer App oder Ihrem Dienst.

Die folgenden Schritte beschreiben den End-to-End-Prozess der Verwendung der Microsoft Store-Übermittlungs-API:

  1. Stellen Sie sicher, dass alle Voraussetzungen erfüllt sind.
  2. Rufen Sie vor dem Aufrufen einer Methode in der Microsoft Store-Übermittlungs-API ein Azure AD-Zugriffstoken ab. Nach dem Abruf eines Tokens können Sie es für einen Zeitraum von 60 Minuten in Aufrufen der Microsoft Store-Übermittlungs-API verwenden, bevor es abläuft. Nach Ablauf des Tokens können Sie ein neues Token generieren.
  3. Rufen Sie die Microsoft Store-Übermittlungs-API für MSI- oder EXE-App auf.

Schritt 1: Erfüllen der Voraussetzungen für die Verwendung der Microsoft Store-Übermittlungs-API

Stellen Sie sicher, dass die folgenden Voraussetzungen erfüllt sind, bevor Sie mit dem Schreiben von Code zum Aufrufen der Microsoft Store-Übermittlungs-API für MSI- oder EXE-App beginnen.

  • Sie (oder Ihre Organisation) müssen über ein Azure AD-Verzeichnis verfügen, und Ihnen müssen die Berechtigungen globaler Administrator für das Verzeichnis gewährt worden sein. Wenn Sie Microsoft 365 oder andere Unternehmensdienste von Microsoft verwenden, verfügen Sie bereits über ein Azure AD-Verzeichnis. Andernfalls können Sie ohne zusätzliche Kosten eine neue Azure AD-Instanz in Partner Center erstellen.
  • Sie müssen Ihrem Partner Center-Konto eine Azure AD-Anwendung zuordnen und Ihre Mandanten-ID, die Client-ID und den Schlüssel abrufen. Sie benötigen diese Werte, um ein Azure AD-Zugriffstoken zu erhalten, das Sie in Aufrufen der Microsoft Store-Übermittlungs-API verwenden.
  • Bereiten Sie Ihre App mit der Microsoft Store-Übermittlungs-API auf den Einsatz vor:
    • Wenn Ihre App noch nicht im Partner Center vorhanden ist, müssen Sie im Partner Center Ihre App durch Reservieren eines Namens erstellen. Sie können die Microsoft Store-Übermittlungs-API nicht zum Erstellen einer App im Partner Center verwenden. Sie müssen für die Erstellung im Partner Center arbeiten und können danach über die API auf die App zugreifen und programmgesteuert Übermittlungen dafür erstellen.
    • Bevor Sie eine Übermittlung für eine bestimmte App mit dieser API erstellen können, müssen Sie zuerst eine Übermittlung für die App im Partner Center erstellen, einschließlich der Beantwortung des Fragebogens für Altersfreigaben . Anschließend können Sie über die API programmgesteuert neue Übermittlungen für diese App erstellen.
    • Wenn Sie eine App-Übermittlung erstellen oder aktualisieren und ein neues Paket aufnehmen müssen, müssen Sie die Paketdetails vorbereiten.
    • Wenn Sie eine App-Übermittlung erstellen oder aktualisieren und Screenshots oder Bilder für den Store-Eintrag aufnehmen müssen, müssen Sie die Screenshots und Bilder für die App vorbereiten.

Zuordnen einer Azure AD-Anwendung zu Ihrem Partner Center-Konto

Bevor Sie die Microsoft Store-Übermittlungs-API für MSI- oder EXE-App verwenden können, müssen Sie Ihrem Partner Center-Konto eine Azure AD-Anwendung zuordnen, die Mandanten-ID und die Client-ID für die Anwendung abrufen und einen Schlüssel generieren. Die Azure AD-Anwendung stellt die App oder den Dienst dar, von der bzw. dem aus Sie die Microsoft Store-Übermittlungs-API aufrufen möchten. Sie benötigen die Mandanten-ID, die Client-ID und den Schlüssel, um ein Azure AD-Zugriffstoken zu erhalten, das Sie an die API übergeben.

Hinweis

Sie müssen diese Aufgabe nur einmal ausführen. Nachdem Sie über die Mandanten-ID, die Client-ID und den Schlüssel verfügen, können Sie diese jederzeit wiederverwenden, wenn Sie ein neues Azure AD-Zugriffstoken erstellen müssen.

  1. Verknüpfen Sie in Partner Center das Partner Center-Konto Ihrer Organisation mit dem Azure AD-Verzeichnis Ihrer Organisation.
  2. Als Nächstes müssen Sie auf der Seite „Benutzer“ im Abschnitt „Kontoeinstellungen“ von Partner Center die Azure AD-Anwendung hinzufügen, die die App oder den Dienst darstellt, mit der bzw. dem Sie auf die Übermittlungen Ihres Partner Center-Kontos zugreifen. Stellen Sie sicher, dass Sie dieser Anwendung die Rolle Manager zuweisen. Wenn die Anwendung noch nicht in Ihrem Azure AD-Verzeichnis vorhanden ist, können Sie in Partner Center eine neue Azure AD-Anwendung erstellen.
  3. Kehren Sie zur Seite Benutzer zurück, klicken Sie auf den Namen Ihrer Azure AD-Anwendung, um die Anwendungseinstellungen zu öffnen, und schreiben Sie die Werte Mandanten-ID und Client-ID auf.
  4. Informationen zum Hinzufügen eines neuen Schlüssels oder geheimen Clientschlüssels finden Sie in den folgenden Anweisungen oder in den Anweisungen zum Registrieren der App über das Azure-Portal:

So registrieren Sie Ihre App:

  1. Melden Sie sich beim Azure-Portal an.

  2. Wenn Sie Zugriff auf mehrere Mandanten haben, verwenden Sie im Menü am oberen Rand den Filter Verzeichnis + Abonnement , um den Mandanten auszuwählen, in dem Sie die Anwendung registrieren möchten.

  3. Suchen Sie nach Azure Active Directory, und wählen Sie diese Option aus.

  4. Wählen Sie unter „Verwalten“ die „App-Registrierungen“ aus > wählen Sie Ihre Anwendung aus.

  5. Wählen Sie „Zertifikate und Geheimnisse“ > „Geheime Clientschlüssel“ > „Neuer geheimer Clientschlüssel“ aus.

  6. Fügen Sie eine Beschreibung für Ihren geheimen Clientschlüssel hinzu.

  7. Wählen Sie für das Geheimnis eine Ablauffrist aus, oder geben Sie eine benutzerdefinierte Lebensdauer an.

  8. Die Lebensdauer eines geheimen Clientschlüssels ist auf maximal zwei Jahre (24 Monate) begrenzt. Das bedeutet, dass keine benutzerdefinierte Lebensdauer angegeben werden kann, die über die 24 Monate hinausgeht.

    Hinweis

    Microsoft empfiehlt, den Wert für die Ablauffrist auf maximal 12 Monate festzulegen.

  9. Wählen Sie Hinzufügen.

  10. Notieren Sie sich den Wert des Geheimnisses, das in Ihrem Clientanwendungscode verwendet werden soll. Dieser Geheimniswert kann nach Verlassen dieser Seite nicht erneut angezeigt werden.

Schritt 2: Abrufen eines Azure AD-Zugriffstokens

Bevor Sie eine der Methoden in der Microsoft Store-Übermittlungs-API für MSI- oder EXE-App aufrufen, müssen Sie zunächst ein Azure AD-Zugriffstoken abrufen, das Sie an den Autorisierungsheader jeder Methode in der API übergeben. Nachdem Sie ein Zugriffstoken erhalten haben, haben Sie 60 Minuten Zeit, es zu verwenden, bevor es abläuft. Nach dem Ablauf können Sie das Token aktualisieren, damit Sie es in weiteren Aufrufen der API weiterhin verwenden können.

Gehen Sie zum Abrufen des Zugriffstokens nach den Anweisungen unter [Dienst-zu-Dienst-Aufrufe mit Clientanmeldedaten]/azure/active-directory/azuread-dev/v1-oauth2-client-creds-grant-flow) vor, um einen HTTP POST an den https://login.microsoftonline.com/<tenant_id>/oauth2/token-Endpunkt zu senden. Hier ist eine Beispielanforderung:

POST https://login.microsoftonline.com/<tenant-id>/oauth2/v2.0/token HTTP/1.1
Host: login.microsoftonline.com
Content-Type: application/x-www-form-urlencoded; charset=utf-8

grant_type=client_credentials
&client_id=<your_client_id>
&client_secret=<your_client_secret>
&scope=https://api.store.microsoft.com/.default

Geben Sie die Mandanten-ID, die Client-ID und den Schlüssel für die Anwendung, die Sie im vorherigen Abschnitt aus Partner Center abgerufen haben, für den Wert tenant_id im POST-URI sowie die Parameter client_id und client_secret an. Für den Bereichsparameter müssen Sie https://api.store.microsoft.com/.default angeben.

Nachdem Ihr Zugriffstoken abgelaufen ist, können Sie es nach den hier beschriebenen Anweisungen erneuern.

Beispiele zum Abrufen eines Zugriffstokens unter Verwendung von C# oder Node.js finden Sie in den Codebeispielen für die Microsoft Store-Übermittlungs-API für MSI- oder EXE-App.

Schritt 3: Verwenden der Microsoft Store-Übermittlungs-API

Nachdem Sie über ein Azure AD-Zugriffstoken verfügen, können Sie in der Microsoft Store-Übermittlungs-API für MSI- oder EXE-App Methoden aufrufen. Die API enthält viele Methoden, die in Szenarien für Apps gruppiert sind. Zum Erstellen oder Aktualisieren von Übermittlungen werden in der Regel mehrere Methoden in einer bestimmten Reihenfolge aufgerufen. Informationen zu den einzelnen Szenarien und zur Syntax der einzelnen Methoden finden Sie in den folgenden Abschnitten:

Hinweis

Nach dem Abruf eines Zugriffstokens haben Sie 60 Minuten Zeit zum Aufrufen von Methoden in der Microsoft Store-Übermittlungs-API für MSI- oder EXE-App, bevor es abläuft.

Basis-URL

Die Basis-URL für die Microsoft Store-Übermittlungs-API für MSI- oder EXE-App ist: https://api.store.microsoft.com

API-Verträge

API zum Abrufen der aktuellen Metadaten für Übermittlungsentwürfe

Ruft Metadaten in jedem Modul (Listings, Eigenschaften oder Verfügbarkeit) zum aktuellen Übermittlungsentwurf ab.

Pfad [Alle Module]: /submission/v1/product/{productId}/metadata?languages={languages}&includelanguagelist={true/false}
Pfad [Einzelnes Modul]: /submission/v1/product/{productId}/metadata/{moduleName}?languages={languages}&includelanguagelist={true/false}
Methode: GET

Pfadparameter

Parameter Beschreibung
productId Die Partner Center-ID des Produkts
moduleName Partner Center-Modul – Listings, Eigenschaften oder Verfügbarkeit

Abfrageparameter

Parameter Beschreibung
languages Optional Der Listingsprachenfilter als kommagetrennte Zeichenkette [maximal 200 Sprachen].

Wenn nicht vorhanden, werden die Metadaten der ersten 200 verfügbaren Listingsprachen abgerufen. [ z. B. „en-us, en-gb“].
includelanguagelist Optional Boolean – wenn „true“, wird die Liste der hinzugefügten Listingsprachen und der Status ihrer Abgeschlossenheit zurückgegeben.

Erforderliche Header

Header Wert
Authorization: Bearer <Token> Die im Partner Center-Konto registrierte Azure AD-App-ID
X-Seller-Account-Id Verkäufer-ID des Partner Center-Kontos

Antwortheader

Header Wert
X-Correlation-ID Die eindeutige GUID-Typ-ID für jede Anforderung. Sie kann zur Analyse von Problemen an das Supportteam weitergegeben werden.
Retry-After Die Zeit in Sekunden, die der Client aufgrund der Ratenbegrenzung warten muss, bevor er die APIs erneut aufruft.

Antwortparameter

Name Typ Beschreibung
accessibilitySupport Boolean
additionalLicenseTerms String
Verfügbarkeit Objekt Daten des Verfügbarkeitsmoduls
category String Siehe Liste der Kategorien unten
certificationNotes String
Code String Der Fehlercode der Meldung
contactInfo String
copyright String
dependsOnDriversOrNT Boolean
Beschreibung String
developedBy String
discoverability String [DISCOVERABLE, DEEPLINK_ONLY]
enableInFutureMarkets Boolean
errors Array von Objekten Die Liste der eventuellen Fehler- oder Warnmeldungen
freeTrial String [NO_FREE_TRIAL; FREE_TRIAL]
hardwareItemType String
isPrivacyPolicyRequired Boolean
isRecommended Boolean
isRequired Boolean
IsSuccess Boolean
isSystemFeatureRequired Array von Objekten
Sprache String Siehe Liste der Sprachen unten
listings Array von Objekten Daten des Listingmoduls für jede Sprache
Märkte Array aus Zeichenfolgen Siehe Liste der Märkte unten
message String Die Beschreibung des Fehlers
minimumHardware String
minimumRequirement String
penAndInkSupport Boolean
Preise String [FREE, FREEMIUM, SUBSCRIPTION, PAID]
privacyPolicyUrl String
productDeclarations Objekt
productFeatures Array aus Zeichenfolgen
properties Objekt Daten des Eigenschaftenmoduls
recommendedHardware String
recommendedRequirement String
responseData Objekt Enthält die tatsächliche Antwort-Payload für die Anforderung.
Anforderungen Array von Objekten
searchTerms Array aus Zeichenfolgen
shortDescription String
subcategory String Siehe Liste der Unterkategorien unten
supportContactInfo String
systemRequirementDetails Array von Objekten
target String Die Entität, in der der Fehler seinen Ursprung hat
Website String
whatsNew String

Beispiel für eine Antwort

{
    "isSuccess": true,
    "errors": [{
        "code": "badrequest",
        "message": "Error Message 1",
        "target": "listings"
        }, {
        "code": "warning",
        "message": "Warning Message 1",
        "target": "properties"
    }],
    "responseData": {
        "availability":{
            "markets": ["US"],
            "discoverability": "DISCOVERABLE",
            "enableInFutureMarkets": true,
            "pricing": "PAID",
            "freeTrial": "NO_FREE_TRIAL"
        },
        "properties":{
            "isPrivacyPolicyRequired": true,
            "privacyPolicyUrl": "http://contoso.com",
            "website": "http://contoso.com",
            "supportContactInfo": "http://contoso.com",
            "certificationNotes": "Certification Notes",
            "category": "DeveloperTools",
            "subcategory": "Database",
            "productDeclarations": {
                "dependsOnDriversOrNT": false,
                "accessibilitySupport": false,
                "penAndInkSupport": false
            },
            "isSystemFeatureRequired": [
                {
                    "isRequired": true,
                    "isRecommended": false,
                    "hardwareItemType": "Touch"
                },
                {
                    "isRequired": true,
                    "isRecommended": false,
                    "hardwareItemType": "Keyboard"
                },
                {
                    "isRequired": false,
                    "isRecommended": false,
                    "hardwareItemType": "Mouse"
                },
                {
                    "isRequired": false,
                    "isRecommended": false,
                    "hardwareItemType": "Camera"
                },
                {
                    "isRequired": false,
                    "isRecommended": false,
                    "hardwareItemType": "NFC_HCE"
                },
                {
                    "isRequired": false,
                    "isRecommended": false,
                    "hardwareItemType": "NFC_Proximity"
                },
                {
                    "isRequired": false,
                    "isRecommended": false,
                    "hardwareItemType": "Bluetooth_LE"
                },
                {
                    "isRequired": false,
                    "isRecommended": false,
                    "hardwareItemType": "Telephony"
                },
                {
                    "isRequired": false,
                    "isRecommended": false,
                    "hardwareItemType": "Microphone"
                }
            ],
            "systemRequirementDetails": [
                {
                    "minimumRequirement": "1GB",
                    "recommendedRequirement": "4GB",
                    "hardwareItemType": "Memory"
                },
                {
                    "minimumRequirement": "",
                    "recommendedRequirement": "",
                    "hardwareItemType": "DirectX"
                },
                {
                    "minimumRequirement": "",
                    "recommendedRequirement": "",
                    "hardwareItemType": "Video_Memory"
                },
                {
                    "minimumRequirement": "",
                    "recommendedRequirement": "",
                    "hardwareItemType": "Processor"
                },
                {
                    "minimumRequirement": "",
                    "recommendedRequirement": "",
                    "hardwareItemType": "Graphics"
                }
            ]
        },
        "listings":[{
            "language": "en-us",
            "description": "Description",
            "whatsNew": "What's New",
            "productFeatures": ["Feature 1"],
            "shortDescription": "Short Description",
            "searchTerms": ["Search Ter 1"],
            "additionalLicenseTerms": "License Terms",
            "copyright": "Copyright Information",
            "developedBy": "Developer Details",
            "sortTitle": "Product 101",
            "requirements": [
                {
                    "minimumHardware": "Pentium4",
                    "recommendedHardware": "Corei9"
                }
            ],
            "contactInfo": "contactus@contoso.com"               
        }],      
        "listingLanguages": [{"language":"en-us", "isComplete": true}]
    }
}

API zum Aktualisieren der aktuellen Metadaten für Übermittlungsentwürfe

Aktualisiert Metadaten in jedem Modul des Übermittlungsentwurfs Die API-Prüfungen

  • Für aktive Übermittlung. Wenn vorhanden, Fehler mit Fehlermeldung.
  • Zum Zulassen des Vorgangs „Entwurf speichern“, wenn alle Module den Status „Bereit“ haben.
  • Jedes Feld in der Übermittlung wird gemäß den Anforderungen des Store auf Gültigkeit geprüft.
  • Gültigkeitsprüfungsregeln für Details der Systemanforderungen:
    • Zulässige Werte in hardwareItemType = Memory: 300MB, 750MB, 1GB, 2GB, 4GB, 6GB, 8GB, 12GB, 16GB, 20GB
    • Zulässige Werte in hardwareItemType = DirectX: DX9, DX10, DX11, DX12-FEATURELEVEL11, DX12-FEATURELEVEL12
    • Zulässige Werte in hardwareItemType = Video_Memory: 1GB, 2GB, 4GB, 6GB

Pfad [Vollständiges Update des Moduls]: /submission/v1/product/{productId}/metadata
Methode: PUT

Pfad [Patch-Update des Moduls]: /submission/v1/product/{productId}/metadata
Methode: PATCH

API-Verhalten

Im Fall der API für ein vollständiges Update des Moduls müssen für eine vollständige Aktualisierung jedes Felds sämtliche Moduldaten in der Anforderung vorhanden sein. Bei jedem in der Anforderung nicht vorhanden Feld wird zum Überschreiben des aktuellen Werts für das betreffende Modul der Standardwert verwendet.
Im Fall der API für ein Patch-Update des Moduls müssen nur die zu aktualisierenden Felder in der Anforderung vorhanden sein. Diese Feldwerte aus der Anforderung überschreiben die jeweils vorhandenen Werte, wobei alle anderen Felder, die in der Anforderung nicht vorhanden sind, für das betreffende Modul unverändert bleiben.

Pfadparameter

Parameter Beschreibung
productId Die Partner Center-ID des Produkts

Erforderliche Header

Header Wert
Authorization: Bearer <Token> Die im Partner Center-Konto registrierte Azure AD-App-ID
X-Seller-Account-Id Verkäufer-ID des Partner Center-Kontos

Anforderungsparameter

Name Typ BESCHREIBUNG
Verfügbarkeit Objekt Objekt zum Aufnehmen der Metadaten des Verfügbarkeitsmoduls
Märkte Array aus Zeichenfolgen Erforderlich Siehe Liste der Märkte unten
discoverability String Erforderlich [DISCOVERABLE, DEEPLINK_ONLY]
enableInFutureMarkets Boolean Erforderlich
Preise String Erforderlich [FREE, FREEMIUM, SUBSCRIPTION, PAID]
freeTrial String Erforderlich, wenn für Preise PAID oder SUBSCRIPTION angegeben ist [NO_FREE_TRIAL, FREE_TRIAL]
properties Objekt Objekt zum Aufnehmen der Metadaten des Eigenschaftenmoduls
isPrivacyPolicyRequired Boolean Erforderlich
privacyPolicyUrl String Erforderlich, wenn isPrivacyPolicyRequired = true Muss eine gültige URL sein
Website String Muss eine gültige URL sein
supportContactInfo String Muss eine gültige URL oder E-Mail Adresse sein
certificationNotes String Empfohlen Maximal 2000 Zeichen
category String Erforderlich Siehe Liste der Kategorien unten
subcategory String Erforderlich Siehe Liste der Unterkategorien unten
productDeclarations Objekt Erforderlich
isSystemFeatureRequired Array von Objekten [Toucheingabe, Tastatur, Maus, Kamera, NFC_HCE, NFC_Proximity, Bluetooth_LE, Telefonie, Mikrofon]
isRequired Boolean Erforderlich
isRecommended Boolean Erforderlich
hardwareItemType String Erforderlich
systemRequirementDetails Array von Objekten [Prozessor, Grafiken, Arbeitsspeicher, DirectX, Video_Memory]
minimumRequirement String Erforderlich Für systemRequirementsText, MaxLength = 200

Zulässige Werte in hardwareItemType = Memory: [300MB, 750MB, 1GB, 2GB, 4GB, 6GB, 8GB, 12GB, 16GB, 20GB]

Zulässige Werte in hardwareItemType = DirectX: [DX9, DX10, DX11, DX12-FEATURELEVEL11, DX12-FEATURELEVEL12]

Zulässige Werte in hardwareItemType = Video_Memory: [1GB, 2GB, 4GB, 6GB]
recommendedRequirement String Erforderlich Für systemRequirementsText, MaxLength = 200

Zulässige Werte in hardwareItemType = Memory: [300MB, 750MB, 1GB, 2GB, 4GB, 6GB, 8GB, 12GB, 16GB, 20GB]

Zulässige Werte in hardwareItemType = DirectX: [DX9, DX10, DX11, DX12-FEATURELEVEL11, DX12-FEATURELEVEL12]

Zulässige Werte in hardwareItemType = Video_Memory: [1GB, 2GB, 4GB, 6GB]
dependsOnDriversOrNT Boolean Erforderlich
accessibilitySupport Boolean Erforderlich
penAndInkSupport Boolean Erforderlich
listings Objekt Objekt für die Daten des Listingmoduls für eine einzelne Sprache
Sprache String Erforderlich Siehe Liste der Sprachen unten
Beschreibung String Erforderlich Maximal 10000 Zeichen
whatsNew String Maximal 1500 Zeichen
productFeatures Zeichenfolgenarray 200 Zeichen pro Feature; bis zu 20 Features
shortDescription String Maximal 1000 Zeichen
searchTerms Zeichenfolgenarray 30 Zeichen pro Suchbegriff; bis zu 7 Suchbegriffe

21 eindeutige Wörter INSGESAMT für alle Suchbegriffe
additionalLicenseTerms String Erforderlich Maximal 10000 Zeichen
copyright String Maximal 200 Zeichen
developedBy String Maximal 255 Zeichen
Anforderungen Array von Objekten 200 Zeichen pro Element; bis zu 11 Elemente INSGESAMT zwischen Minimum und empfohlen]
minimumHardware String Maximal 200 Zeichen
recommendedHardware String Maximal 200 Zeichen
contactInfo String Maximal 200 Zeichen
listingsToAdd Array aus Zeichenfolgen Siehe Liste der Sprachen unten
listingsToRemove Array aus Zeichenfolgen Siehe Liste der Sprachen unten

Märkte

Markt Abkürzung
Afghanistan AF
Albanien AL
Algerien DZ
Amerikanisch-Samoa AS
Andorra AD
Angola AO
Anguilla KI
Antarktis AQ
Antigua und Barbuda Verfügbarkeitsgruppe
Argentinien AR
Armenien AM
Aruba AW
Australien AU
Österreich AT
Aserbaidschan RP
Bahamas BS
Bahrain BH
Bangladesch BD
Barbados BB
Belarus BY
Belgien BE
Belize BZ
Benin BJ
Bermudas BM
Bhutan BT
Bolivarische Republik Venezuela VE
Bolivien BO
Bonaire BQ
Bosnien und Herzegowina BA
Botsuana BW
Bouvetinsel BV
Brasilien BR
Britisches Territorium im Indischen Ozean IO
Britische Jungferninseln VG
Brunei BN
Bulgarien BG
Burkina Faso BF
Burundi BI
Kambodscha KH
Kamerun CM
Canada CA
Cabo Verde CV
Kaimaninseln HE
Zentralafrikanische Republik CF
Tschad TD
Chile CL
China CN
Weihnachtsinsel CX
Kokosinseln CC
Kolumbien CO
Komoren KM
Kongo (Demokratische Republik) CG
Kongo (DRC) CD
Cookinseln CK
Costa Rica CR
Kroatien HR
Curaçao CW
Zypern CY
Tschechische Republik CZ
Côte d'Ivoire CI
Dänemark DK
Dschibuti DJ
Dominica DM
Dominikanische Republik DO
Ecuador EC
Ägypten EG
El Salvador SV
Äquatorialguinea GQ
Eritrea ER
Estland EE
Äthiopien ET
Falklandinseln FS
Färöer FO
Fidschi FJ
Finnland FI
Frankreich BV
Französisch-Guayana GF
Französisch-Polynesien PF
Französische Süd- und Antarktisgebiete TF
Gabun Allgemein verfügbar
Gambia GM
Georgien GE
Deutschland DE
Ghana GH
Gibraltar GI
Griechenland GR
Grönland GL
Grenada GD
Guadeloupe GP
Guam GU
Guatemala GT
Guernsey GG
Guinea GN
Guinea-Bissau GW
Guayana GY
Haiti HT
Heard und McDonaldinseln HM
Vatikanstadt VA
Honduras HN
Hongkong (SAR) HK
Ungarn HU
Island IS
Indien IN
Indonesien Kennung
Irak IQ
Irland IE
Israel BY
Italien IT
Jamaika JM
Japan JP
Jersey JE
Jordan JO
Kasachstan KZ
Kenia KE
Kiribati KI
Korea KR
Kuwait KW
Kirgisistan KG
Laos LA
Lettland LV
Libanon LB
Lesotho LS
Liberia LR
Libyen LY
Liechtenstein LI
Litauen LT
Luxemburg LU
Macau (SAR) MO
Nordmazedonien MK
Madagaskar MG
Malawi MW
Malaysia MY
Malediven MV
Mali ML
Malta MT
Isle of Man IM
Marshallinseln MH
Martinique MQ
Mauretanien MR
Mauritius MU
Mayotte YT
Mexiko MX
Mikronesien FM
Moldau MD
Monaco MC
Mongolei BB
Montenegro – ME
Montserrat MS
Marokko NI
Mosambik MZ
Myanmar MM
Namibia Nicht verfügbar
Nauru NR
Nepal NP
Niederlande NL
Neukaledonien NC
Neuseeland NZ
Nicaragua NI
Niger NE
Nigeria NG
Niue NU
Norfolkinsel NF
Nördliche Marianen MP
Norwegen NEIN
Oman OM
Pakistan PK
Palau PW
Palästinensische Autonomiegebiete PS
Panama PA
Papua-Neuguinea PG
Paraguay PY
Peru PE
Philippinen PH
Pitcairninseln PN
Polen PL
Portugal PT
Katar QA
Réunion RE
Rumänien RO
Russland RU
Ruanda RW
St. Barthélemy BL
St. Helena, Ascension und Tristan da Cunha SH
St. Kitts und Nevis KN
St. Lucia LC
St. Martin (französischer Teil) MF
St. Pierre und Miquelon PM
St. Vincent und die Grenadinen VC
Samoa WS
San Marino SM
Saudi-Arabien SA
Senegal SN
Serbien RS
Seychellen SC
Sierra Leone SL
Singapur SG
Sint Maarten (niederländischer Teil) SX
Slowakei SK
Slowenien SI
Salomonen SB
Somalia SO
Südafrika ZA
Südgeorgien und die Südlichen Sandwichinseln GS
Spanien ES
Sri Lanka LK
Surinam SR
Spitzbergen und Jan Mayen SJ
Swasiland SZ
Schweden SE
Schweiz CH
São Tomé und Príncipe ST
Taiwan TW
Tadschikistan TJ
Tansania TZ
Thailand TH
Timor-Leste TL
Togo – TG
Tokelau TK
Tonga TO
Trinidad und Tobago – TT
Tunesien TN
Türkiye TR
Turkmenistan TM
Turks- und Caicosinseln TC
Tuwalu TV
USA Kleinere Amerikanische Überseeinseln UM
Amerikanische Jungferninseln VI
Uganda UG
Ukraine UA
Vereinigte Arabische Emirate AE
United Kingdom GB
USA US
Uruguay UY
Usbekistan UZ
Vanuatu VU
Vietnam VN
Wallis und Futuna WF
Jemen YE
Sambia ZM
Simbabwe ZW
Ålandinseln AX

Kategorien und Unterkategorien

Kategorie Unterkategorien
BooksAndReference EReader, Fiction, Nonfiction, Reference
Business AccountingAndfinance, Collaboration, CRM, DataAndAnalytics, FileManagement, InventoryAndlogistics, LegalAndHR, ProjectManagement, RemoteDesktop, SalesAndMarketing, TimeAndExpenses
DeveloperTools Database, DesignTools, DevelopmentKits, Networking, ReferenceAndTraining, Servers, Utilities, WebHosting
Education EducationBooksAndReference, EarlyLearning, InstructionalTools, Language, StudyAids
Entertainment (Keine)
FoodAndDining (Keine)
GovernmentAndPolitics (Keine)
HealthAndFitness (Keine)
KidsAndFamily KidsAndFamilyBooksAndReference, KidsAndFamilyEntertainment, HobbiesAndToys, SportsAndActivities, KidsAndFamilyTravel
Lifestyle Automotive, DYI, HomeAndGarden, Relationships, SpecialInterest, StyleAndFashion
Medizin (Keine)
MultimediaDesign IllustrationAndGraphicDesign, MusicProduction, PhotoAndVideoProduction
Musik (Keine)
NavigationAndMaps (Keine)
NewsAndWeather Nachrichten, Wetter
PersonalFinance BankingAndInvestments, BudgetingAndTaxes
Personalisierung RingtonesAndSounds, themes, WallpaperAndLockScreens
PhotoAndVideo (Keine)
Produktivität (Keine)
Sicherheit PCProtection, PersonalSecurity
Shopping (Keine)
Soziale Netzwerke (Keine)
Sport (Keine)
Anfahrt CityGuides, Hotels
UtilitiesAndTools BackupAndManage, FileManager

Sprachen

Name der Sprache Unterstützte Sprachcodes
Afrikaans af, af-za
Albanisch sq, sq-al
Amharisch am, am-et
Armenisch hy, hy-am
Assamesisch as, as-in
Aserbaidschanisch az-arab, az-arab-az, az-cyrl, az-cyrl-az, az-latn, az-latn-az
Baskisch (Baskisch) eu, eu-es
Belarussisch be, be-by
Bengalisch bn, bn-bd, bn-in
Bosnisch bs, bs-cyrl, bs-cyrl-ba, bs-latn, bs-latn-ba
Bulgarisch bg, bg-bg
Katalanisch ca, ca-es, ca-es-valencia
Cherokee chr-cher, chr-cher-us, chr-latn
Chinesisch (vereinfacht) zh-Hans, zh-cn, zh-hans-cn, zh-sg, zh-hans-sg
Chinesisch (traditionell) zh-Hant, zh-hk, zh-mo, zh-tw, zh-hant-hk, zh-hant-mo, zh-hant-tw, zh-mo, zh-tw, zh-hant-hk, zh-hant-mo, zh-hant-tw
Kroatisch hr, hr-hr, hr-ba
Tschechisch cs, cs-cz
Dänisch da, da-dk
Dari prs, prs-af, prs-arab
Niederländisch nl, nl-nl, nl-be
Englisch en, en-au, en-ca, en-gb, en-ie, en-in, en-nz, en-sg, en-us, en-za, en-bz, en-hk, en-id, en-jm, en-kz, en-mt, en-my, en-ph, en-pk, en-tt, en-vn, en-zw
Estnisch et, et-ee
Philippinisch – fil, fil-latn, fil-ph
Finnisch fi, fi-fi
Französisch fr, fr-be , fr-ca , fr-ch , fr-fr , fr-lu, fr-cd, fr-ci, fr-cm, fr-ht, fr-ma, fr-mc, fr-ml, fr-re, frc-latn, frp-latn
Galicisch gl, gl-es
Georgisch ka, ka-ge
Deutsch de, de-at, de-ch, de-de, de-lu, de-li
Griechisch el, el-gr
Gujarati gu, gu-in
Haussa ha, ha-latn, ha-latn-ng
Hebräisch he, he-il
Hindi hi, hi-in
Ungarisch hu, hu-hu
Isländisch is, is-is
Igbo – ig-latn, ig-ng
Indonesisch id, id-id
Inuktitut (Lateinisch) iu-cans, iu-latn, iu-latn-ca
Irisch ga, ga-ie
isi Xhosa xh, xh-za
isi Zulu zu, zu-za
Italienisch it, it-it, it-ch
Japanisch ja , ja-jp
Kannada kn, kn-in
Kasachisch kk, kk-kz
Khmer km, km-kh
K'iche' quc-latn, qut-gt, qut-latn
Kinyarwanda rw, rw-rw
Kisuaheli sw, sw-ke
Konkani kok, kok-in
Koreanisch ko, ko-kr
Kurdisch ku-arab, ku-arab-iq
Kirgisisch ky-kg, ky-cyrl
Laotisch lo, lo-la
Lettisch lv, lv-lv
Litauisch lt, lt-lt
Luxemburgisch lb, lb-lu
Mazedonisch mk, mk-mk
Malaiisch ms, ms-bn, ms-my
Malayalam ml, ml-in
Maltesisch mt, mt-mt
Maori mi, mi-latn, mi-nz
Marathi mr, mr-in
Mongolisch (Kyrillisch) mn-cyrl, mn-mong, mn-mn, mn-phag
Nepalesisch ne, ne-np
Norwegisch nb, nb-no, nn, nn-no, no, no-no
Odia or, or-in
Persisch fa, fa-ir
Polnisch pl, pl-pl
Portugiesisch (Brasilien) pt-br
Portugiesisch (Portugal) pt, pt-pt
Pandschabi pa, pa-arab, pa-arab-pk, pa-deva, pa-in
Quechua quz, quz-bo, quz-ec, quz-pe
Rumänisch ro, ro-ro
Russisch ru , ru-ru
Schottisch-Gälisch gd-gb, gd-latn
Serbisch (Lateinisch) sr-Latn, sr-latn-cs, sr, sr-latn-ba, sr-latn-me, sr-latn-rs
Serbisch (Kyrillisch) sr-cyrl, sr-cyrl-ba, sr-cyrl-cs, sr-cyrl-me, sr-cyrl-rs
Nord-Sotho nso, nso-za
Tswana tn, tn-bw, tn-za
Sindhi sd-arab, sd-arab-pk, sd-deva
Singhalesisch si, si-lk
Slowakisch sk, sk-sk
Slowenisch sl, sl-si
Spanisch es, es-cl, es-co, es-es, es-mx, es-ar, es-bo, es-cr, es-do, es-ec, es-gt, es-hn, es-ni, es-pa, es-pe, es-pr, es-py, es-sv, es-us, es-uy, es-ve
Schwedisch sv, sv-se, sv-fi
Tadschikisch (Kyrillisch) tg-arab, tg-cyrl, tg-cyrl-tj, tg-latn
Tamilisch ta, ta-in
Tatarisch tt-arab, tt-cyrl, tt-latn, tt-ru
Telugu te, te-in
Thailändisch th, th-th
Tigrinya ti, ti-et
Türkisch tr, tr-tr
Turkmenisch tk-cyrl, tk-latn, tk-tm, tk-latn-tr, tk-cyrl-tr
Ukrainisch uk, uk-ua
Urdu ur, ur-pk
Uigurisch ug-arab, ug-cn, ug-cyrl, ug-latn
Usbekisch (Lateinisch) uz, uz-cyrl, uz-latn, uz-latn-uz
Vietnamesisch vi, vi-vn
Walisisch cy, cy-gb
Wolof wo, wo-sn
Yoruba yo-latn, yo-ng

Beispiel für eine Anforderung

{
    "availability":{
        "markets": ["US"],
        "discoverability": "DISCOVERABLE",
        "enableInFutureMarkets": true,
        "pricing": "PAID",
        "freeTrial": "NO_FREE_TRIAL"
    },
    "properties":{
        "isPrivacyPolicyRequired": true,
        "privacyPolicyUrl": "http://contoso.com",
        "website": "http://contoso.com",
        "supportContactInfo": "http://contoso.com",
        "certificationNotes": "Certification Notes",
        "category": "DeveloperTools",
        "subcategory": "Database",
        "productDeclarations": {
            "dependsOnDriversOrNT": false,
            "accessibilitySupport": false,
            "penAndInkSupport": false
        },
        "isSystemFeatureRequired": [
        {
            "isRequired": true,
                "isRecommended": false,
                "hardwareItemType": "Touch"
            },
            {
                "isRequired": true,
                "isRecommended": false,
                "hardwareItemType": "Keyboard"
            },
            {
                "isRequired": false,
                "isRecommended": false,
                "hardwareItemType": "Mouse"
            },
            {
                "isRequired": false,
                "isRecommended": false,
                "hardwareItemType": "Camera"
            },
            {
                "isRequired": false,
                "isRecommended": false,
                "hardwareItemType": "NFC_HCE"
            },
            {
                "isRequired": false,
                "isRecommended": false,
                "hardwareItemType": "NFC_Proximity"
            },
            {
                "isRequired": false,
                "isRecommended": false,
                "hardwareItemType": "Bluetooth_LE"
            },
            {
                "isRequired": false,
                "isRecommended": false,
                "hardwareItemType": "Telephony"
            },
            {
                "isRequired": false,
                "isRecommended": false,
                "hardwareItemType": "Microphone"
            }
        ],
        "systemRequirementDetails": [
            {
                "minimumRequirement": "1GB",
                "recommendedRequirement": "4GB",
                "hardwareItemType": "Memory"
            },
            {
                "minimumRequirement": "",
                "recommendedRequirement": "",
                "hardwareItemType": "DirectX"
            },
            {
                "minimumRequirement": "",
                "recommendedRequirement": "",
                "hardwareItemType": "Video_Memory"
            },
            {
                "minimumRequirement": "",
                "recommendedRequirement": "",
                "hardwareItemType": "Processor"
            },
            {
                "minimumRequirement": "",
                "recommendedRequirement": "",
                "hardwareItemType": "Graphics"
            }
        ]
    },
    "listings":{
        "language": "en-us",
        "description": "Description",
        "whatsNew": "What's New",
        "productFeatures": ["Feature 1"],
        "shortDescription": "Short Description",
        "searchTerms": ["Search Ter 1"],
        "additionalLicenseTerms": "License Terms",
        "copyright": "Copyright Information",
        "developedBy": "Developer Details",
        "sortTitle": "Product 101",
        "requirements": [
            {
                "minimumHardware": "Pentium4",
                "recommendedHardware": "Corei9"
            }
        ],
        "contactInfo": "contactus@contoso.com"               
    },      
    "listingsToAdd": ["en-au"],
    "listingsToRemove": ["en-gb"]
}

Antwortheader

Header Wert
X-Correlation-ID Die eindeutige GUID-Typ-ID für jede Anforderung. Sie kann zur Analyse von Problemen an das Supportteam weitergegeben werden.
Retry-After Die Zeit in Sekunden, die der Client aufgrund der Ratenbegrenzung warten muss, bevor er die APIs erneut aufruft.

Antwortparameter

Name Typ Beschreibung
IsSuccess Boolean
errors Array von Objekten Die Liste der eventuellen Fehler- oder Warnmeldungen
Code String Der Fehlercode der Meldung
message String Die Beschreibung des Fehlers
target String Die Entität, in der der Fehler seinen Ursprung hat
responseData Objekt Enthält die tatsächliche Antwort-Payload für die Anforderung.
pollingUrl String Abruf-URL zum Abrufen des Status einer laufenden Übermittlung
ongoingSubmissionId String Übermittlungs-ID einer bereits laufenden Übermittlung

Beispiel für eine Antwort

{
    "isSuccess": true,
    "errors": [{
        "code": "badrequest",
        "message": "Error Message 1",
        "target": "listings"
        }, {
        "code": "warning",
        "message": "Warning Message 1",
        "target": "properties"
    }],
    "responseData": {
        "pollingUrl": "/submission/v1/product/{productId}/submission/{submissionId}/status",
        "ongoingSubmissionId": ""
    } 
}

API zum Abrufen der aktuellen Paketentwürfe

Ruft Paketdetails zum aktuellen Übermittlungsentwurf ab.

Pfad [Alle Pakete]: /submission/v1/product/{productId}/packages
Methode: GET

Pfad [Einzelnes Paket]: /submission/v1/product/{productId}/packages/{packageId}
Methode: GET

Pfadparameter

Name Beschreibung
productId Die Partner Center-ID des Produkts
packageId Die eindeutige ID des abzurufenden Pakets

Erforderliche Header

Header Wert
Authorization: Bearer <Token> Verwenden der im Partner Center-Konto registrierten Azure AD-App-ID
X-Seller-Account-Id Verkäufer-ID des Partner Center-Kontos

Antwortheader

Header Wert
X-Correlation-ID Die eindeutige GUID-Typ-ID für jede Anforderung. Sie kann zur Analyse von Problemen an das Supportteam weitergegeben werden.
Retry-After Die Zeit in Sekunden, die der Client aufgrund der Ratenbegrenzung warten muss, bevor er die APIs erneut aufruft.

Antwortparameter

Name Typ Beschreibung
IsSuccess Boolean
errors Array von Objekten Die Liste der eventuellen Fehler oder Warnmeldungen
Code String Der Fehlercode der Meldung
message String Die Beschreibung des Fehlers
target String Die Entität, in der der Fehler seinen Ursprung hat
responseData Objekt
packages Array von Objekten Objekt zum Aufnehmen der Daten des Paketmoduls
packageId String
packageUrl String
languages Array aus Zeichenfolgen
architectures Array aus Zeichenfolgen [Neutral; X86; X64; Arm; Arm64]
isSilentInstall Boolean Sollte als „true“ markiert sein, wenn das Installationsprogramm ohne erforderliche Switches im unbeaufsichtigten Modus ausgeführt wird, oder andernfalls als „false“
installerParameters String
genericDocUrl String
errorDetails Array von Objekten
errorScenario String
errorScenarioDetails Array von Objekten
errorValue String
errorUrl String
packageType String

Beispiel für eine Antwort

{   
    "isSuccess": true,
    "errors": [{
        "code": "badrequest",
        "message": "Error Message 1",
        "target": "listings"
    }, {
        "code": "warning",
        "message": "Warning Message 1",
        "target": "properties"
    }],
    "responseData":{
        "packages":[{
            "packageId": "pack0832",
            "packageUrl": "https://www.contoso.com/downloads/1.1/setup.exe",
            "languages": ["en-us"],
            "architectures": ["X86"],
            "isSilentInstall": true,
            "installerParameters": "/s",
            "genericDocUrl": "https://docs.contoso.com/doclink",
            "errorDetails": [{
                "errorScenario": "rebootRequired",
                "errorScenarioDetails": [{
                    "errorValue": "ERR001001",
                    "errorUrl": "https://errors.contoso.com/errors/ERR001001"
                }]
            }],
            "packageType": "exe",
        }]
    }
}

API zum Aktualisieren der aktuellen Paketentwürfe

Aktualisiert Paketdetails zum aktuellen Übermittlungsentwurf.

Pfad [Vollständiges Update des Moduls]: /submission/v1/product/{productId}/packages
Methode: PUT

Pfad [Patch-Update eines einzelnen Pakets]: /submission/v1/product/{productId}/packages/{packageId}
Methode: PATCH

API-Verhalten

Im Fall der API für ein vollständiges Update des Moduls müssen für eine vollständige Aktualisierung jedes Felds sämtliche Paketdaten in der Anforderung vorhanden sein. Bei jedem in der Anforderung nicht vorhanden Feld wird zum Überschreiben des aktuellen Werts für das betreffende Modul der Standardwert verwendet. Dadurch werden alle vorhandenen Pakete mit einem neuen Satz von Paketen aus der Anforderung überschrieben. Dadurch werden Paket-IDs neu generiert, und der Benutzer sollte für die neuesten Paket-IDs die API zum Abrufen von Paketen aufrufen.

Im Fall der API für ein Patch-Update eines einzelnen Pakets müssen nur die für ein bestimmtes Paket zu aktualisierenden Felder in der Anforderung vorhanden sein. Diese Feldwerte aus der Anforderung überschreiben die jeweils vorhandenen Werte, wobei alle anderen Felder, die in der Anforderung nicht vorhanden sind, für das betreffende Paket unverändert bleiben. Andere Pakete im Satz bleiben unverändert.

Pfadparameter

Name Beschreibung
productId Die Partner Center-ID des Produkts
packageId Die eindeutige ID des Pakets

Erforderliche Header

Header Wert
Authorization: Bearer <Token> Verwenden der im Partner Center-Konto registrierten Azure AD-App-ID
X-Seller-Account-Id Verkäufer-ID des Partner Center-Kontos

Anforderungsparameter

Name Typ Beschreibung
packages Array von Objekten Objekt zum Aufnehmen der Daten des Paketmoduls [Nur erforderlich für vollständiges Update des Moduls]
packageUrl String Erforderlich
languages Array aus Zeichenfolgen Erforderlich
architectures Array aus Zeichenfolgen Erforderlich Sollte eine einzelne Architektur enthalten – Neutral, X86, X64, Arm, Arm64
isSilentInstall Boolean Erforderlich Sollte als „true“ markiert sein, wenn das Installationsprogramm ohne erforderliche Switches im unbeaufsichtigten Modus ausgeführt wird, oder andernfalls als „false“
installerParameters String Erforderlich, wenn isSilentInstall „false“ ist
genericDocUrl String Erforderlich, wenn packageType „exe“ ist Link zum Dokument mit Details der benutzerdefinierten Fehlercodes für das EXE-Typ-Installationsprogramm
errorDetails Array von Objekten Metadaten zum Aufnehmen benutzerdefinierter Fehlercodes und Details für EXE-Typ-Installationsprogramme.
errorScenario String Bestimmung des spezifischen Fehlerszenarios. [installationCancelledByUser, applicationAlreadyExists, installationAlreadyInProgress, diskSpaceIsFull, rebootRequired, networkFailure, packageRejectedDuringInstallation, installationSuccessful, miscellaneous]
errorScenarioDetails Array von Objekten
errorValue String Fehlercode, der während der Installation vorhanden sein kann
errorUrl String URL mit Details zum Fehler
packageType String Erforderlich [exe, msi]

Beispielanforderung [Vollständiges Update des Moduls]

{
    "packages":[{
        "packageUrl": "https://www.contoso.com/downloads/1.1/setup.exe",
        "languages": ["en-us"],
        "architectures": ["X86"],
        "isSilentInstall": true,
        "installerParameters": "/s",
        "genericDocUrl": "https://docs.contoso.com/doclink",
        "errorDetails": [{
            "errorScenario": "rebootRequired",
            "errorScenarioDetails": [{
                "errorValue": "ERR001001",
                "errorUrl": "https://errors.contoso.com/errors/ERR001001"
            }]
        }],
        "packageType": "exe",
    }]
}

Beispielanforderung [Patch-Update eines einzelnen Pakets]

{
    "packageUrl": "https://www.contoso.com/downloads/1.1/setup.exe",
    "languages": ["en-us"],
    "architectures": ["X86"],
    "isSilentInstall": true,
    "installerParameters": "/s",
    "genericDocUrl": "https://docs.contoso.com/doclink",
    "errorDetails": [{
        "errorScenario": "rebootRequired",
        "errorScenarioDetails": [{
            "errorValue": "ERR001001",
            "errorUrl": "https://errors.contoso.com/errors/ERR001001"
        }]
    }],
    "packageType": "exe",
}

Antwortheader

Header Wert
X-Correlation-ID Die eindeutige GUID-Typ-ID für jede Anforderung. Sie kann zur Analyse von Problemen an das Supportteam weitergegeben werden.
Retry-After Die Zeit in Sekunden, die der Client aufgrund der Ratenbegrenzung warten muss, bevor er die APIs erneut aufruft.

Antwortparameter

Name Typ Beschreibung
IsSuccess Boolean
errors Array von Objekten [Die Liste der eventuellen Fehler- oder Warnmeldungen]
Code String Der Fehlercode der Meldung
message String Die Beschreibung des Fehlers
target String Die Entität, in der der Fehler seinen Ursprung hat
responseData Objekt
pollingUrl String [Abruf-URL zum Abrufen des Status im Fall einer bereits laufenden Übermittlung]
ongoingSubmissionId String [Übermittlungs-ID einer bereits laufenden Übermittlung]

Beispiel für eine Antwort

{
    "isSuccess": true,
    "errors": [{
        "code": "badrequest",
        "message": "Error Message 1",
        "target": "listings"
        }, {
        "code": "warning",
        "message": "Warning Message 1",
        "target": "properties"
    }],
    "responseData": {
        "pollingUrl": "/submission/v1/product/{productId}/submission/{submissionId}/status",
        "ongoingSubmissionId": ""
    } 
}

API zum Committen von Paketen

Committet den neuen Satz von Paketen, die mit den APIs zum Aktualisieren von Paketen zum aktuellen Übermittlungsentwurf aktualisiert wurden. Diese API gibt eine Abruf-URL zum Nachverfolgen des Paketuploads zurück.

Pfad: /submission/v1/product/{productId}/packages/commit
Methode: POST

Pfadparameter

Name Beschreibung
productId Die Partner Center-ID des Produkts

Erforderliche Header

Header Wert
Authorization: Bearer <Token> Verwenden der im Partner Center-Konto registrierten Azure AD-App-ID
X-Seller-Account-Id Verkäufer-ID des Partner Center-Kontos

Antwortheader

Header Wert
X-Correlation-ID Die eindeutige GUID-Typ-ID für jede Anforderung. Sie kann zur Analyse von Problemen an das Supportteam weitergegeben werden.
Retry-After Die Zeit in Sekunden, die der Client aufgrund der Ratenbegrenzung warten muss, bevor er die APIs erneut aufruft.

Antwortparameter

Name Typ Beschreibung
IsSuccess Boolean
errors Array von Objekten [Die Liste der eventuellen Fehler- oder Warnmeldungen]
Code String Der Fehlercode der Meldung
message String Die Beschreibung des Fehlers
target String Die Entität, in der der Fehler seinen Ursprung hat
responseData Objekt
pollingUrl String [Abruf-URL zum Abrufen des Status von Paketuploads oder des Übermittlungsstatus im Fall einer bereits laufenden Übermittlung]
ongoingSubmissionId String [Übermittlungs-ID einer bereits laufenden Übermittlung]

Beispiel für eine Antwort

{
    "isSuccess": true,
    "errors": [{
        "code": "badrequest",
        "message": "Error Message 1",
        "target": "listings"
        }, {
        "code": "warning",
        "message": "Warning Message 1",
        "target": "properties"
    }],
    "responseData": {
        "pollingUrl": "/submission/v1/product/{productId}/status",
        "ongoingSubmissionId": ""
    } 
}

API zum Abrufen der aktuellen Listingentwurfsobjekte

Ruft Details zu Listingobjekten zum aktuellen Übermittlungsentwurf ab.

Pfad: /submission/v1/product/{productId}/listings/assets?languages={languages}
Methode: GET

Pfadparameter

Name Beschreibung
productId Die Partner Center-ID des Produkts

Abfrageparameter

Name Beschreibung
languages [Optional] Der Listingsprachenfilter als kommagetrennte Zeichenkette [maximal 200 Sprachen]. Wenn nicht vorhanden, werden die Objektdaten der ersten 200 verfügbaren Listingsprachen abgerufen. (z. B. „en-us, en-gb“)

Erforderliche Header

Header Wert
Authorization: Bearer <Token> Verwenden der im Partner Center-Konto registrierten Azure AD-App-ID
X-Seller-Account-Id Verkäufer-ID des Partner Center-Kontos

Antwortheader

Header Wert
X-Correlation-ID Die eindeutige GUID-Typ-ID für jede Anforderung. Sie kann zur Analyse von Problemen an das Supportteam weitergegeben werden.
Retry-After Die Zeit in Sekunden, die der Client aufgrund der Ratenbegrenzung warten muss, bevor er die APIs erneut aufruft.

Antwortparameter

Name Typ Beschreibung
IsSuccess Boolean
errors Array von Objekten Die Liste der eventuellen Fehler- oder Warnmeldungen
Code String Der Fehlercode der Meldung
message String Die Beschreibung des Fehlers
target String Die Entität, in der der Fehler seinen Ursprung hat
responseData Objekt
listingAssets Array von Objekten Details zu Listingobjekten für jede Sprache
Sprache String
storeLogos Array von Objekten
screenshots Array von Objekten
id String
assetUrl String Muss eine gültige URL sein
imageSize Objekt
width Ganzzahl
Höhe Ganzzahl

Beispiel für eine Antwort

{   
"isSuccess": true,
    "errors": [{
        "code": "badrequest",
        "message": "Error Message 1",
        "target": "listings"
        }, {
        "code": "warning",
        "message": "Warning Message 1",
        "target": "properties"
    }],
    "responseData":{
        "listingAssets": [{
            "language": "en-us",
            "storeLogos": [
                {
                    "id": "1234567890abcdefgh",
                    "assetUrl": "https://contoso.com/blob=1234567890abcdefgh",
                    "imageSize": {
                        "width": 2160,
                        "height": 2160
                    }
                }
            ],
            "screenshots": [
                {
                    "id": "1234567891abcdefgh",
                    "assetUrl": "https://contoso.com/blob=1234567891abcdefgh",
                    "imageSize": {
                        "width": 2160,
                        "height": 2160
                    }
                }
            ]
        }]
    }
}

API zum Erstellen von Listingobjekten

Erstellt einen neuen Upload von Listingobjekten zum aktuellen Übermittlungsentwurf.

Aktualisieren von Listingobjekten

Die Microsoft Store-Übermittlungs-API für EXE- oder MSI-App verwendet laufzeitgenerierte SAS-URLs für Blob-Stores für die einzelnen Uploads von Bildobjekten zusammen mit einem Commit-API-Aufruf nach erfolgreichem Upload. Um die Möglichkeit zu haben, Listingobjekte zu aktualisieren und im Gegenzug Gebietsschemas im Listingmodul hinzuzufügen/zu entfernen, können Sie folgendermaßen vorgehen:

  1. Senden Sie über die API zum Erstellen von Listingobjekten eine Anforderung zum Ressourcenupload unter Angabe von Sprache, Typ und Anzahl der Ressourcen.
  2. Basierend auf der Anzahl der angeforderten Objekte werden Objekt-IDs nach Bedarf erstellt, und es wird eine kurzzeitige SAS-URL erstellt und im Antworttext unter dem Objekttyp zurückgesendet. Anhand dieser URL können Sie Bildobjekte des betreffenden Typs über HTTP-Clients hochladen [Put Blob (REST-API) – Azure Storage | Microsoft-Dokumentation].
  3. Nach dem Hochladen können Sie über die API zum Committen von Listingobjekten auch die zuvor aus dem vorherigen API-Aufruf empfangenen neuen Objekt-ID-Informationen senden. Die einzelne API führt nach der Validierung intern einen Commit für die Daten der Listingobjekte durch.
  4. Dadurch wird der gesamte Satz früherer Bilder des Objekttyps zu einer bestimmten Sprache aus der gesendeten Anforderung effektiv überschrieben. Daher werden zuvor hochgeladene Objekte entfernt.

Pfad: /submission/v1/product/{productId}/listings/assets/create
Methode: POST

Pfadparameter

Name Beschreibung
productId Die Partner Center-ID des Produkts

Erforderliche Header

Header Beschreibung
Authorization: Bearer <Token> Verwenden der im Partner Center-Konto registrierten Azure AD-App-ID
X-Seller-Account-Id Verkäufer-ID des Partner Center-Kontos

Anforderungsparameter

Name Typ BESCHREIBUNG
language String Erforderlich
createAssetRequest Objekt Erforderlich
Screenshot Ganzzahl Erforderlich, wenn ISV Screenshots aktualisieren oder eine neue Listingsprache hinzufügen muss [1 – 10]
Logo Ganzzahl Erforderlich, wenn ISV Logos aktualisieren oder eine neue Listingsprache hinzufügen muss [1 oder 2]

Antwortheader

Header Beschreibung
X-Correlation-ID Die eindeutige GUID-Typ-ID für jede Anforderung. Sie kann zur Analyse von Problemen an das Supportteam weitergegeben werden.
Retry-After Die Zeit in Sekunden, die der Client aufgrund der Ratenbegrenzung warten muss, bevor er die APIs erneut aufruft.

Antwortparameter

Name Typ Beschreibung
IsSuccess Boolean
errors Array von Objekten Die Liste der eventuellen Fehler- oder Warnmeldungen
Code String Der Fehlercode der Meldung
message String Die Beschreibung des Fehlers
target String Die Entität, in der der Fehler seinen Ursprung hat
responseData Objekt
listingAssets Objekt Objekt mit Details zu StoreLogos und Screenshots, die hochgeladen werden sollen
Sprache String
storeLogos Array von Objekten
screenshots Array von Objekten
id String
primaryAssetUploadUrl String Primäre URL zum Hochladen eines Listingobjekts über die Azure Blob REST-API
secondaryAssetUploadUrl String Sekundäre URL zum Hochladen eines Listingobjekts über die Azure Blob REST-API
HTTP-Methode HTTP-Methode Die HTTP-Methode, die zum Hochladen von Objekten über die Objektupload-URLs verwendet werden muss – primär oder sekundär
httpHeaders Objekt Ein Objekt mit Schlüsseln als erforderliche Header, das im Upload-API-Aufruf an Objektupload-URLs vorhanden sein muss. Wenn der Wert nicht leer ist, müssen die Header bestimmte Werte haben. Andernfalls werden während des API-Aufrufs Werte berechnet.

Beispiel für eine Antwort

{
    "isSuccess": true,
    "errors": [{
        "code": "badrequest",
        "message": "Error Message 1",
        "target": "listings"
        }, {
        "code": "warning",
        "message": "Warning Message 1",
        "target": "properties"
    }],
    "responseData": {
        "listingAssets": {
            "language": "en-us",
            "storeLogos":[{
                "id": "1234567890abcdefgh",
                "primaryAssetUploadUrl": "https://contoso.com/upload?blob=1234567890abcdefgh&sig=12345",
                "secondaryAssetUploadUrl": "https://contoso.com/upload?blob=0987654321abcdfger&sig=54326",
                "httpMethod": "PUT",
                "httpHeaders": {"Required Header Name": "Header Value"}
            }],
            "screenshots":[{
                "id": "0987654321abcdfger",
                "primaryAssetUploadUrl": "https://contoso.com/upload?blob=0987654321abcdfger&sig=54321",
                "secondaryAssetUploadUrl": "https://contoso.com/upload?blob=0987654321abcdfger&sig=54322",
                "httpMethod": "PUT",
                "httpHeaders": {"Required Header Name": "Header Value"}

            }]
        }
    } 
}

API zum Committen von Listingobjekten

Committet das neue hochgeladene Listingobjekt anhand der Details aus der API zum Erstellen von Objekten zum aktuellen Übermittlungsentwurf.

Pfad: /submission/v1/product/{productId}/listings/assets/commit
Methode: PUT

Pfadparameter

Name Beschreibung
productId Die Partner Center-ID des Produkts

Erforderliche Header

Header Beschreibung
Authorization: Bearer <Token> Verwenden der im Partner Center-Konto registrierten Azure AD-App-ID
X-Seller-Account-Id Verkäufer-ID des Partner Center-Kontos

Anforderungsparameter

Name Typ Beschreibung
listingAssets Objekt
Sprache String
storeLogos Array von Objekten
screenshots Array von Objekten
id String Sollte entweder eine vorhandene ID aus der API zum Abrufen der aktuellen Listingobjekte sein, die der Benutzer beibehalten möchte, oder eine neue ID, unter der ein neues Objekt in die API zum Erstellen von Listingobjekten hochgeladen wurde.
assetUrl String Sollte entweder die URL des vorhandenen Objekts aus der API zum Abrufen der aktuellen Listingobjekte sein, die der Benutzer beibehalten möchte, oder die Upload-URL – primär oder sekundär –, mit der ein neues Objekt in die API zum Erstellen von Listingobjekten hochgeladen wurde. Muss eine gültige URL sein

Beispiel für eine Anforderung

{
    "listingAssets": { 
        "language": "en-us",    
        "storeLogos": [
            {
                "id": "1234567890abcdefgh",
                "assetUrl": "https://contoso.com/blob=1234567890abcdefgh",
            }
        ],
        "screenshots": [
            {
                "id": "1234567891abcdefgh",
                "assetUrl": "https://contoso.com/blob=1234567891abcdefgh",
            }
        ]
    }
}

Antwortheader

Header Beschreibung
X-Correlation-ID Die eindeutige GUID-Typ-ID für jede Anforderung. Sie kann zur Analyse von Problemen an das Supportteam weitergegeben werden.
Retry-After Die Zeit in Sekunden, die der Client aufgrund der Ratenbegrenzung warten muss, bevor er die APIs erneut aufruft.

Antwortparameter

Name Typ Beschreibung
IsSuccess Boolean
errors Array von Objekten Die Liste der eventuellen Fehler- oder Warnmeldungen
Code String Der Fehlercode der Meldung
message String Die Beschreibung des Fehlers
target String Die Entität, in der der Fehler seinen Ursprung hat
responseData Objekt
pollingUrl String Abruf-URL zum Abrufen des Status einer laufenden Übermittlung
ongoingSubmissionId String Übermittlungs-ID einer bereits laufenden Übermittlung

Beispiel für eine Antwort

{
    "isSuccess": true,
    "errors": [{
        "code": "badrequest",
        "message": "Error Message 1",
        "target": "listings"
        }, {
        "code": "warning",
        "message": "Warning Message 1",
        "target": "properties"
    }],
    "responseData": {
        "pollingUrl": "/submission/v1/product/{productId}/submission/{submissionId}/status",
        "ongoingSubmissionId": ""
    } 
}

API zum Abrufen des Modulstatus

API zum Überprüfen der Bereitschaft des Moduls, bevor die Übermittlung erstellt werden kann. Validiert außerdem den Uploadstatus des Pakets.

Pfad: /submission/v1/product/{productId}/status
Methode: GET

Pfadparameter

Name Beschreibung
productId Die Partner Center-ID des Produkts

Erforderliche Header

Header Beschreibung
Authorization: Bearer <Token> Verwenden der im Partner Center-Konto registrierten Azure AD-App-ID
X-Seller-Account-Id Verkäufer-ID des Partner Center-Kontos

Antwortheader

Header Beschreibung
X-Correlation-ID Die eindeutige GUID-Typ-ID für jede Anforderung. Sie kann zur Analyse von Problemen an das Supportteam weitergegeben werden.
Retry-After Die Zeit in Sekunden, die der Client aufgrund der Ratenbegrenzung warten muss, bevor er die APIs erneut aufruft.

Antwortparameter

Name Typ Beschreibung
IsSuccess Boolean
errors Array von Objekten Die Liste der eventuellen Fehler- oder Warnmeldungen
Code String Der Fehlercode der Meldung
message String Die Beschreibung des Fehlers
target String Die Entität, in der der Fehler seinen Ursprung hat
responseData Objekt
isReady Boolean Gibt an, ob alle Module den Status „Bereit“ haben, einschließlich Paketupload
ongoingSubmissionId String Übermittlungs-ID einer bereits laufenden Übermittlung

Beispiel für eine Antwort

{
    "isSuccess": true,
    "errors": [{
        "code": "badrequest",
        "message": "Error Message 1",
        "target": "listings"
        }, {
        "code": "warning",
        "message": "Warning Message 1",
        "target": "properties"
    }],
    "responseData": {
        "isReady": true,
        "ongoingSubmissionId": ""
    }
}

API zum Erstellen von Übermittlungen

Erstellt eine Übermittlung aus dem aktuellen Entwurf für MSI- oder EXE-App. Die API überprüft:

  • auf aktive Übermittlung und Fehler mit Fehlermeldung, es eine aktive Übermittlung gibt.
  • ob alle Module den Status „Bereit“ haben, um die Übermittlung zu erstellen.
  • Jedes Feld in der Übermittlung wird gemäß den Anforderungen des Store auf Gültigkeit geprüft.

Pfad:/submission/v1/product/{productId}/submit
Methode: POST

Pfadparameter

Name Beschreibung
productId Die Partner Center-ID des Produkts

Erforderliche Header

Header Beschreibung
Authorization: Bearer <Token> Verwenden der im Partner Center-Konto registrierten Azure AD-App-ID
X-Seller-Account-Id Verkäufer-ID des Partner Center-Kontos

Antwortheader

Header Beschreibung
X-Correlation-ID Die eindeutige GUID-Typ-ID für jede Anforderung. Sie kann zur Analyse von Problemen an das Supportteam weitergegeben werden.
Retry-After Die Zeit in Sekunden, die der Client aufgrund der Ratenbegrenzung warten muss, bevor er die APIs erneut aufruft.

Antwortparameter

Name Typ Beschreibung
IsSuccess Boolean
errors Array von Objekten Die Liste der eventuellen Fehler- oder Warnmeldungen
Code String Der Fehlercode der Meldung
message String Die Beschreibung des Fehlers
target String Die Entität, in der der Fehler seinen Ursprung hat
responseData Objekt
pollingUrl String Abruf-URL zum Abrufen des Status der Modulbereitschaft einschließlich Paketupload für Übermittlung
submissionId String Die ID für die neu erstellte Übermittlung
ongoingSubmissionId String Übermittlungs-ID einer bereits laufenden Übermittlung

Beispiel für eine Antwort

{
    "isSuccess": true,
    "errors": [{
        "code": "badrequest",
        "message": "Error Message 1",
        "target": "listings"
        }, {
        "code": "warning",
        "message": "Warning Message 1",
        "target": "properties"
    }],
    "responseData": {
        "submissionId": "1234567890", 
        "pollingUrl": "/submission/v1/product/{productId}/submission/{submissionId}/status",
        "ongoingSubmissionId": ""
    }
}

API zum Abrufen des Übermittlungsstatus

API zum Überprüfen des Übermittlungsstatus.

Pfad: /submission/v1/product/{productId}/submission/{submissionId}/status
Methode: GET

Pfadparameter

Name Beschreibung
productId Die Partner Center-ID des Produkts

Erforderliche Header

Header Beschreibung
Authorization: Bearer <Token> Verwenden der im Partner Center-Konto registrierten Azure AD-App-ID
X-Seller-Account-Id Verkäufer-ID des Partner Center-Kontos

Antwortheader

Header Beschreibung
X-Correlation-ID Die eindeutige GUID-Typ-ID für jede Anforderung. Sie kann zur Analyse von Problemen an das Supportteam weitergegeben werden.
Retry-After Die Zeit in Sekunden, die der Client aufgrund der Ratenbegrenzung warten muss, bevor er die APIs erneut aufruft.

Antwortparameter

Name Typ Beschreibung
IsSuccess Boolean
errors Array von Objekten Die Liste der eventuellen Fehler- oder Warnmeldungen
Code String Der Fehlercode der Meldung
message String Die Beschreibung des Fehlers
target String Die Entität, in der der Fehler seinen Ursprung hat
responseData Objekt
publishingStatus String Veröffentlichungsstatus der Übermittlung – [INPROGRESS, PUBLISHED, FAILED, UNKNOWN]
hasFailed Boolean Gibt an, ob die Veröffentlichung fehlgeschlagen ist und nicht wiederholt wird.

Beispiel für eine Antwort

{
    "isSuccess": true,
    "errors": [{
        "code": "badrequest",
        "message": "Error Message 1",
        "target": "listings"
        }, {
        "code": "warning",
        "message": "Warning Message 1",
        "target": "properties"
    }],
    "responseData": {
        "publishingStatus": "INPROGRESS",
        "hasFailed": false
    }
}

Codebeispiele

Die folgenden Artikel enthalten detaillierte Codebeispiele, die veranschaulichen, wie die Microsoft Store-Übermittlungs-API in verschiedenen Programmiersprachen verwendet wird:

Beispiel für C#: Microsoft Store-Übermittlungs-API für MSI- oder EXE-App

Dieser Artikel enthält C#-Codebeispiele, die die Verwendung der Microsoft Store-Übermittlungs-API für MSI- oder EXE-App veranschaulichen. Sie können jedes Beispiel durchgehen, um mehr über die beschriebene Aufgabe zu erfahren, oder Sie können alle Codebeispiele in diesem Artikel in einer Konsolenanwendung erstellen.

Voraussetzungen In diesen Beispielen wird die folgende Bibliothek verwendet:

  • Newtonsoft.Json NuGet-Paket von Newtonsoft.

Standardprogramm Das folgende Beispiel implementiert ein Befehlszeilenprogramm, das die anderen Beispielmethoden in diesem Artikel aufruft, um verschiedene Möglichkeiten zur Verwendung der Microsoft Store-Übermittlungs-API zu veranschaulichen. So passen Sie dieses Programm für eigene Zwecke an:

  • Weisen Sie die Eigenschaft SellerId der Verkäufer-ID Ihres Partner Center-Kontos zu.
  • Weisen Sie die Eigenschaft ApplicationId der ID der zu verwaltenden App zu.
  • Weisen Sie die Eigenschaften ClientId und ClientSecret der Client-ID und dem Schlüssel für Ihre App zu und ersetzen Sie die Zeichenkette „tenantid“ in der TokenEndpoint-URL durch die Mandanten-ID für Ihre App. Weitere Informationen finden Sie unter Zuordnen einer Azure AD-Anwendung zu Ihrem Partner Center-Konto.
using System;
using System.Threading.Tasks;

namespace Win32SubmissionApiCSharpSample
{
    public class Program
    {
        static async Task Main(string[] args)
        {
            var config = new ClientConfiguration()
            {
                ApplicationId = "...",
                ClientId = "...",
                ClientSecret = "...",
                Scope = "https://api.store.microsoft.com/.default",
                ServiceUrl = "https://api.store.microsoft.com",
                TokenEndpoint = "...",
                SellerId = 0
            };

            await new AppSubmissionUpdateSample(config).RunAppSubmissionUpdateSample();

        }
    }
}

Hilfsprogrammklasse ClientConfiguration bei Verwendung von C#

Die Beispiel-App verwendet die Hilfsprogrammklasse ClientConfiguration, um Azure Active Directory-Daten und App-Daten an jede der Beispielmethoden zu übergeben, die die Microsoft Store-Übermittlungs-API verwenden.

using System;
using System.Collections.Generic;
using System.Text;

namespace Win32SubmissionApiCSharpSample
{
    public class ClientConfiguration
    {
        /// <summary>
        /// Client Id of your Azure Active Directory app.
        /// Example" 00001111-aaaa-2222-bbbb-3333cccc4444
        /// </summary>
        public string ClientId { get; set; }

        /// <summary>
        /// Client secret of your Azure Active Directory app
        /// </summary>
        public string ClientSecret { get; set; }

        /// <summary>
        /// Service root endpoint.
        /// Example: "https://api.store.microsoft.com"
        /// </summary>
        public string ServiceUrl { get; set; }

        /// <summary>
        /// Token endpoint to which the request is to be made. Specific to your Azure Active Directory app
        /// Example: https://login.microsoftonline.com/d454d300-128e-2d81-334a-27d9b2baf002/oauth2/v2.0/token
        /// </summary>
        public string TokenEndpoint { get; set; }

        /// <summary>
        /// Resource scope. If not provided (set to null), default one is used for the production API
        /// endpoint ("https://api.store.microsoft.com/.default")
        /// </summary>
        public string Scope { get; set; }

        /// <summary>
        /// Partner Center Application ID.
        /// Example: 3e31a9f9-84e8-4d2d-9eba-487878d02ebf
        /// </summary>
        public string ApplicationId { get; set; }


        /// <summary>
        /// The Partner Center Seller Id
        /// Example: 123456892
        /// </summary>
        public int SellerId { get; set; }
    }
}

Erstellen einer App-Übermittlung bei Verwendung von C#

Das folgende Beispiel implementiert eine Klasse, die verschiedene Methoden in der Microsoft Store-Übermittlungs-API verwendet, um eine App-Übermittlung zu aktualisieren.

using Newtonsoft.Json.Linq;
using System;
using System.Collections.Generic;
using System.IO;
using System.Net.Http;
using System.Text;
using System.Threading.Tasks;

namespace Win32SubmissionApiCSharpSample
{
    public class AppSubmissionUpdateSample
    {
        private ClientConfiguration ClientConfig;

        /// <summary>
        /// Constructor
        /// </summary>
        /// <param name="configuration">An instance of ClientConfiguration that contains all parameters populated</param>
        public AppSubmissionUpdateSample(ClientConfiguration configuration)
        {
            this.ClientConfig = configuration;
        }

        /// <summary>
        /// Main method to Run the Sample Application
        /// </summary>
        /// <returns></returns>
        /// <exception cref="InvalidOperationException"></exception>
        public async Task RunAppSubmissionUpdateSample()
        {
            // **********************
            //       SETTINGS
            // **********************
            var appId = this.ClientConfig.ApplicationId;
            var clientId = this.ClientConfig.ClientId;
            var clientSecret = this.ClientConfig.ClientSecret;
            var serviceEndpoint = this.ClientConfig.ServiceUrl;
            var tokenEndpoint = this.ClientConfig.TokenEndpoint;
            var scope = this.ClientConfig.Scope;

            // Get authorization token.
            Console.WriteLine("Getting authorization token");
            var accessToken = await SubmissionClient.GetClientCredentialAccessToken(
                tokenEndpoint,
                clientId,
                clientSecret,
                scope);

            var client = new SubmissionClient(accessToken, serviceEndpoint);

            client.DefaultHeaders = new Dictionary<string, string>()
            {
                {"X-Seller-Account-Id", this.ClientConfig.SellerId.ToString() }
            };

            Console.WriteLine("Getting Current Application Draft Status");
            
            dynamic AppDraftStatus = await client.Invoke<dynamic>(HttpMethod.Get, string.Format(SubmissionClient.ProductDraftStatusPollingUrlTemplate,
                SubmissionClient.Version, appId), null);
            
            Console.WriteLine(AppDraftStatus.ToString());

            Console.WriteLine("Getting Application Packages ");

            dynamic PackagesResponse = await client.Invoke<dynamic>(HttpMethod.Get, string.Format(SubmissionClient.PackagesUrlTemplate,
                SubmissionClient.Version, appId), null);

            Console.WriteLine(PackagesResponse.ToString());

            Console.WriteLine("Getting Single Package");

            dynamic SinglePackageResponse = await client.Invoke<dynamic>(HttpMethod.Get, string.Format(SubmissionClient.PackageByIdUrlTemplate,
                SubmissionClient.Version, appId, (string)PackagesResponse.responseData.packages[0].packageId), null);

            Console.WriteLine(SinglePackageResponse.ToString());

            Console.WriteLine("Updating Entire Package Set");

            // Update data in Packages list to have final set of updated Packages

            // Example - Updating Installer Parameters
            PackagesResponse.responseData.packages[0].installerParameters = "/s /r new-args";

            dynamic PackagesUpdateRequest = new
            {
                packages = PackagesResponse.responseData.packages
            };

            dynamic PackagesUpdateResponse = await client.Invoke<dynamic>(HttpMethod.Put, string.Format(SubmissionClient.PackagesUrlTemplate,
                SubmissionClient.Version, appId), PackagesUpdateRequest);

            Console.WriteLine(PackagesUpdateResponse.ToString());

            Console.WriteLine("Updating Single Package's Download Url");

            // Update data in the SinglePackage object

            var SinglePackageUpdateRequest = SinglePackageResponse.responseData.packages[0];

            // Example - Updating Installer Parameters
            SinglePackageUpdateRequest.installerParameters = "/s /r /t new-args";

            dynamic PackageUpdateResponse = await client.Invoke<dynamic>(HttpMethod.Patch, string.Format(SubmissionClient.PackageByIdUrlTemplate,
                SubmissionClient.Version, appId, SinglePackageUpdateRequest.packageId), SinglePackageUpdateRequest);

            Console.WriteLine("Committing Packages");

            dynamic PackageCommitResponse = await client.Invoke<dynamic>(HttpMethod.Post, string.Format(SubmissionClient.PackagesCommitUrlTemplate,
                SubmissionClient.Version, appId), null);

            Console.WriteLine(PackageCommitResponse.ToString());

            Console.WriteLine("Polling Package Upload Status");

            AppDraftStatus = await client.Invoke<dynamic>(HttpMethod.Get, string.Format(SubmissionClient.ProductDraftStatusPollingUrlTemplate,
                SubmissionClient.Version, appId), null);

            while (!((bool)AppDraftStatus.responseData.isReady))
            {
                AppDraftStatus = await client.Invoke<dynamic>(HttpMethod.Get, string.Format(SubmissionClient.ProductDraftStatusPollingUrlTemplate,
                    SubmissionClient.Version, appId), null);

                Console.WriteLine("Waiting for Upload to finish");

                await Task.Delay(TimeSpan.FromSeconds(2));

                if(AppDraftStatus.errors != null && AppDraftStatus.errors.Count > 0)
                {
                    for(var index = 0; index < AppDraftStatus.errors.Count; index++)
                    {
                        if(AppDraftStatus.errors[index].code == "packageuploaderror")
                        {
                            throw new InvalidOperationException("Package Upload Failed. Please try committing packages again.");
                        }
                    }
                }
            }

            Console.WriteLine("Getting Application Metadata - All Modules");

            dynamic AppMetadata = await client.Invoke<dynamic>(HttpMethod.Get, string.Format(SubmissionClient.AppMetadataUrlTemplate,
                SubmissionClient.Version, appId), null);

            Console.WriteLine(AppMetadata.ToString());

            Console.WriteLine("Getting Application Metadata - Listings");

            dynamic AppListingsMetadata = await client.Invoke<dynamic>(HttpMethod.Get, string.Format(SubmissionClient.AppListingsFetchMetadataUrlTemplate,
                SubmissionClient.Version, appId), null);

            Console.WriteLine(AppListingsMetadata.ToString());

            Console.WriteLine("Updating Listings Metadata - Description");

            // Update Required Fields in Listings Metadata Object - Per Language. For eg. AppListingsMetadata.responseData.listings[0]

            // Example - Updating Description
            AppListingsMetadata.responseData.listings[0].description = "New Description Updated By C# Sample Code";

            dynamic ListingsUpdateRequest = new
            {
                listings = AppListingsMetadata.responseData.listings[0]
            };

            dynamic UpdateListingsMetadataResponse = await client.Invoke<dynamic>(HttpMethod.Put, string.Format(SubmissionClient.AppMetadataUrlTemplate,
                SubmissionClient.Version, appId), ListingsUpdateRequest);

            Console.WriteLine(UpdateListingsMetadataResponse.ToString());

            Console.WriteLine("Getting All Listings Assets");

            dynamic ListingAssets = await client.Invoke<dynamic>(HttpMethod.Get, string.Format(SubmissionClient.ListingAssetsUrlTemplate,
                SubmissionClient.Version, appId), null);

            Console.WriteLine(ListingAssets.ToString());

            Console.WriteLine("Creating Listing Assets for 1 Screenshot");

            
            dynamic AssetCreateRequest = new
            {
                language = ListingAssets.responseData.listingAssets[0].language,
                createAssetRequest = new Dictionary<string, int>()
                {
                    {"Screenshot", 1 },
                    {"Logo", 0 }
                }
            };

            dynamic AssetCreateResponse = await client.Invoke<dynamic>(HttpMethod.Post, string.Format(SubmissionClient.ListingAssetsCreateUrlTemplate,
               SubmissionClient.Version, appId), AssetCreateRequest);

            Console.WriteLine(AssetCreateResponse.ToString());

            Console.WriteLine("Uploading Listing Assets");

            // Path to PNG File to be Uploaded as Screenshot / Logo
            var PathToFile = "./Image.png";
            var AssetToUpload = File.OpenRead(PathToFile);

            await client.UploadAsset(AssetCreateResponse.responseData.listingAssets.screenshots[0].primaryAssetUploadUrl.Value as string, AssetToUpload);

            Console.WriteLine("Committing Listing Assets");

            dynamic AssetCommitRequest = new
            {
                listingAssets = new
                {
                    language = ListingAssets.responseData.listingAssets[0].language,
                    storeLogos = ListingAssets.responseData.listingAssets[0].storeLogos,
                    screenshots = JToken.FromObject(new List<dynamic>() { new
                {
                    id = AssetCreateResponse.responseData.listingAssets.screenshots[0].id.Value as string,
                    assetUrl = AssetCreateResponse.responseData.listingAssets.screenshots[0].primaryAssetUploadUrl.Value as string
                }
                }.ToArray())
                }
            };

            dynamic AssetCommitResponse = await client.Invoke<dynamic>(HttpMethod.Put, string.Format(SubmissionClient.ListingAssetsCommitUrlTemplate,
               SubmissionClient.Version, appId), AssetCommitRequest);

            Console.WriteLine(AssetCommitResponse.ToString());

            Console.WriteLine("Getting Current Application Draft Status before Submission");

            AppDraftStatus = await client.Invoke<dynamic>(HttpMethod.Get, string.Format(SubmissionClient.ProductDraftStatusPollingUrlTemplate,
                SubmissionClient.Version, appId), null);

            Console.WriteLine(AppDraftStatus.ToString());

            if (AppDraftStatus == null || !((bool)AppDraftStatus.responseData.isReady))
            {
                throw new InvalidOperationException("Application Current Status is not in Ready Status for All Modules");
            }

            Console.WriteLine("Creating Submission");

            dynamic SubmissionCreationResponse = await client.Invoke<dynamic>(HttpMethod.Post, string.Format(SubmissionClient.CreateSubmissionUrlTemplate,
                SubmissionClient.Version, appId), null);

            Console.WriteLine(SubmissionCreationResponse.ToString());

            Console.WriteLine("Current Submission Status");

            dynamic SubmissionStatus = await client.Invoke<dynamic>(HttpMethod.Get, string.Format(SubmissionClient.SubmissionStatusPollingUrlTemplate,
                SubmissionClient.Version, appId, SubmissionCreationResponse.responseData.submissionId.Value as string), null);

            Console.Write(SubmissionStatus.ToString());

            // User can Poll on this API to know if Submission Status is INPROGRESS, PUBLISHED or FAILED.
            // This Process involves File Scanning, App Certification and Publishing and can take more than a day.
        }
    }
}

Hilfklasse IngestionClient bei Verwendung von C#

Die Hilfsprogrammklasse IngestionClient stellt Hilfsmethoden bereit, die von anderen Methoden in der Beispiel-App zum Ausführen der folgenden Aufgaben verwendet werden:

  • Abrufen eines Azure AD-Zugriffstokens, das zum Aufrufen von Methoden in der Microsoft Store-Übermittlungs-API verwendet werden kann. Nach dem Abruf eines Tokens können Sie es für einen Zeitraum von 60 Minuten in Aufrufen der Microsoft Store-Übermittlungs-API verwenden, bevor es abläuft. Nach Ablauf des Tokens können Sie ein neues Token generieren.
  • Verarbeiten der HTTP-Anforderungen für die Microsoft Store-Übermittlungs-API.
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using System;
using System.Collections.Generic;
using System.IO;
using System.Net.Http;
using System.Net.Http.Headers;
using System.Text;
using System.Threading.Tasks;

namespace Win32SubmissionApiCSharpSample
{
    /// <summary>
    /// This class is a proxy that abstracts the functionality of the API service
    /// </summary>
    public class SubmissionClient : IDisposable
    {
        public static readonly string Version = "1";
        private HttpClient httpClient;
        private HttpClient imageUploadClient;

        private readonly string accessToken;

        public static readonly string PackagesUrlTemplate = "/submission/v{0}/product/{1}/packages";
        public static readonly string PackageByIdUrlTemplate = "/submission/v{0}/product/{1}/packages/{2}";
        public static readonly string PackagesCommitUrlTemplate = "/submission/v{0}/product/{1}/packages/commit";
        public static readonly string AppMetadataUrlTemplate = "/submission/v{0}/product/{1}/metadata";
        public static readonly string AppListingsFetchMetadataUrlTemplate = "/submission/v{0}/product/{1}/metadata/listings";
        public static readonly string ListingAssetsUrlTemplate = "/submission/v{0}/product/{1}/listings/assets";
        public static readonly string ListingAssetsCreateUrlTemplate = "/submission/v{0}/product/{1}/listings/assets/create";
        public static readonly string ListingAssetsCommitUrlTemplate = "/submission/v{0}/product/{1}/listings/assets/commit";
        public static readonly string ProductDraftStatusPollingUrlTemplate = "/submission/v{0}/product/{1}/status";
        public static readonly string CreateSubmissionUrlTemplate = "/submission/v{0}/product/{1}/submit";
        public static readonly string SubmissionStatusPollingUrlTemplate = "/submission/v{0}/product/{1}/submission/{2}/status";

        public const string JsonContentType = "application/json";
        public const string PngContentType = "image/png";
        public const string BinaryStreamContentType = "application/octet-stream";

        /// <summary>
        /// Initializes a new instance of the <see cref="SubmissionClient" /> class.
        /// </summary>
        /// <param name="accessToken">
        /// The access token. This is JWT a token obtained from Azure Active Directory allowing the caller to invoke the API
        /// on behalf of a user
        /// </param>
        /// <param name="serviceUrl">The service URL.</param>
        public SubmissionClient(string accessToken, string serviceUrl)
        {
            if (string.IsNullOrEmpty(accessToken))
            {
                throw new ArgumentNullException("accessToken");
            }

            if (string.IsNullOrEmpty(serviceUrl))
            {
                throw new ArgumentNullException("serviceUrl");
            }

            this.accessToken = accessToken;
            this.httpClient = new HttpClient
            {
                BaseAddress = new Uri(serviceUrl)
            };
            this.imageUploadClient = new HttpClient();
            this.DefaultHeaders = new Dictionary<string, string>();
        }

        /// <summary>
        /// Gets or Sets the default headers.
        /// </summary>
        public Dictionary<string, string> DefaultHeaders { get; set; }

        /// <summary>
        /// Performs application-defined tasks associated with freeing, releasing, or resetting
        /// unmanaged resources.
        /// </summary>
        public void Dispose()
        {
            if (this.httpClient != null)
            {
                this.httpClient.Dispose();
                this.httpClient = null;
                GC.SuppressFinalize(this);
            }
        }

        /// <summary>
        /// Gets the authorization token for the provided client id, client secret, and the scope.
        /// This token is usually valid for 1 hour, so if your submission takes longer than that to complete,
        /// make sure to get a new one periodically.
        /// </summary>
        /// <param name="tokenEndpoint">Token endpoint to which the request is to be made. Specific to your
        /// Azure Active Directory app. Example: https://login.microsoftonline.com/d454d300-128e-2d81-334a-27d9b2baf002/oauth2/v2.0/token </param>
        /// <param name="clientId">Client Id of your Azure Active Directory app. Example" 00001111-aaaa-2222-bbbb-3333cccc4444</param>
        /// <param name="clientSecret">Client secret of your Azure Active Directory app</param>
        /// <param name="scope">Scope. If not provided, default one is used for the production API endpoint.</param>
        /// <returns>Autorization token. Prepend it with "Bearer: " and pass it in the request header as the
        /// value for "Authorization: " header.</returns>
        public static async Task<string> GetClientCredentialAccessToken(
            string tokenEndpoint,
            string clientId,
            string clientSecret,
            string scope = null)
        {
            if (scope == null)
            {
                scope = "https://api.store.microsoft.com/.default";
            }

            dynamic result;
            using (HttpClient client = new HttpClient())
            {
                string tokenUrl = tokenEndpoint;
                using (
                    HttpRequestMessage request = new HttpRequestMessage(
                        HttpMethod.Post,
                        tokenUrl))
                {
                    string strContent =
                        string.Format(
                            "grant_type=client_credentials&client_id={0}&client_secret={1}&scope={2}",
                            clientId,
                            clientSecret,
                            scope);

                    request.Content = new StringContent(strContent, Encoding.UTF8,
                        "application/x-www-form-urlencoded");

                    using (HttpResponseMessage response = await client.SendAsync(request))
                    {
                        string responseContent = await response.Content.ReadAsStringAsync();
                        result = JsonConvert.DeserializeObject(responseContent);
                    }
                }
            }

            return result.access_token;
        }


        /// <summary>
        /// Invokes the specified HTTP method.
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="httpMethod">The HTTP method.</param>
        /// <param name="relativeUrl">The relative URL.</param>
        /// <param name="requestContent">Content of the request.</param>
        /// <returns>instance of the type T</returns>
        /// <exception cref="ServiceException"></exception>
        public async Task<T> Invoke<T>(HttpMethod httpMethod,
            string relativeUrl,
            object requestContent)
        {
            using (var request = new HttpRequestMessage(httpMethod, relativeUrl))
            {
                this.SetRequest(request, requestContent);

                using (HttpResponseMessage response = await this.httpClient.SendAsync(request))
                {
                    T result;
                    if (this.TryHandleResponse(response, out result))
                    {
                        return result;
                    }

                    if (response.IsSuccessStatusCode)
                    {
                        var resource = JsonConvert.DeserializeObject<T>(await response.Content.ReadAsStringAsync());
                        return resource;
                    }

                    throw new Exception(await response.Content.ReadAsStringAsync());
                }
            }
        }

        /// <summary>
        /// Uploads a given Image Asset file to Asset Storage
        /// </summary>
        /// <param name="assetUploadUrl">Asset Storage Url</param>
        /// <param name="fileStream">The Stream instance of file to be uploaded</param>
        /// <returns></returns>
        /// <exception cref="Exception"></exception>
        public async Task UploadAsset(string assetUploadUrl, Stream fileStream)
        {
            using (var request = new HttpRequestMessage(HttpMethod.Put, assetUploadUrl))
            {
                request.Headers.Add("x-ms-blob-type", "BlockBlob");
                request.Content = new StreamContent(fileStream);
                request.Content.Headers.ContentType = new MediaTypeHeaderValue(PngContentType);
                using (HttpResponseMessage response = await this.imageUploadClient.SendAsync(request))
                {
                    if (response.IsSuccessStatusCode)
                    {
                        return;
                    }
                    throw new Exception(await response.Content.ReadAsStringAsync());
                }
            }
        }

        /// <summary>
        /// Sets the request.
        /// </summary>
        /// <param name="request">The request.</param>
        /// <param name="requestContent">Content of the request.</param>
        protected virtual void SetRequest(HttpRequestMessage request, object requestContent)
        {
            request.Headers.Authorization = new AuthenticationHeaderValue("Bearer", this.accessToken);

            foreach (var header in this.DefaultHeaders)
            {
                request.Headers.Add(header.Key, header.Value);
            }

            if (requestContent != null)
            {
                request.Content = new StringContent(JsonConvert.SerializeObject(requestContent),
                        Encoding.UTF8,
                        JsonContentType);
                
            }
        }


        /// <summary>
        /// Tries the handle response.
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="response">The response.</param>
        /// <param name="result">The result.</param>
        /// <returns>true if the response was handled</returns>
        protected virtual bool TryHandleResponse<T>(HttpResponseMessage response, out T result)
        {
            result = default(T);
            return false;
        }
    }
}

Beispiel für Node.js: Microsoft Store-Übermittlungs-API für MSI- oder EXE-App

Dieser Artikel enthält Node.js-Codebeispiele zeigt das Verwenden der Microsoft Store-Übermittlungs-API für MSI- oder EXE-App. Sie können jedes Beispiel durchgehen, um mehr über die beschriebene Aufgabe zu erfahren, oder Sie können alle Codebeispiele in diesem Artikel in einer Konsolenanwendung erstellen.

Voraussetzungen In diesen Beispielen wird die folgende Bibliothek verwendet:

  • node-fetch v2 [npm install node-fetch@2]

Erstellen einer App-Übermittlung bei Verwendung von node.js

Das folgende Beispiel ruft die anderen Beispielmethoden in diesem Artikel auf, um verschiedene Möglichkeiten zur Verwendung der Microsoft Store-Übermittlungs-API zu veranschaulichen. So passen Sie dieses Programm für eigene Zwecke an:

  • Weisen Sie die Eigenschaft SellerId der Verkäufer-ID Ihres Partner Center-Kontos zu.
  • Weisen Sie die Eigenschaft ApplicationId der ID der zu verwaltenden App zu.
  • Weisen Sie die Eigenschaften ClientId und ClientSecret der Client-ID und dem Schlüssel für Ihre App zu und ersetzen Sie die Zeichenkette „tenantid“ in der TokenEndpoint-URL durch die Mandanten-ID für Ihre App. Weitere Informationen finden Sie unter Zuordnen einer Azure AD-Anwendung zu Ihrem Partner Center-Konto.

Das folgende Beispiel implementiert eine Klasse, die verschiedene Methoden in der Microsoft Store-Übermittlungs-API verwendet, um eine App-Übermittlung zu aktualisieren.

const config = require('./Configuration');
const submissionClient = require('./SubmissionClient');
const fs = require('fs');

var client = new submissionClient(config);

/**
 * Main entry method to Run the Store Submission API Node.js Sample
 */
async function RunNodeJsSample(){
    print('Getting Access Token');
    await client.getAccessToken();
    
    print('Getting Current Application Draft Status');
    var currentDraftStatus = await client.callStoreAPI(client.productDraftStatusPollingUrlTemplate, 'get');
    print(currentDraftStatus);

    print('Getting Application Packages');
    var currentPackages = await client.callStoreAPI(client.packagesUrlTemplate, 'get');
    print(currentPackages);

    print('Getting Single Package');
    var packageId = currentPackages.responseData.packages[0].packageId;
    var packageIdUrl = `${client.packageByIdUrlTemplate}`.replace('{packageId}', packageId);
    var singlePackage = await client.callStoreAPI(packageIdUrl, 'get');
    print(singlePackage);

    print('Updating Entire Package Set');
    // Update data in Packages list to have final set of updated Packages
    currentPackages.responseData.packages[0].installerParameters = "/s /r new-args";
    var packagesUpdateRequest = {
        'packages': currentPackages.responseData.packages
    };
    print(packagesUpdateRequest);
    var packagesUpdateResponse = await client.callStoreAPI(client.packagesUrlTemplate, 'put', packagesUpdateRequest);
    print(packagesUpdateResponse);

    print('Updating Single Package\'s Download Url');
    // Update data in the SinglePackage object
    singlePackage.responseData.packages[0].installerParameters = "/s /r /t new-args";
    var singlePackageUpdateResponse = await client.callStoreAPI(packageIdUrl, 'patch', singlePackage.responseData.packages[0]);
    print(singlePackageUpdateResponse);

    print('Committing Packages');
    var commitPackagesResponse = await client.callStoreAPI(client.packagesCommitUrlTemplate, 'post');
    print(commitPackagesResponse);

    await poll(async ()=>{
        print('Waiting for Upload to finish');
        return await client.callStoreAPI(client.productDraftStatusPollingUrlTemplate, 'get');
    }, 2);

    print('Getting Application Metadata - All Modules');
    var appMetadata = await client.callStoreAPI(client.appMetadataUrlTemplate, 'get');
    print(appMetadata);

    print('Getting Application Metadata - Listings');
    var appListingMetadata = await client.callStoreAPI(client.appListingsFetchMetadataUrlTemplate, 'get');
    print(appListingMetadata);

    print('Updating Listings Metadata - Description');   
    // Update Required Fields in Listings Metadata Object - Per Language. For eg. AppListingsMetadata.responseData.listings[0]
    // Example - Updating Description
    appListingMetadata.responseData.listings[0].description = 'New Description Updated By Node.js Sample Code';
    var listingsUpdateRequest = {
        'listings': appListingMetadata.responseData.listings[0]
    };
    var listingsMetadataUpdateResponse = await client.callStoreAPI(client.appMetadataUrlTemplate, 'put', listingsUpdateRequest);
    print(listingsMetadataUpdateResponse);

    print('Getting All Listings Assets');
    var listingAssets = await client.callStoreAPI(client.listingAssetsUrlTemplate, 'get');
    print(listingAssets);

    print('Creating Listing Assets for 1 Screenshot');
    var listingAssetCreateRequest = {
        'language': listingAssets.responseData.listingAssets[0].language,
        'createAssetRequest': {
            'Screenshot': 1,
            'Logo': 0
        }
    };
    var listingAssetCreateResponse = await client.callStoreAPI(client.listingAssetsCreateUrlTemplate, 'post', listingAssetCreateRequest);
    print(listingAssetCreateResponse);

    print('Uploading Listing Assets');
    const pathToFile = './Image.png';
    const stats = fs.statSync(pathToFile);
    const fileSize = stats.size;
    const fileStream = fs.createReadStream(pathToFile);
    await client.uploadAssets(listingAssetCreateResponse.responseData.listingAssets.screenshots[0].primaryAssetUploadUrl, fileStream, fileSize);

    print('Committing Listing Assets');
    var assetCommitRequest = {
        'listingAssets': {
            'language': listingAssets.responseData.listingAssets[0].language,
            'storeLogos': listingAssets.responseData.listingAssets[0].storeLogos,
            'screenshots': [{
                'id': listingAssetCreateResponse.responseData.listingAssets.screenshots[0].id,
                'assetUrl': listingAssetCreateResponse.responseData.listingAssets.screenshots[0].primaryAssetUploadUrl
            }]
        }
    };
    var assetCommitResponse = await client.callStoreAPI(client.listingAssetsCommitUrlTemplate, 'put', assetCommitRequest);
    print(assetCommitResponse);

    print('Getting Current Application Draft Status before Submission');
    currentDraftStatus = await client.callStoreAPI(client.productDraftStatusPollingUrlTemplate, 'get');
    print(currentDraftStatus);
    if(!currentDraftStatus.responseData.isReady){
        throw new Error('Application Current Status is not in Ready Status for All Modules');
    }

    print('Creating Submission');
    var submissionCreationResponse = await client.callStoreAPI(client.createSubmissionUrlTemplate, 'post');
    print(submissionCreationResponse);

    print('Current Submission Status');
    var submissionStatusUrl = `${client.submissionStatusPollingUrlTemplate}`.replace('{submissionId}', submissionCreationResponse.responseData.submissionId);
    var submissionStatusResponse = await client.callStoreAPI(submissionStatusUrl, 'get');
    print(submissionStatusResponse);

    // User can Poll on this API to know if Submission Status is INPROGRESS, PUBLISHED or FAILED.
    // This Process involves File Scanning, App Certification and Publishing and can take more than a day.
}

/**
 * Utility Method to Poll using a given function and time interval in seconds
 * @param {*} func 
 * @param {*} intervalInSeconds 
 * @returns 
 */
async function poll(func, intervalInSeconds){
var result = await func();
if(result.responseData.isReady){
    Promise.resolve(true);
}
else if(result.errors && result.errors.length > 0 && result.errors.find(element => element.code == 'packageuploaderror') != undefined){
throw new Error('Package Upload Failed');
}
else{
    await new Promise(resolve => setTimeout(resolve, intervalInSeconds*1000));
    return await poll(func, intervalInSeconds); 
}
}

/**
 * Utility function to Print a Json or normal string
 * @param {*} json 
 */
function print(json){
    if(typeof(json) == 'string'){
        console.log(json);
    }
    else{
        console.log(JSON.stringify(json));
    }
    console.log("\n");
}

/** Run the Node.js Sample Application */
RunNodeJsSample();

Hilfsprogramm ClientConfiguration

Die Beispiel-App verwendet die Hilfsprogrammklasse ClientConfiguration, um Azure Active Directory-Daten und App-Daten an jede der Beispielmethoden zu übergeben, die die Microsoft Store-Übermittlungs-API verwenden.

/** Configuration Object for Store Submission API */
var config = {
    version : "1",
    applicationId : "...",
    clientId : "...",
    clientSecret : "...",
    serviceEndpoint : "https://api.store.microsoft.com",
    tokenEndpoint : "...",
    scope : "https://api.store.microsoft.com/.default",
    sellerId : "...",
    jsonContentType : "application/json",
    pngContentType : "image/png",
    binaryStreamContentType : "application/octet-stream"
};

module.exports = config;

Hilfsprogramm IngestionClient bei Verwendung von node.js

Die Hilfsprogrammklasse IngestionClient stellt Hilfsmethoden bereit, die von anderen Methoden in der Beispiel-App zum Ausführen der folgenden Aufgaben verwendet werden:

  • Abrufen eines Azure AD-Zugriffstokens, das zum Aufrufen von Methoden in der Microsoft Store-Übermittlungs-API verwendet werden kann. Nach dem Abruf eines Tokens können Sie es für einen Zeitraum von 60 Minuten in Aufrufen der Microsoft Store-Übermittlungs-API verwenden, bevor es abläuft. Nach Ablauf des Tokens können Sie ein neues Token generieren.
  • Verarbeiten der HTTP-Anforderungen für die Microsoft Store-Übermittlungs-API.
const fetch = require('node-fetch');
/**
 * Submission Client to invoke all available Store Submission API and Asset Upload to Blob Store
 */
class SubmissionClient{

    constructor(config){
        this.configuration = config;
        this.accessToken = "";
        this.packagesUrlTemplate = `/submission/v${this.configuration.version}/product/${this.configuration.applicationId}/packages`;
        this.packageByIdUrlTemplate = `/submission/v${this.configuration.version}/product/${this.configuration.applicationId}/packages/{packageId}`;
        this.packagesCommitUrlTemplate = `/submission/v${this.configuration.version}/product/${this.configuration.applicationId}/packages/commit`;
        this.appMetadataUrlTemplate = `/submission/v${this.configuration.version}/product/${this.configuration.applicationId}/metadata`;
        this.appListingsFetchMetadataUrlTemplate = `/submission/v${this.configuration.version}/product/${this.configuration.applicationId}/metadata/listings`;
        this.listingAssetsUrlTemplate = `/submission/v${this.configuration.version}/product/${this.configuration.applicationId}/listings/assets`;
        this.listingAssetsCreateUrlTemplate = `/submission/v${this.configuration.version}/product/${this.configuration.applicationId}/listings/assets/create`;
        this.listingAssetsCommitUrlTemplate = `/submission/v${this.configuration.version}/product/${this.configuration.applicationId}/listings/assets/commit`;
        this.productDraftStatusPollingUrlTemplate = `/submission/v${this.configuration.version}/product/${this.configuration.applicationId}/status`;
        this.createSubmissionUrlTemplate = `/submission/v${this.configuration.version}/product/${this.configuration.applicationId}/submit`;
        this.submissionStatusPollingUrlTemplate = `/submission/v${this.configuration.version}/product/${this.configuration.applicationId}/submission/{submissionId}/status`;
    }
    
    async getAccessToken(){
        var params = new URLSearchParams();
        params.append('grant_type','client_credentials');
        params.append('client_id',this.configuration.clientId);
        params.append('client_secret',this.configuration.clientSecret);
        params.append('scope',this.configuration.scope);
        var response = await fetch(this.configuration.tokenEndpoint,{
            method: "POST",
            body: params
        });    
        var data = await response.json();
        this.accessToken = data.access_token;
    }

    async callStoreAPI(url, method, data){
        var request = {
            method: method,
            headers:{
                'Authorization': `Bearer ${this.accessToken}`,
                'Content-Type': this.configuration.jsonContentType,
                'X-Seller-Account-Id': this.configuration.sellerId
            },            
        };
        if(data){
            request.body = JSON.stringify(data);
        }
        var response = await fetch(`${this.configuration.serviceEndpoint}${url}`,request);
        var jsonResponse = await response.json();
        return jsonResponse;
    }

    async uploadAssets(url, stream, size){
        var request = {
            method: 'put',
            headers:{
                'Content-Type': this.configuration.pngContentType,
                'x-ms-blob-type': 'BlockBlob',
                "Content-length": size
            },            
            body: stream
        };
        var response = await fetch(`${url}`,request);
        if(response.ok){
            return response;
        }
        else{
            throw new Error('Uploading of assets failed');
        }
    }
}
module.exports = SubmissionClient;

Weitere Hilfe

Wenn Sie Fragen zur Microsoft Store-Übermittlungs-API haben oder Unterstützung beim Verwalten Ihrer Übermittlungen mit dieser API benötigen, können Sie die folgenden Ressourcen verwenden:

  • Stellen Sie Fragen in unseren Foren.
  • Besuchen Sie unsere Supportseite und fordern Sie eine der unterstützten Supportoptionen für Partner Center an. Wenn Sie aufgefordert werden, einen Problemtyp und eine Kategorie auszuwählen, wählen Sie „App-Übermittlung und -Zertifizierung“ bzw. „Übermitteln einer App“ aus.