API de soumission au Microsoft Store pour application MSI ou EXE

Utilisez l’API de soumission du Microsoft Store pour les applications MSI ou EXE afin d’interroger et de créer des soumissions par programmation pour votre compte Partner Center ou celui de votre organisation. Cette API est utile si votre compte gère de nombreuses applications et que vous souhaitez automatiser et optimiser le processus de soumission de ces actifs. Cette API utilise l’ID Microsoft Entra pour authentifier les appels à partir de votre application ou service.

Les étapes suivantes décrivent le processus de bout en bout de l’utilisation de l’API de soumission du Microsoft Store :

  1. Assurez-vous d'avoir rempli tous les prérequis.
  2. Avant d’appeler une méthode dans l’API de soumission au Microsoft Store, obtenez un jeton d’accès d’ID Microsoft Entra. Une fois le jeton obtenu, vous avez 60 minutes pour l’utiliser dans les appels à l’API de soumission au Microsoft Store avant expiration. Une fois le jeton arrivé à expiration, vous pouvez en générer un autre.
  3. Appelez l'API de soumission au Microsoft Store pour l'application MSI ou EXE.

Étape 1 : prérequis complets pour l’utilisation de l’API de soumission au Microsoft Store

Avant de commencer à écrire du code pour appeler l'API de soumission au Microsoft Store pour les applications MSI ou EXE, assurez-vous d'avoir rempli les conditions préalables suivantes.

  • Vous (ou votre organisation) devez disposer d’un répertoire d’ID Microsoft Entra et vous devez disposer de l’autorisation d’administrateur général pour l’annuaire. Si vous utilisez déjà Microsoft 365 ou d’autres services professionnels de Microsoft, vous disposez déjà de l’annuaire Microsoft Entra ID. Sinon, vous pouvez créer un NOUVEL ID Microsoft Entra dans l’Espace partenaires sans frais supplémentaires.
  • Vous devez associer une application Microsoft Entra ID à votre compte Espace partenaires et obtenir votre ID de locataire, votre ID client et votre clé. Vous avez besoin de ces valeurs pour obtenir un jeton d’accès Microsoft Entra ID, que vous utiliserez dans les appels à l’API de soumission du Microsoft Store.
  • Préparez votre application à utiliser avec l’API de soumission au Microsoft Store :
    • Si votre application n’existe pas encore dans l’Espace partenaires, vous devez créer votre application en réservant son nom dans l’Espace partenaires. Vous ne pouvez pas utiliser l’API de soumission au Microsoft Store pour créer une application dans l’Espace partenaires ; vous devez travailler dans l’Espace partenaires pour le créer, puis après cela, vous pouvez utiliser l’API pour accéder à l’application et créer par programmation des soumissions pour celle-ci.
    • Avant de pouvoir créer une soumission pour une application donnée à l’aide de cette API, vous devez d’abord créer une soumission pour l’application dans l’Espace partenaires, y compris répondre au questionnaire d’évaluation de l’âge. Une fois cette opération effectuée, vous pourrez créer par programmation de nouvelles soumissions pour cette application à l’aide de l’API.
    • Si vous créez ou mettez à jour une soumission d’application et que vous devez inclure un nouveau package, préparez les détails du package.
    • Si vous créez ou mettez à jour une soumission d’application et que vous devez inclure des captures d’écran ou des images pour la description du Windows Store, préparez les captures d’écran et les images de l’application.

Comment associer une application Microsoft Entra ID à votre compte Espace partenaires

Avant de pouvoir utiliser l’API de soumission du Microsoft Store pour l’application MSI ou EXE, vous devez associer une application Microsoft Entra ID à votre compte Espace partenaires, récupérer l’ID client et l’ID client de l’application et générer une clé. L’application Microsoft Entra ID représente l’application ou le service à partir duquel vous souhaitez appeler l’API de soumission du Microsoft Store. Vous avez besoin de l’ID de locataire, de l’ID client et de la clé pour obtenir un jeton d’accès Microsoft Entra ID que vous transmettez à l’API.

Remarque

Vous ne devez effectuer cette tâche qu’une seule fois. Une fois que vous avez l’ID de locataire, l’ID client et la clé, vous pouvez les réutiliser chaque fois que vous devez créer un jeton d’accès Microsoft Entra ID.

  1. Dans l’Espace partenaires, associez le compte espace partenaires de votre organisation à l’annuaire Microsoft Entra ID de votre organisation.
  2. Ensuite, dans la page Utilisateurs de la section Paramètres du compte de l’Espace partenaires, ajoutez l’application Microsoft Entra ID qui représente l’application ou le service que vous utiliserez pour accéder aux soumissions de votre compte Espace partenaires. Veillez à attribuer à cette application le rôle Gestionnaire. Si l’application n’existe pas encore dans votre répertoire d’ID Microsoft Entra, vous pouvez créer une application Microsoft Entra ID dans l’Espace partenaires.
  3. Revenez à la page Utilisateurs, cliquez sur le nom de votre application Microsoft Entra ID pour accéder aux paramètres de l’application, puis copiez l’ID de locataire et les valeurs d’ID client.
  4. Pour ajouter une nouvelle clé ou une clé secrète client, consultez les instructions suivantes ou reportez-vous aux instructions pour inscrire l’application via le portail Azure :

Pour inscrire votre application :

  1. Connectez-vous au portail Azure.

  2. Si vous avez accès à plusieurs locataires, utilisez le filtre Répertoires + abonnements dans le menu du haut pour basculer vers le locataire dans lequel vous voulez inscrire l’application.

  3. Recherchez et sélectionnez l’annuaire Microsoft Entra ID.

  4. Sous Gérer, sélectionnez Inscriptions d'applications > sélectionnez votre application.

  5. Sélectionnez Certificats et secrets > Clé secrète client > Nouvelle clé secrète client.

  6. Ajoutez une description pour votre secret client.

  7. Sélectionnez un délai d’expiration pour le secret ou spécifiez une durée de vie personnalisée.

  8. La durée de vie d’un secret client est limitée à deux ans (24 mois) ou moins. Vous ne pouvez pas spécifier une durée de vie personnalisée supérieure à 24 mois.

    Remarque

    Microsoft vous recommande de définir une valeur d’expiration inférieure à 12 mois.

  9. Sélectionnez Ajouter.

  10. Enregistrez la valeur du secret en prévision d’une utilisation dans le code de votre application cliente. Cette valeur secrète ne sera plus jamais affichée lorsque vous aurez quitté cette page.

Étape 2 : Obtenir un jeton d’accès Microsoft Entra ID

Avant d’appeler l’une des méthodes de l’API de soumission du Microsoft Store pour l’application MSI ou EXE, vous devez d’abord obtenir un jeton d’accès Microsoft Entra ID que vous passez à l’en-tête d’autorisation de chaque méthode dans l’API. Une fois que vous avez récupéré le jeton d’accès, vous avez 60 minutes pour l’utiliser avant qu’il n’expire. Après l'expiration du jeton, vous pouvez le rafraîchir afin de pouvoir continuer à l'utiliser lors d'autres appels à l'API.

Pour obtenir le jeton d’accès, suivez les instructions fournies dans Service to Service Calls Using Client Credentials to send an HTTP POST to the https://login.microsoftonline.com/<tenant_id>/oauth2/token endpoint. Voici un exemple de requête.

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

Pour la valeur tenant_id de l'URI POST et les paramètres client_id et client_secret, indiquez l'ID tenant, l'ID client et la clé de votre application que vous avez récupérée auprès de l’Espace partenaires dans la section précédente. Pour l’étendue du paramètre, vous devez spécifier https://api.store.microsoft.com/.default.

Une fois votre jeton d’accès expiré, vous pouvez l’actualiser en suivant les instructions fournies ici.

Pour obtenir des exemples illustrant comment obtenir un jeton d’accès à l’aide de C# ou Node.js, consultez les exemples de code pour l’API de soumission au Microsoft Store pour l’application MSI ou EXE.

Étape 3 : utiliser l’API de soumission au Microsoft Store

Une fois que vous avez un jeton d’accès Microsoft Entra ID, vous pouvez appeler des méthodes dans l’API de soumission du Microsoft Store pour l’application MSI ou EXE. L’API inclut de nombreuses méthodes regroupées dans des scénarios pour les applications. Pour créer ou mettre à jour des soumissions, vous appelez généralement plusieurs méthodes dans un ordre spécifique. Pour plus d'informations sur chaque scénario et la syntaxe de chaque méthode, reportez-vous aux sections suivantes :

Remarque

Après avoir obtenu un jeton d'accès, vous disposez de 60 minutes pour appeler les méthodes de l'API de soumission au Microsoft Store pour les applications MSI ou EXE avant que le jeton n'expire.

URL de base

L'URL de base de l'API de soumission au Microsoft Store pour les applications EXE ou MSI est : https://api.store.microsoft.com

Contrats API

Obtenir l’API de métadonnées de soumission brouillon actuelle

Récupère les métadonnées de chaque module (annonces, caractéristiques ou disponibilité) dans la soumission en brouillon actuelle.

Chemin d'accès [Tous les modules] : /submission/v1/product/{productId}/metadata?languages={languages}&includelanguagelist={true/false}
Chemin d'accès [Module unique] : /submission/v1/product/{productId}/metadata/{moduleName}?languages={languages}&includelanguagelist={true/false}
Méthode : GET

Paramètres de chemin d’accès

Paramètre Descriptif
ID de produit L’ID Partner Center du produit
Nom du module Module Espace partenaires : référencements, propriétés ou disponibilité

Paramètres de requête

Paramètre Descriptif
langues Facultatif Filtre des langues d’annonce sous forme de chaîne de caractères séparée par des virgules [limité à 200 langues maximum].

En l’absence, les 200 premières métadonnées de langues de référencement disponibles sont récupérées. [ par exemple, « en-us, en-gb »].
includelanguagelist Booléen facultatif : si la valeur est true, retourne la liste des langues de liste ajoutées et leur état d’exhaustivité.

En-têtes obligatoires

En-tête Valeur
Authorization: Bearer <Token> ID d’application Microsoft Entra ID inscrit auprès du compte Espace partenaires
X-Seller-Account-Id ID du vendeur du compte Partner Center

En-têtes de réponse

En-tête Valeur
X-Correlation-ID ID unique de type GUID pour chaque requête. Cela peut être partagé avec l’équipe de support technique pour analyser n’importe quel problème.
Retry-After Temps en secondes pendant lequel le client doit attendre avant d’appeler à nouveau les API en raison de la limitation de débit.

Paramètres de réponse

Nom Type Descriptif
accessibilitySupport Booléen
conditions supplémentaires de licence Chaîne
disponibilité Objet Données du module de disponibilité
catégorie Chaîne Voir la liste des catégories ci-dessous
notes de certification Chaîne
code Chaîne Le code d'erreur du message
informations de contact Chaîne
droit d'auteur Chaîne
dependsOnDriversOrNT Booléen
descriptif Chaîne
developedBy Chaîne
découvrabilité Chaîne [DISCOVERABLE, DEEPLINK_ONLY]
enableInFutureMarkets Booléen
erreurs Tableau d’objets Liste des messages d’erreur ou d’avertissement le cas échéant
freeTrial Chaîne [NO_FREE_TRIAL, FREE_TRIAL]
hardwareItemType Chaîne
La politique de confidentialité est-elle requise ? Booléen
isRecommended Booléen
isRequired Booléen
isSuccess Booléen
isSystemFeatureRequired Tableau d’objets
langue Chaîne Voir la liste des langues ci-dessous
listes Tableau d’objets Répertorie les données de module pour chaque langue
marchés Tableau de chaînes Voir la liste des marchés ci-dessous
message Chaîne La description de l'erreur
minimumHardware Chaîne
minimumRequirement Chaîne
penAndInkSupport Booléen
Prix Chaîne [GRATUIT, FREEMIUM, ABONNEMENT, PAYANT]
URL de la politique de confidentialité Chaîne
déclarations de produits Objet
caractéristiques du produit Tableau de chaînes
Propriétés Objet Données du module Propriétés
matériel recommandé Chaîne
exigence recommandée Chaîne
donnéesDeRéponse Objet Contient une charge utile de réponse réelle pour la requête
spécifications Tableau d’objets
termes de recherche Tableau de chaînes
brève description Chaîne
sous-catégorie Chaîne Voir la liste des sous-catégories ci-dessous
Informations de contact pour le support Chaîne
systemRequirementDetails Tableau d’objets
cible Chaîne L’entité d’où provient l’Erreur.
website Chaîne
Nouveautés Chaîne

Mettre à jour l’API des métadonnées de la soumission en brouillon actuelle

Mises à jour métadonnées dans chaque module sous soumission préliminaire. Les vérifications d’API

  • Pour la soumission active. S’il existe, échouez avec le message d'erreur.
  • Si tous les modules sont prêts à l’état pour autoriser l’opération Enregistrer le brouillon.
  • Chaque champ de la soumission est validé conformément aux exigences du Windows Store
  • Règles de validation des détails de la configuration système requise:
    • Valeurs autorisées dans hardwareItemType = Mémoire : 300 Mo, 750 Mo, 1 Go, 2 Go, 4 Go, 6 Go, 8 Go, 12 Go, 16 Go, 20 Go
    • Valeurs autorisées dans hardwareItemType = DirectX : DX9, DX10, DX11, DX12-FEATURELEVEL11, DX12-FEATURELEVEL12
    • Valeurs autorisées dans hardwareItemType = Video_Memory : 1 Go, 2 Go, 4 Go, 6 Go

Chemin d'accès [Mise à jour complète du module] : /submission/v1/product/{productId}/metadata
Méthode : PUT

Chemin d'accès [Mise à jour du correctif du module] : /submission/v1/product/{productId}/metadata
Méthode : PATCH

Comportement de l’API

Dans le cas de l’API De mise à jour complète du module, les données de module entières doivent être présentes dans la demande de mise à jour intégrale de chaque champ. Tout champ qui n’est pas présent dans la requête, sa valeur par défaut est utilisée pour remplacer la valeur actuelle pour ce module spécifique.
Dans le cas de l’API Patch Module Update, seuls les champs à mettre à jour doivent être présents dans la requête. Ces valeurs de champ de Requête remplacent leurs valeurs existantes, en conservant tous les autres champs qui ne sont pas présents dans la requête, identiques à ceux actuels pour ce module spécifique.

Paramètres de chemin d’accès

Paramètre Descriptif
ID de produit L’ID Partner Center du produit

En-têtes obligatoires

En-tête Valeur
Authorization: Bearer <Token> ID d’application Microsoft Entra ID inscrit auprès du compte Espace partenaires
X-Seller-Account-Id ID vendeur du compte Espace partenaires

Paramètres de la requête

Nom Type Descriptif
disponibilité Objet Objet pour contenir les métadonnées du module de disponibilité
marchés Tableau de chaînes Obligatoire Consultez la liste des marchés ci-dessous
découvrabilité Chaîne Obligatoire [DISCOVERABLE, DEEPLINK_ONLY]
enableInFutureMarkets Booléen Obligatoire
Prix Chaîne Obligatoire [GRATUIT, FREEMIUM, ABONNEMENT, PAYANT]
freeTrial Chaîne Obligatoire si la tarification est PAYANTE ou ABONNEMENT [NO_FREE_TRIAL, FREE_TRIAL]
Propriétés Objet Objet contenant les métadonnées du module de propriétés
isPrivacyPolicyRequired Booléen Obligatoire
URL de la politique de confidentialité Chaîne Obligatoire si isPrivacyPolicyRequired = true Doit être une URL valide
website Chaîne Doit être un URL valide
Informations de contact pour le support Chaîne Doit être une URL ou une adresse e-mail valide
notes de certification Chaîne Limite de caractères recommandée = 2 000
catégorie Chaîne Obligatoire Consultez la liste des catégories ci-dessous
sous-catégorie Chaîne Obligatoire Consultez la liste des sous-catégories ci-dessous
déclarations de produits Objet Obligatoire
isSystemFeatureRequired Tableau d’objets [Tactile, Clavier, Souris, Caméra, NFC_HCE, NFC_Proximity, Bluetooth_LE, Téléphonie, Microphone]
isRequired Booléen Obligatoire
isRecommended Booléen Obligatoire
hardwareItemType Chaîne Obligatoire
systemRequirementDetails Tableau d’objets [Processeur, Graphics, Mémoire, DirectX, Video_Memory]
minimumRequirement Chaîne Obligatoire pour systemRequirementsText, MaxLength = 200

Valeurs autorisées dans hardwareItemType = Mémoire : [300 Mo, 750 Mo, 1 Go, 2 Go, 4 Go, 6 Go, 8 Go, 12 Go, 16 Go, 20 Go]

Valeurs autorisées dans hardwareItemType = DirectX : [DX9, DX10, DX11, DX12-FEATURELEVEL11, DX12-FEATURELEVEL12]

Valeurs autorisées dans hardwareItemType = Video_Memory : [1 Go, 2 Go, 4 Go, 6 Go]
exigence recommandée Chaîne Obligatoire pour systemRequirementsText, MaxLength = 200

Valeurs autorisées dans hardwareItemType = Mémoire : [300 Mo, 750 Mo, 1 Go, 2 Go, 4 Go, 6 Go, 8 Go, 12 Go, 16 Go, 20 Go]

Valeurs autorisées dans hardwareItemType = DirectX : [DX9, DX10, DX11, DX12-FEATURELEVEL11, DX12-FEATURELEVEL12]

Valeurs autorisées dans hardwareItemType = Video_Memory : [1 Go, 2 Go, 4 Go, 6 Go]
dependsOnDriversOrNT Booléen Obligatoire
accessibilitySupport Booléen Obligatoire
penAndInkSupport Booléen Obligatoire
listes Objet Objet pour répertorier les données de module pour une seule langue
langue Chaîne Obligatoire Consultez la liste des langues ci-dessous
descriptif Chaîne Limite de caractères requise = 10 000
Nouveautés Chaîne Limite de caractères = 1 500
caractéristiques du produit Tableau de chaînes 200 caractères par fonctionnalité ; Jusqu’à 20 fonctionnalités
brève description Chaîne Limite de caractères = 1 000
termes de recherche Tableau de chaînes 30 caractères par critère de recherche ; Jusqu’à 7 critères de recherche

21 mots uniques au total dans tous les termes de recherche
conditions supplémentaires de licence Chaîne Limite de caractères requise = 10 000
droit d'auteur Chaîne Limite de caractères = 200
developedBy Chaîne Limite de caractères = 255
spécifications Tableau d’objets 200 caractères par élément ; Jusqu’à 11 éléments TOTAL entre minimum et recommandé]
minimumHardware Chaîne Limite de caractères = 200
matériel recommandé Chaîne Limite de caractères = 200
informations de contact Chaîne Limite de caractères = 200
listingsToAdd Tableau de chaînes Voir la liste des langues ci-dessous
listes à supprimer Tableau de chaînes Voir la liste des langues ci-dessous

Marchés

Afficher le tableau | Marché | Abréviation | |--------|--------------| | Afghanistan | AF | | Albanie | AL | | Algérie | DZ | | Samoa américaines | AS | | Andorre | AD | | Angola | AO | | Anguilla | AI | | Antarctique | AQ | | Antigua-et-Barbuda | AG | | Argentine | AR | | Arménie | AM | | Aruba | AW | | Australie | AU | | Autriche | AT | | Azerbaïdjan | AZ | | Bahamas | BS | | Bahreïn | BH | | Bangladesh | BD | | Barbade | BB | | Bélarus | BY | | Belgique | BE | | Belize | BZ | | Benin | BJ | | Bermudes | BM | | Bhoutan | BT | | République bolivarienne du Venezuela | VE | | Bolivie | BO | | Bonaire | BQ | | Bosnie-Herzégovine | BA | | Botswana | BW | | Île Bouvet | BV | | Brésil | BR | | Territoire britannique de l’Océan Indien | IO | | Îles Vierges britanniques | VG | | Brunéi | BN | | Bulgarie | BG | | Burkina Faso | BF | | Burundi | BI | | Cambodge | KH | | Cameroun | CM | | Canada | CA | | Cap-Vert | CV | | Îles Caïmans | KY | | République centrafricaine | CF | | Tchad | TD | | Chili | CL | | Chine | CN | | Île Christmas | CX | | Îles Cocos | CC | | Colombie | CO | | Comores | KM | | Congo | CG | | Congo (RDC) | CD | | Îles Cook | CK | | Costa Rica | CR | | Croatie | HR | | Curaçao | CW | | Chypre | CY | | République tchèque | CZ | | Côte d’Ivoire | CI | | Danemark | DK | | Djibouti | DJ | | Dominique | DM | | République dominicaine | DO | | Équateur | EC | | Égypte | EG | | Salvador | SV | | Guinée équatoriale | GQ | | Érythrée | ER | | Estonie | EE | | Éthiopie | ET | | Îles Malouines | FK | | Îles Féroé | FO | | Fidji | FJ | | Finlande | FI | | France | FR | | Guyane | GF | | Polynésie française | PF | | Terres australes et antarctiques françaises | TF | | Gabon | GA | | Gambie | GM | | Géorgie | GE | | Allemagne | DE | | Ghana | GH | | Gibraltar | GI | | Grèce | GR | | Groenland | GL | | Grenade | GD | | Guadeloupe | GP | | Guam | GU | | Guatemala | GT | | Guernesey | GG | | Guinée | GN | | Guinée-Bissau | GW | | Guyana | GY | | Haïti | HT | | Îles Heard-et-McDonald | HM | | État de la Cité du Vatican | VA | | Honduras | HN | | Hong Kong (R.A.S.) | HK | | Hongrie | HU | | Islande | IS | | Inde | IN | | Indonésie | ID | | Irak | IQ | | Irlande | IE | | Israël | IL | | Italie | IT | | Jamaïque | JM | | Japon | JP | | Jersey | JE | | Jordanie | JO | | Kazakhstan | KZ | | Kenya | KE | | Kiribati | KI | | Corée du Sud | KR | | Koweït | KW | | Kirghizistan | KG | | Laos | LA | | Lettonie | LV | | Liban | LB | | Lesotho | LS | | Liberia | LR | | Lybie | LY | | Liechtenstein | LI | | Lituanie | LT | | Luxembourg | LU | | Macao (R.A.S.) | MO | | Macédoine du Nord | MK | | Madagascar | MG | | Malawi | MW | | Malaisie | MY | | Maldives | MV | | Mali | ML | | Malte | MT | | Île de Man | IM | | Îles Marshall | MH | | Martinique | MQ | | Mauritanie | MR | | Maurice | MU | | Mayotte | YT | | Mexique | MX | | Micronésie | FM | | Moldova | MD | | Monaco | MC | | Mongolie | MN | | Monténégro - ME | | Montserrat | MS | | Maroc | MA | | Mozambique | MZ | | Myanmar | MM | | Namibie | NA | | Nauru | NR | | Népal | NP | | Pays-Bas | NL | | Nouvelle-Calédonie | NC | | Nouvelle-Zélande | NZ | | Nicaragua | NI | | Niger | NE | | Nigéria | NG | | Niue | NU | | Île Norfolk | NF | | Îles Mariannes du Nord | MP | | Norvège | NO | | Oman | OM | | Pakistan | PK | | Palau | PW | | Autorité palestinienne | PS | | Panama | PA | | Papouasie-Nouvelle-Guinée | PG | | Paraguay | PY | | Pérou | PE | | Philippines | PH | | Îles Pitcairn | PN | | Pologne | PL | | Portugal | PT | | Qatar | QA | | La réunion | RE | | Roumanie | RO | | Russie | RU | | Rwanda | RW | | Saint Barthélemy | BL | | Sainte-Hélène, Ascension et Tristan da Cunha | SH | | Saint-Kitts-et-Nevis | KN | | Sainte-Lucie | LC | | Saint-Martin (partie française) | MF | | Saint-Pierre-et-Miquelon | PM | | Saint-Vincent-et-les Grenadines | VC | | Samoa | WS | | Saint-Marin | SM | | Arabie saoudite | SA | | Sénégal | SN | | Serbie | RS | | Seychelles | SC | | Sierra Leone | SL | | Singapour | SG | | Saint-Martin (partie néerlandaise) | SX | | Slovaquie | SK | | Slovénie | SI | | Îles Salomon | SB | | Somalie | SO | | Afrique du Sud | ZA | | Géorgie du Sud et îles Sandwich du Sud | GS | | Espagne | ES | | Sri Lanka | LK | | Suriname | SR | | Svalbard et Jan Mayen | SJ | | Swaziland | SZ | | Suède | SE | | Suisse | CH | | Sao Tomé-et-Principe | ST | | Taïwan | TW | | Tadjikistan | TJ | | Tanzanie | TZ | | Thaïlande | TH | | Timor-Leste | TL | | Tog - TG | | Tokelau | TK | | Tonga | TO | | Trinité-et-Tobago - TT | | Tunisie | TN | | Turquie | TR | | Turkménistan | TM | | Îles Turques-et-Caïques | TC | | Tuvalu | TV | | Îles mineures éloignées des États-Unis | UM | | Îles Vierges des États-Unis | VI | | Ouganda | UG | | Ukraine | UA | | Émirats arabes unis | AE | | Royaume-Uni | GB | | États-Unis | US | | Uruguay | UY | | Ouzbékistan | UZ | | Vanuatu | VU | | Vietnam | VN | | Wallis et Futuna | WF | | Yémen | YE | | Zambie | ZM | | Zimbabwe | ZW | | Îles Åland | AX |

Catégories et sous-catégories

Afficher le tableau | Catégorie | Sous-catégories | |-----------------------|---------------| | BooksAndReference | EReader, Fiction, Non-fiction, Référence | | Professionnel | AccountingAndfinance, Collaboration, CRM, DataAndAnalytics, FileManagement, InventoryAndlogistics, LegalAndHR, ProjectManagement, RemoteDesktop, SalesAndMarketing, TimeAndExpenses | | DeveloperTools | Base de données, DesignTools, DevelopmentKits, Networking, ReferenceAndTraining, Serveurs, Services publics, WebHosting | Éducation | EducationBooksAndReference, EarlyLearning, InstructionalTools, Langue, StudyAids | | Divertissement | (Aucun) | | FoodAndDining | (Aucun) | | GovernmentAndPolitics | (Aucun) | | HealthAndFitness | (Aucun) | | KidsAndFamily | KidsAndFamilyBooksAndReference, KidsAndFamilyEntertainment, HobbiesAndToys, SportsAndActivities, KidsAndFamilyTravel | | Style de vie | Automobile, DYI, HomeAndGarden, Relations, SpecialInterest, StyleAndFashion | | Médical | (Aucun) | | MultimediaDesign | IllustrationAndGraphicDesign, MusicProduction, PhotoAndVideoProduction | | Musique | (Aucun) | | NavigationAndMaps | (Aucun) | | NewsAndWeather | Actualités et météo | | PersonalFinance | BankingAndInvestments, BudgetingAndTaxes | | Personnalisation | RingtonesAndSounds, thèmes, WallpaperAndLockScreens | | PhotoAndVideo | (Aucun) | | Productivité | (Aucun) | | Sécurité | PCProtection, PersonalSecurity | | Achats | (Aucun) | | Réseaux sociaux | (Aucun) | | Sports | (Aucun) | | Déplacements | CityGuides, Hôtels | | UtilitiesAndTools | BackupAndManage, FileManager |

Langues

Afficher le tableau | Nom de la langue | Codes de langue pris en charge | |---------------|--------------------------| | Afrikaans | af, af-za | | Albanais | sq, sq-al | | Amharique | am, am-et | | Arménien | hy, hy-am | | Assamais | as, as-in | | azéri | az-arab, az-arab-az, az-cyrl, az-cyrl-az, az-latn, az-latn-az | | Basque (basque) | eu, eu-es | | Biélorusse | be, be-by | | Bengali | bn, bn-bd, bn-in | | Bosniaque | bs, bs-cyrl, bs-cyrl-ba, bs-latn, bs-latn-ba | | Bulgare | bg, bg-bg | | Catalan | ca, ca-es, ca-es-valencia | | Cherokee | chr-cher, chr-cher-us, chr-latn | | Chinois (simplifié) | zh-Hans, zh-cn, zh-hans-cn, zh-sg, zh-hans-sg | | Chinois (traditionnel) | 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 | | Croate | hr, hr-hr, hr-ba | | Tchèque | cs, cs-cz | | Danois | da, da-dk | | Dari | prs, prs-af, prs-arab | | Néerlandais | nl, nl-nl, nl-be | | Anglais | 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 | | Estonien | et, et-ee | | Filipino | fil, fil-latn, fil-ph | | Finnois | fi, fi-fi | | Français | 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 | | Galicien | gl, gl-es | | Géorgien | ka, ka-ge | | Allemand | de, de-at, de-ch, de-de, de-lu, de-li | | Grec | el, el-gr | | Goudjarati | gu, gu-in | | Haoussa | ha, ha-latn, ha-latn-ng | | Hébreu | he, he-il | | Hindi | hi, hi-in | | Hongrois | hu, hu-hu | | Islandais | is, is-is | | Igbo | ig-latn, ig-ng | | Indonésien | id, id-id | | Inuktitut (latin) | iu-cans, iu-latn, iu-latn-ca | | Irlandais | ga, ga-ie | | Xhosa | xh, xh-za | | Zoulou | zu, zu-za | | Italien | it, it-it, it-ch | | Japonais | ja , ja-jp | | Kannada | kn, kn-in | | Kazakh | kk, kk-kz | | Khmer | km, km-kh | | K’iche’ | quc-latn, qut-gt, qut-latn | | Kinyarwanda | rw, rw-rw | | Swahili | sw, sw-ke | | Konkani | kok, kok-in | | Coréen | ko, ko-kr | | Kurde | ku-arab, ku-arab-iq | | Kirghize | ky-kg, ky-cyrl | | Lao | lo, lo-la | | Letton | lv, lv-lv | | Lituanien | lt, lt-lt | | Luxembourgeois | lb, lb-lu | | Macédonien | mk, mk-mk | | Malais | ms, ms-bn, ms-my | | Malayalam | ml, ml-in | | Maltais | mt, mt-mt | | Maori | mi, mi-latn, mi-nz | | Marathi | mr, mr-in | | Mongol (cyrillique) | mn-cyrl, mn-mong, mn-mn, mn-phag | | Népalais | ne, ne-np | | Norvégien | nb, nb-no, nn, nn-no, no, no-no | | Odia | or, or-in | | Persan | fa, fa-ir | | Polonais | pl, pl-pl | | Portugais (Brésil) | pt-br | | Portugais (Portugal) | pt, pt-pt | | Pendjabi | pa, pa-arab, pa-arab-pk, pa-deva, pa-in | | Quechua | quz, quz-bo, quz-ec, quz-pe | | Roumain | ro, ro-ro | | Russe | ru , ru-ru | | Gaélique écossais | gd-gb, gd-latn | | Serbe (latin) | sr-Latn, sr-latn-cs, sr, sr-latn-ba, sr-latn-me, sr-latn-rs | | Serbe (cyrillique) | sr-cyrl, sr-cyrl-ba, sr-cyrl-cs, sr-cyrl-me, sr-cyrl-rs | | Sotho du Nord | nso, nso-za | | Setswana | tn, tn-bw, tn-za | | Sindhi | sd-arab, sd-arab-pk, sd-deva | | Cingalais | si, si-lk | | Slovaque | sk, sk-sk | | Slovène | sl, sl-si | | Espagnol | 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 | | Suédois | sv, sv-se, sv-fi | | Tadjik (cyrillique) | tg-arab, tg-cyrl, tg-cyrl-tj, tg-latn | | Tamoul | ta, ta-in | | Tatar | tt-arab, tt-cyrl, tt-latn, tt-ru | | Télougou | te, te-in | | Thaï | th, th-th | | Tigrigna | ti, ti-et | | Turc | tr, tr-tr | | Turkmène | tk-cyrl, tk-latn, tk-tm, tk-latn-tr, tk-cyrl-tr | | Ukrainien | uk, uk-ua | | Ourdou | ur, ur-pk | | Ouïghour | ug-arab, ug-cn, ug-cyrl, ug-latn | | Ouzbek (latin) | uz, uz-cyrl, uz-latn, uz-latn-uz | | Vietnamien | vi, vi-vn | | Gallois | cy, cy-gb | | Wolof | wo, wo-sn | | Yoruba | yo-latn, yo-ng |

Exemple de demande

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

En-têtes de réponse

En-tête Valeur
X-Correlation-ID ID unique de type GUID pour chaque requête. Cela peut être partagé avec l’équipe de support technique pour analyser n’importe quel problème.
Retry-After Durée en secondes pendant laquelle le client doit attendre avant d’appeler à nouveau les API en raison de la limitation de débit

Paramètres de réponse

Nom Type Descriptif
isSuccess Booléen
erreurs Tableau d’objets Liste des messages d’erreur ou d’avertissement le cas échéant
code Chaîne Le code d'erreur du message
message Chaîne La description de l'erreur
cible Chaîne L’entité d’où provient l’Erreur.
donnéesDeRéponse Objet Contient une charge utile de réponse réelle pour la requête
URL de sondage Chaîne URL d’interrogation pour connaître le statut de toute soumission en cours
ongoingSubmissionId Chaîne Identifiant de toute soumission déjà en cours

Exemple de réponse

{
    "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 de récupération des paquets de brouillon actuels

Récupère les détails du package sous soumission préliminaire actuelle.

Chemin d'accès [Tous les packages] : /submission/v1/product/{productId}/packages
Méthode : GET

Chemin d’accès [Package unique] : /submission/v1/product/{productId}/packages/{packageId}
Méthode : GET

Paramètres de chemin d’accès

Nom Descriptif
ID de produit L’ID Partner Center du produit
packageId ID unique du package à récupérer

En-têtes obligatoires

En-tête Valeur
Authorization: Bearer <Token> Utilisation de l’identifiant d’application Microsoft Entra ID enregistré avec le compte Partner Center
X-Seller-Account-Id ID du vendeur du compte Partner Center

En-têtes de réponse

En-tête Valeur
X-Correlation-ID ID unique de type GUID pour chaque requête. Cela peut être partagé avec l’équipe de support technique pour analyser n’importe quel problème.
Retry-After Temps en secondes pendant lequel le client doit attendre avant d’appeler à nouveau les API en raison de la limitation de débit.

Paramètres de réponse

Nom Type Descriptif
isSuccess Booléen
erreurs Tableau d’objets Liste des erreurs ou messages d’avertissement le cas échéant
code Chaîne Le code d'erreur du message
message Chaîne La description de l'erreur
cible Chaîne L’entité d’où provient l’erreur.
donnéesDeRéponse Objet
Paquets Tableau d’objets Objet contenant les données du module de package
packageId Chaîne
URL du paquet Chaîne
langues Tableau de chaînes
architectures Tableau de chaînes [Neutre, X86, X64, Arm, Arm64]
isSilentInstall Booléen Cela doit être marqué comme vrai si votre programme d’installation s’exécute en mode silencieux sans nécessiter de commutateurs ou d’autres valeurs false
installerParameters Chaîne
genericDocUrl Chaîne
détails de l'erreur Tableau d’objets
errorScenario Chaîne
errorScenarioDetails Tableau d’objets
errorValue Chaîne
errorUrl Chaîne
type de paquet Chaîne

Exemple de réponse

{   
    "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 de mise à jour des paquets de brouillon actuels

Mises à jour détails du package sous la soumission préliminaire actuelle.

Chemin d'accès [Mise à jour complète du module] : /submission/v1/product/{productId}/packages
Méthode : PUT

Chemin [Mise à jour de correctif pour un seul paquet]: /submission/v1/product/{productId}/packages/{packageId}
Méthode : PATCH

Comportement de l’API

Dans le cas de l’API Full Module Update, les données complètes des packages doivent être présentes dans la demande de mise à jour intégrale de chaque champ. Tout champ qui n’est pas présent dans la requête, sa valeur par défaut est utilisée pour remplacer la valeur actuelle pour ce module spécifique. Cela entraîne le remplacement de tous les packages existants avec un nouvel ensemble de packages à partir de la requête. Cela entraîne la régénération des ID de package et l’utilisateur doit appeler l’API GET Packages pour les derniers ID de package.

Dans le cas de l’API Single Package Patch Update, seuls les champs à mettre à jour doivent être présents dans la requête. Ces valeurs de champ de la requête remplacent leurs valeurs existantes, en conservant tous les autres champs qui ne sont pas présents dans la requête, identiques à ceux actuels pour ce package spécifique. Les autres packages de l’ensemble restent tels qu’ils le sont.

Paramètres de chemin d’accès

Nom Descriptif
ID de produit ID du produit dans le Centre de partenaires
packageId ID unique du package

En-têtes obligatoires

En-tête Valeur
Authorization: Bearer <Token> Utilisation de l’identifiant d’application Microsoft Entra ID enregistré avec le compte Partner Center
X-Seller-Account-Id ID vendeur du compte Espace partenaires

Paramètres de la requête

Nom Type Descriptif
Paquets Tableau d’objets Objet pour contenir les données du module de package [Obligatoire uniquement pour la mise à jour intégrale du module]
URL du paquet Chaîne Obligatoire
langues Tableau de chaînes Obligatoire
architectures Tableau de chaînes Obligatoire doit contenir une architecture unique - Neutre, X86, X64, Arm, Arm64
isSilentInstall Booléen Obligatoire : cette propriété doit être marquée comme true si votre programme d’installation s’exécute en mode silencieux sans nécessiter de commutateurs ou d’autres valeurs false
installerParameters Chaîne Obligatoire si isSilentInstall a la valeur false
genericDocUrl Chaîne Obligatoire si packageType est exe Lien vers le document contenant les détails des codes d’erreur personnalisés pour le programme d’installation de type EXE
détails de l'erreur Tableau d’objets Métadonnées destinées à contenir des codes d’erreur personnalisés et des informations détaillées pour les programmes d’installation de type EXE.
errorScenario Chaîne Identifiez le scénario d’erreur spécifique. [installationCancelledByUser, applicationAlreadyExists, installationAlreadyInProgress, diskSpaceIsFull, rebootRequired, networkFailure, packageRejectedDuringInstallation, installationSuccessful, miscellaneous]
errorScenarioDetails Tableau d’objets
errorValue Chaîne Code d’erreur qui peut être présent pendant l’installation
errorUrl Chaîne URL pour obtenir des détails sur l’erreur
type de paquet Chaîne Obligatoire [exe, msi]

Exemple de requête [Mise à jour intégrale du module]

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

Exemple de requête [Mise à jour corrective d’un package unique]

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

En-têtes de réponse

En-tête Valeur
X-Correlation-ID ID unique de type GUID pour chaque requête. Cela peut être partagé avec l’équipe de support technique pour analyser n’importe quel problème.
Retry-After Temps en secondes pendant lequel le client doit attendre avant d’appeler à nouveau les API en raison de la limitation de débit.

Paramètres de réponse

Nom Type Descriptif
isSuccess Booléen
erreurs Tableau d’objets [Liste des messages d’erreur ou d’avertissement le cas échéant]
code Chaîne Le code d'erreur du message
message Chaîne La description de l'erreur
cible Chaîne L’entité d’où provient l’Erreur.
donnéesDeRéponse Objet
URL de sondage Chaîne URL d’interrogation pour obtenir l’état d’une soumission en cas de soumission déjà en cours
ongoingSubmissionId Chaîne [ID de toute soumission déjà en cours]

Exemple de réponse

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

Commit Packages API

Valide le nouvel ensemble de packages mis à jour à l’aide des API de mise à jour de package sous l’ébauche actuelle de soumission. Cette API retourne une URL d’interrogation pour suivre le chargement du package.

Chemin d'accès : /submission/v1/product/{productId}/packages/commit
Méthode : POST

Paramètres de chemin d’accès

Nom Descriptif
ID de produit L’ID de l’Espace partenaires du produit

En-têtes obligatoires

En-tête Valeur
Authorization: Bearer <Token> Utilisation de l’ID d’application Microsoft Entra ID inscrit auprès du compte Espace partenaires
X-Seller-Account-Id ID vendeur du compte Espace partenaires

En-têtes de réponse

En-tête Valeur
X-Correlation-ID L’identifiant unique de type GUID pour chaque requête. Cela peut être partagé avec l’équipe de support technique pour analyser n’importe quel problème.
Retry-After Temps en secondes pendant lequel le client doit attendre avant d’appeler à nouveau les API en raison de la limitation de débit.

Paramètres de réponse

Nom Type Descriptif
isSuccess Booléen
erreurs Tableau d’objets [Liste des messages d’erreur ou d’avertissement le cas échéant]
code Chaîne Le code d'erreur du message
message Chaîne La description de l'erreur
cible Chaîne L’entité d’où provient l’erreur.
donnéesDeRéponse Objet
URL de sondage Chaîne [URL d’interrogation pour obtenir l’état du chargement ou de l’état de soumission du package en cas de soumission en cours]
ongoingSubmissionId Chaîne [ID de la soumission déjà en cours]

Exemple de réponse

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

Obtenir l’API De référencement des ressources brouillons actuelles

Récupère les détails de la liste des éléments multimédias sous l’envoi brouillon actuel.

Chemin d'accès : /submission/v1/product/{productId}/listings/assets?languages={languages}
Méthode : GET

Paramètres de chemin d’accès

Nom Descriptif
ID de produit ID du produit dans le Centre de partenaires

Paramètres de requête

Nom Descriptif
langues [Facultatif] Le filtre des langues de l’annonce sous forme de chaîne de caractères séparée par des virgules [limite de 200 langues maximum]. En l’absence, les 200 premières données de ressources de la langue de référencement disponibles sont récupérées. (par exemple, « en-us, en-gb »)

En-têtes obligatoires

En-tête Valeur
Authorization: Bearer <Token> Utilisation de l’ID d’application Microsoft Entra ID inscrit auprès du compte Espace partenaires
X-Seller-Account-Id ID du vendeur du compte Partner Center

En-têtes de réponse

En-tête Valeur
X-Correlation-ID ID unique de type GUID pour chaque requête. Cela peut être partagé avec l’équipe de support technique pour analyser n’importe quel problème.
Retry-After Temps en secondes pendant lequel le client doit attendre avant d’appeler à nouveau les API en raison de la limitation de débit.

Paramètres de réponse

Nom Type Descriptif
isSuccess Booléen
erreurs Tableau d’objets Liste des messages d’erreur ou d’avertissement le cas échéant
code Chaîne Le code d'erreur du message
message Chaîne La description de l'erreur
cible Chaîne L’entité d’où provient l’erreur.
donnéesDeRéponse Objet
listingAssets Tableau d’objets Liste des détails de la ressource pour chaque langue
langue Chaîne
storeLogos Tableau d’objets
captures d'écran Tableau d’objets
id Chaîne
assetUrl Chaîne Doit être un URL valide
taille de l’image Objet
largeur Nombre entier
hauteur Nombre entier

Exemple de réponse

{   
"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 de création des ressources d’annonce

Crée un chargement de ressource de référencement sous soumission préliminaire actuelle.

Mise à jour de la liste des ressources

L’API de soumission au Microsoft Store pour les applications EXE ou MSI utilise des URL SAS générées au moment de l’exécution pour le chargement de chaque ressource d’image individuelle dans le stockage Blob, ainsi qu’un appel à l’API Commit une fois le chargement terminé avec succès. Pour avoir la possibilité de mettre à jour les ressources de référencement et, à son tour, de pouvoir ajouter/supprimer des paramètres régionaux dans le module de référencement, l’approche suivante peut être utilisée :

  1. Utilisez l’API Create Listing Asset pour envoyer une requête concernant le chargement de ressources, ainsi que la langue, le type et le nombre de ressources.
  2. En fonction du nombre de ressources demandées, des ID de ressource sont créés à la demande, puis une URL SAS à court terme est générée et renvoyée dans le corps de la réponse, sous le type de ressources. Vous pouvez utiliser cette URL pour charger des ressources d’image de type spécifique à l’aide de clients HTTP [Put Blob (API REST) - Stockage Azure | Microsoft Docs].
  3. Après le chargement, vous pouvez utiliser l’API Commit Listing Assets pour envoyer les nouvelles informations d’ID de ressource reçues précédemment à partir de l’appel d’API précédent. L’API unique valide en interne les données des ressources de liste après validation.
  4. Cette approche remplacera efficacement l’ensemble complet des images précédentes du type de ressource sous une langue spécifique qui est envoyée dans la requête. Par conséquent, les ressources précédemment chargées sont supprimées.

Chemin d'accès : /submission/v1/product/{productId}/listings/assets/create
Méthode : POST

Paramètres de chemin d’accès

Nom Descriptif
ID de produit L’ID Partner Center du produit

En-têtes obligatoires

En-tête Descriptif
Authorization: Bearer <Token> Utilisation de l’ID d’application Microsoft Entra ID inscrit auprès du compte Espace partenaires
X-Seller-Account-Id ID du vendeur du compte Partner Center

Paramètres de la requête

Nom Type Descriptif
langue Chaîne Obligatoire
createAssetRequest Objet Obligatoire
Capture d'écran Nombre entier Obligatoire si l’ISV doit mettre à jour des captures d’écran ou ajouter une nouvelle langue de la fiche [1 - 10]
Logo Nombre entier Obligatoire si l’ISV doit mettre à jour les logos ou ajouter une nouvelle langue pour la fiche [1 ou 2]

En-têtes de réponse

En-tête Descriptif
X-Correlation-ID ID unique de type GUID pour chaque requête. Cela peut être partagé avec l’équipe de support technique pour analyser n’importe quel problème.
Retry-After Temps en secondes pendant lequel le client doit attendre avant d’appeler à nouveau les API en raison de la limitation de débit.

Paramètres de réponse

Nom Type Descriptif
isSuccess Booléen
erreurs Tableau d’objets Liste des messages d’erreur ou d’avertissement le cas échéant
code Chaîne Le code d'erreur du message
message Chaîne La description de l'erreur
cible Chaîne L’entité d’où provient l’erreur.
donnéesDeRéponse Objet
listingAssets Objet Objet contenant les détails du StoreLogos et des captures d’écran à charger
langue Chaîne
storeLogos Tableau d’objets
captures d'écran Tableau d’objets
id Chaîne
primaryAssetUploadUrl Chaîne URL principale pour charger une ressource de référencement à l’aide de l’API REST Blob Azure
secondaryAssetUploadUrl Chaîne URL secondaire pour charger une ressource de référencement à l’aide de l’API REST Blob Azure
httpMethod Méthode HTTP La méthode HTTP doit être utilisée pour charger des ressources via les URL de chargement de ressources – principal ou secondaire
httpHeaders Objet Objet avec des clés en tant qu’en-têtes Obligatoires à présenter dans l’appel d’API de chargement vers les URL de chargement de ressources. Si la valeur n’est pas vide, les en-têtes doivent avoir des valeurs spécifiques. Sinon, les valeurs sont calculées pendant l’appel d’API.

Exemple de réponse

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

            }]
        }
    } 
}

Valider l’API Ressources de liste

Valide la nouvelle ressource de liste chargée à l’aide des détails de l’API Créer des ressources sous la soumission préliminaire actuelle.

Chemin d'accès : /submission/v1/product/{productId}/listings/assets/commit
Méthode : PUT

Paramètres de chemin d’accès

Nom Descriptif
ID de produit ID du produit dans le Centre de partenaires

En-têtes obligatoires

En-tête Descriptif
Authorization: Bearer <Token> Utilisation de l’ID d’application Microsoft Entra ID inscrit auprès du compte Espace partenaires
X-Seller-Account-Id ID vendeur du compte Espace partenaires

Paramètres de la requête

Nom Type Descriptif
listingAssets Objet
langue Chaîne
storeLogos Tableau d’objets
captures d'écran Tableau d’objets
id Chaîne Doit être un ID existant que l’utilisateur souhaite conserver à partir de l’API Obtenir les ressources de référencement actuelles ou un nouvel ID sous lequel une nouvelle ressource a été chargée dans l’API Créer des ressources de référencement.
assetUrl Chaîne Doit être l’URL de l’élément multimédia existant que l’utilisateur souhaite conserver à partir de l’API Obtenir les ressources de référencement actuelles ou l’URL de chargement (principal ou secondaire) à l’aide de laquelle un nouvel élément multimédia a été chargé dans l’API Créer des ressources de référencement. Doit être un URL valide

Exemple de demande

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

En-têtes de réponse

En-tête Descriptif
X-Correlation-ID L’identifiant unique de type GUID pour chaque requête. Cela peut être partagé avec l’équipe de support technique pour analyser n’importe quel problème.
Retry-After Temps en secondes pendant lequel le client doit attendre avant d’appeler à nouveau les API en raison de la limitation de débit.

Paramètres de réponse

Nom Type Descriptif
isSuccess Booléen
erreurs Tableau d’objets Liste des messages d’erreur ou d’avertissement le cas échéant
code Chaîne Le code d'erreur du message
message Chaîne La description de l'erreur
cible Chaîne L’entité d’où provient l’erreur.
donnéesDeRéponse Objet
URL de sondage Chaîne URL d’interrogation pour obtenir l’état d’une soumission en cours
ongoingSubmissionId Chaîne ID de soumission d’une soumission déjà en cours

Exemple de réponse

{
    "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 d’interrogation de l’état du module

Une API peut être créée pour vérifier l’état de préparation du module avant la soumission. Valide également l’état du chargement du package.

Chemin d'accès : /submission/v1/product/{productId}/status
Méthode : GET

Paramètres de chemin d’accès

Nom Descriptif
ID de produit L’identifiant Partner Center du produit

En-têtes obligatoires

En-tête Descriptif
Authorization: Bearer <Token> Utilisation de l’ID d’application Microsoft Entra ID inscrit auprès du compte Espace partenaires
X-Seller-Account-Id ID vendeur du compte Espace partenaires

En-têtes de réponse

En-tête Descriptif
X-Correlation-ID Identifiant unique de type GUID pour chaque requête. Cela peut être partagé avec l’équipe de support technique pour analyser n’importe quel problème.
Retry-After Temps en secondes pendant lequel le client doit attendre avant d’appeler à nouveau les API en raison de la limitation de débit.

Paramètres de réponse

Nom Type Descriptif
isSuccess Booléen
erreurs Tableau d’objets Liste des messages d’erreur ou d’avertissement le cas échéant
code Chaîne Le code d'erreur du message
message Chaîne La description de l'erreur
cible Chaîne L’entité d’où provient l’erreur.
donnéesDeRéponse Objet
isReady Booléen Indique si tous les modules sont à l’état prêt, y compris le chargement de package
ongoingSubmissionId Chaîne ID de soumission d’une soumission déjà en cours

Exemple de réponse

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

Créer une API de soumission

Crée une soumission à partir du brouillon actuel pour l’application MSI ou EXE. Les vérifications API :

  • vérifie s’il existe une soumission active et échoue en affichant un message d’erreur si c’est le cas.
  • si tous les modules sont à l’état « prêt » pour créer une soumission.
  • Chaque champ de la soumission est validé conformément aux exigences du Windows Store

Chemin d’accès :/submit/v1/product/{productId}/submit
Méthode : POST

Paramètres de chemin d’accès

Nom Descriptif
ID de produit L’ID de l’Espace partenaires du produit

En-têtes obligatoires

En-tête Descriptif
Authorization: Bearer <Token> Utilisation de l’ID d’application Microsoft Entra ID inscrit auprès du compte Espace partenaires
X-Seller-Account-Id ID du vendeur du compte Partner Center

En-têtes de réponse

En-tête Descriptif
X-Correlation-ID Identifiant unique de type GUID pour chaque requête. Cela peut être partagé avec l’équipe de support technique pour analyser n’importe quel problème.
Retry-After Temps en secondes pendant lequel le client doit attendre avant d’appeler à nouveau les API en raison de la limitation de débit.

Paramètres de réponse

Nom Type Descriptif
isSuccess Booléen
erreurs Tableau d’objets Liste des messages d’erreur ou d’avertissement le cas échéant
code Chaîne Le code d'erreur du message
message Chaîne La description de l'erreur
cible Chaîne L’entité d’où provient l’erreur.
donnéesDeRéponse Objet
URL de sondage Chaîne URL de requête pour obtenir l’état de préparation du module, y compris le téléversement du package en vue de la soumission
ID de soumission Chaîne ID de la soumission nouvellement créée
ongoingSubmissionId Chaîne ID de soumission d’une soumission déjà en cours

Exemple de réponse

{
    "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 d’interrogation de l’état de soumission

API pour vérifier le statut de soumission.

Chemin d’accès : /submission/v1/product/{productId}/submission/{submissionId}/status
Méthode : GET

Paramètres de chemin d’accès

Nom Descriptif
ID de produit L’identifiant du produit dans l’Espace partenaires

En-têtes obligatoires

En-tête Descriptif
Authorization: Bearer <Token> Utilisation de l’ID d’application Microsoft Entra ID inscrit auprès du compte Espace partenaires
X-Seller-Account-Id ID vendeur du compte Espace partenaires

En-têtes de réponse

En-tête Descriptif
X-Correlation-ID L’identifiant unique de type GUID pour chaque requête. Cela peut être partagé avec l’équipe de support technique pour analyser n’importe quel problème.
Retry-After Temps en secondes pendant lequel le client doit attendre avant d’appeler à nouveau les API en raison de la limitation de débit.

Paramètres de réponse

Nom Type Descriptif
isSuccess Booléen
erreurs Tableau d’objets Liste des messages d’erreur ou d’avertissement le cas échéant
code Chaîne Le code d'erreur du message
message Chaîne La description de l'erreur
cible Chaîne L’entité d’où provient l’erreur.
donnéesDeRéponse Objet
publishingStatus Chaîne État de publication de la soumission - [INPROGRESS, PUBLISHED, FAILED, UNKNOWN]
a échoué Booléen Indique si la publication a échoué et ne sera pas retentée

Exemple de réponse

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

Exemples de code

Les articles suivants fournissent des exemples de code détaillés qui montrent comment utiliser l’API de soumission au Microsoft Store dans différents langages de programmation :

Exemple en C# : API de soumission au Microsoft Store pour une application MSI ou EXE

Cet article fournit des exemples de code C# qui démontrent comment utiliser l'API de soumission au Microsoft Store pour les applications MSI ou EXE. Vous pouvez passer en revue chaque exemple pour en savoir plus sur la tâche qu’elle illustre, ou vous pouvez générer tous les exemples de code de cet article dans une application console.

Conditions préalables Ces exemples utilisent la bibliothèque suivante :

  • Package NuGet Newtonsoft.Json de Newtonsoft.

Programme principal L’exemple suivant implémente un programme de ligne de commande qui appelle les autres exemples de méthodes de cet article pour illustrer différentes façons d’utiliser l’API de soumission au Microsoft Store. Pour adapter ce code en fonction de vos besoins :

  • Attribuer la propriété SellerId à l’ID vendeur de votre compte Espace partenaires.
  • Attribuer la propriété ApplicationId à l’ID de l’application que vous souhaitez gérer.
  • Attribuez les propriétés ClientId et ClientSecret à l’ID client et à la clé de votre application, puis remplacez la chaîne tenantid dans l’URL TokenEndpoint par l’ID tenant de votre application. Pour plus d’informations, consultez Comment associer une application Microsoft Entra ID à votre compte Espace partenaires
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();

        }
    }
}

Classe d’assistance ClientConfiguration à l’aide de C#

L’exemple d’application utilise la classe d’assistance ClientConfiguration pour transmettre des données d’annuaire d’ID Microsoft Entra et des données d’application à chacun des exemples de méthodes qui utilisent l’API de soumission du Microsoft Store.

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

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

        /// <summary>
        /// Client secret of your Microsoft Entra ID 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 Microsoft Entra ID 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; }
    }
}

Créer une soumission d’applications à l’aide de C#

L'exemple suivant met en œuvre une classe qui utilise plusieurs méthodes de l'API de soumission au Microsoft Store pour mettre à jour la soumission d’applications.

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

Classe d’assistance IngestionClient à l’aide de C#

La classe IngestionClient fournit des méthodes d’assistance utilisées par d’autres méthodes dans l’exemple d’application pour effectuer les tâches suivantes :

  • Obtenez un jeton d’accès d’ID Microsoft Entra qui peut être utilisé pour appeler des méthodes dans l’API de soumission du Microsoft Store. Une fois le jeton obtenu, vous avez 60 minutes pour l’utiliser dans les appels à l’API de soumission au Microsoft Store avant expiration. Une fois le jeton arrivé à expiration, vous pouvez en générer un autre.
  • Traitez les requêtes HTTP pour l’API de soumission au Microsoft Store.
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 Microsoft Entra ID 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
        /// Microsoft Entra ID Directory app. Example: https://login.microsoftonline.com/d454d300-128e-2d81-334a-27d9b2baf002/oauth2/v2.0/token </param>
        /// <param name="clientId">Client Id of your Microsoft Entra ID Directory app. Example" 00001111-aaaa-2222-bbbb-3333cccc4444</param>
        /// <param name="clientSecret">Client secret of your Microsoft Entra ID 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;
        }
    }
}

Exemple Node.js : API de soumission au Microsoft Store pour une application MSI ou EXE

Cet article fournit des exemples de code Node.js qui démontrent comment utiliser l'API de soumission au Microsoft Store pour les applications MSI ou EXE. Vous pouvez passer en revue chaque exemple pour en savoir plus sur la tâche qu’elle illustre, ou vous pouvez générer tous les exemples de code de cet article dans une application console.

Conditions préalables Ces exemples utilisent la bibliothèque suivante :

  • node-fetch v2 [commande d'installation : npm install node-fetch@2]

Créer une soumission d’application à l’aide de node.js

L’exemple suivant appelle les autres exemples de méthodes de cet article pour illustrer différentes façons d’utiliser l’API de soumission au Microsoft Store. Pour adapter ce code en fonction de vos besoins :

  • Attribuer la propriété SellerId à l’ID vendeur de votre compte Espace partenaires.
  • Attribuer la propriété ApplicationId à l’ID de l’application que vous souhaitez gérer.
  • Attribuez les propriétés ClientId et ClientSecret à l’ID client et à la clé de votre application, puis remplacez la chaîne tenantid dans l’URL TokenEndpoint par l’ID tenant de votre application. Pour plus d’informations, consultez Comment associer une application Microsoft Entra ID à votre compte Espace partenaires

L'exemple suivant met en œuvre une classe qui utilise plusieurs méthodes de l'API de soumission au Microsoft Store pour mettre à jour la soumission d’applications.

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();

Assistance ClientConfiguration

L’exemple d’application utilise la classe d’assistance ClientConfiguration pour transmettre des données d’annuaire d’ID Microsoft Entra et des données d’application à chacun des exemples de méthodes qui utilisent l’API de soumission du Microsoft Store.

/** 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;

Assistant IngestionClient avec Node.js

La classe IngestionClient fournit des méthodes d’assistance utilisées par d’autres méthodes dans l’exemple d’application pour effectuer les tâches suivantes :

  • Obtenez un jeton d’accès d’ID Microsoft Entra qui peut être utilisé pour appeler des méthodes dans l’API de soumission du Microsoft Store. Une fois le jeton obtenu, vous avez 60 minutes pour l’utiliser dans les appels à l’API de soumission au Microsoft Store avant expiration. Une fois le jeton arrivé à expiration, vous pouvez en générer un autre.
  • Traitez les requêtes HTTP pour l’API de soumission au Microsoft Store.
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;

Aide supplémentaire

Si vous avez des questions sur l’API de soumission au Microsoft Store ou si vous avez besoin d’aide pour gérer vos soumissions avec cette API, utilisez les ressources suivantes :

  • Poser vos questions sur nos forums.
  • Visitez notre page de support et demandez l’une des options de support assisté pour l’Espace partenaires. Si vous êtes invité à choisir un type de problème et une catégorie, choisissez la soumission et la certification de l’application et l’envoi d’une application, respectivement.

Questions fréquemment posées

  1. Que puis-je faire par le biais de l’API de soumission de Microsoft Store ?

    L’API de soumission au Microsoft Store permet aux développeurs d’automatiser les tâches de gestion des applications, notamment :

    • Création et envoi de mises à jour d’application.
    • Chargement et gestion des packages d’application.
    • Mise à jour des métadonnées et des descriptions du Windows Store.

    Vous pouvez intégrer cette API à votre intégration continue ou créer des flux de travail, en automatisant les tâches de routine pour simplifier votre processus de publication.