Partager via


API de soumission au Microsoft Store pour application MSI ou EXE

Utilisez l’API de soumission au Microsoft Store pour l’application MSI ou EXE pour interroger et créer des soumissions pour les applications MSI ou EXE pour votre compte Espace partenaires 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 Azure Active Directory (Azure AD) 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 Azure AD. 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 annuaire Azure AD et de l’autorisation Administrateur général sur l’annuaire. Si vous utilisez déjà Microsoft 365 ou d’autres services professionnels de Microsoft, vous disposez déjà d’un annuaire Azure AD. Sinon, vous pouvez créer un annuaire Azure AD dans l’Espace partenaires sans frais supplémentaires.
  • Vous devez associer une application Azure AD à votre compte Espace partenaires et récupérer votre ID tenant, votre ID client et votre clé. Ces valeurs sont nécessaires pour obtenir un jeton d’accès Azure AD, que vous utiliserez dans les appels à l’API de soumission au 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.

Associer une application Azure AD à un compte Espace partenaires

Avant de pouvoir utiliser l'API de soumission au Microsoft Store pour les applications MSI ou EXE, vous devez associer une application Azure AD à votre compte Espace partenaires, récupérer l'ID tenant et l'ID client pour l'application et générer une clé. L'application Azure AD représente l'application ou le service à partir duquel vous souhaitez appeler l'API de soumission au Microsoft Store. Il vous faut l’ID tenant, l’ID client et la clé pour obtenir un jeton d’accès Azure AD à transmettre à l’API.

Remarque

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

  1. Dans l’Espace partenaires, associez le compte Espace partenaires de votre organisation à l’annuaire Azure AD de votre organisation.
  2. Ensuite, sur la page Utilisateurs de la section Paramètres de compte de l’Espace partenaires, ajoutez l’application Azure AD représentant 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 annuaire Azure AD, vous pouvez créer une application Azure AD dans l’Espace partenaires.
  3. Revenez à la page Utilisateurs, cliquez sur le nom de votre application Azure AD pour accéder à ses paramètres, puis copiez les valeurs ID tenant et 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 Azure Active Directory.

  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 clé secrète 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 Azure AD

Avant d'appeler l'une des méthodes de l'API de soumission au Microsoft Store pour les applications MSI ou EXE, vous devez d'abord obtenir un jeton d'accès Azure AD que vous transmettez à l’en-tête d'autorisation de chaque méthode de 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 de [Service to Service Calls Using Client Credentials]/azure/active-directory/azuread-dev/v1-oauth2-client-creds-grant-flow) pour envoyer un HTTP POST au point de terminaison https://login.microsoftonline.com/<tenant_id>/oauth2/token. 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

Après avoir obtenu un jeton d'accès Azure AD, vous pouvez appeler des méthodes dans l'API de soumission au Microsoft Store pour les applications 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 dans chaque module (listings, propriétés ou disponibilité) sous le brouillon actuel de soumission.

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 de l’Espace partenaires 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 Le filtre des langues de liste sous forme de chaîne séparée par des virgules [limite allant jusqu’à 200 langues].

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 Azure AD App 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 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 Catégorie Descriptif
prise en charge de l'accessibilité 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
dépendDesPilotesOuNT Booléen
descriptif Chaîne
développé par 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 [PAS_D'ESSAI_GRATUIT, ESSAI_GRATUIT]
type d'article de matériel Chaîne
isPrivacyPolicyRequired Booléen
estRecommandé Booléen
estRequis Booléen
estSucces Booléen
fonctionnalitéDuSystèmeRequise 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
configuration matérielle minimale Chaîne
exigence minimale 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
Détails des exigences système Tableau d’objets
cible Chaîne L’entité d’où provient l’Erreur.
site web Chaîne
Nouveautés 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": {
        "availability":{
            "markets": ["US"],
            "discoverability": "DISCOVERABLE",
            "enableInFutureMarkets": true,
            "pricing": "PAID",
            "freeTrial": "NO_FREE_TRIAL"
        },
        "properties":{
            "isPrivacyPolicyRequired": true,
            "privacyPolicyUrl": "http://contoso.com",
            "website": "http://contoso.com",
            "supportContactInfo": "http://contoso.com",
            "certificationNotes": "Certification Notes",
            "category": "DeveloperTools",
            "subcategory": "Database",
            "productDeclarations": {
                "dependsOnDriversOrNT": false,
                "accessibilitySupport": false,
                "penAndInkSupport": false
            },
            "isSystemFeatureRequired": [
                {
                    "isRequired": true,
                    "isRecommended": false,
                    "hardwareItemType": "Touch"
                },
                {
                    "isRequired": true,
                    "isRecommended": false,
                    "hardwareItemType": "Keyboard"
                },
                {
                    "isRequired": false,
                    "isRecommended": false,
                    "hardwareItemType": "Mouse"
                },
                {
                    "isRequired": false,
                    "isRecommended": false,
                    "hardwareItemType": "Camera"
                },
                {
                    "isRequired": false,
                    "isRecommended": false,
                    "hardwareItemType": "NFC_HCE"
                },
                {
                    "isRequired": false,
                    "isRecommended": false,
                    "hardwareItemType": "NFC_Proximity"
                },
                {
                    "isRequired": false,
                    "isRecommended": false,
                    "hardwareItemType": "Bluetooth_LE"
                },
                {
                    "isRequired": false,
                    "isRecommended": false,
                    "hardwareItemType": "Telephony"
                },
                {
                    "isRequired": false,
                    "isRecommended": false,
                    "hardwareItemType": "Microphone"
                }
            ],
            "systemRequirementDetails": [
                {
                    "minimumRequirement": "1GB",
                    "recommendedRequirement": "4GB",
                    "hardwareItemType": "Memory"
                },
                {
                    "minimumRequirement": "",
                    "recommendedRequirement": "",
                    "hardwareItemType": "DirectX"
                },
                {
                    "minimumRequirement": "",
                    "recommendedRequirement": "",
                    "hardwareItemType": "Video_Memory"
                },
                {
                    "minimumRequirement": "",
                    "recommendedRequirement": "",
                    "hardwareItemType": "Processor"
                },
                {
                    "minimumRequirement": "",
                    "recommendedRequirement": "",
                    "hardwareItemType": "Graphics"
                }
            ]
        },
        "listings":[{
            "language": "en-us",
            "description": "Description",
            "whatsNew": "What's New",
            "productFeatures": ["Feature 1"],
            "shortDescription": "Short Description",
            "searchTerms": ["Search Ter 1"],
            "additionalLicenseTerms": "License Terms",
            "copyright": "Copyright Information",
            "developedBy": "Developer Details",
            "sortTitle": "Product 101",
            "requirements": [
                {
                    "minimumHardware": "Pentium4",
                    "recommendedHardware": "Corei9"
                }
            ],
            "contactInfo": "contactus@contoso.com"               
        }],      
        "listingLanguages": [{"language":"en-us", "isComplete": true}]
    }
}

Mettre à jour l’API de métadonnées de soumission 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 requise système :
    • 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 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 de l’Espace partenaires du produit

En-têtes obligatoires

En-tête Valeur
Authorization: Bearer <Token> ID Azure AD App inscrit auprès du compte Espace partenaires
X-Seller-Account-Id ID vendeur du compte Espace partenaires

Paramètres de la requête

Nom Catégorie 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 [DÉTECTABLE, 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
site web 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
fonctionnalitéDuSystèmeRequise Tableau d’objets [Tactile, Clavier, Souris, Caméra, NFC_HCE, NFC_Proximity, Bluetooth_LE, Téléphonie, Microphone]
estRequis Booléen Obligatoire
estRecommandé Booléen Obligatoire
type d'article de matériel Chaîne Obligatoire
Détails des exigences système Tableau d’objets [Processeur, Graphics, Mémoire, DirectX, Video_Memory]
exigence minimale 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]
dépendDesPilotesOuNT Booléen Obligatoire
prise en charge de l'accessibilité 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 TOTAL dans tous les critères 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
développé par 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é]
configuration matérielle minimale 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
listingsÀAjouter 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

Marketing Abréviation
Afghanistan AF
Albanie AL
Algérie DZ
Samoa américaines COMME
Andorre ANNONCE
Angola AO
Anguilla Intelligence artificielle
Antarctique AQ
Antigua-et-Barbuda Groupe de disponibilité
Argentine Réalité Augmentée
Arménie matin
Aruba AW
Australie UA
Autriche À
Azerbaïdjan AZ
Les Bahamas Licence ès sciences
Bahreïn BH
Bangladesh bande dessinée
Barbade BB
Bélarus PAR
Belgique ÊTRE
Belize BZ
Bénin BJ
Bermudes BM
Bhoutan BT
République bolivarienne du Venezuela VE
Bolivie BO
Bonaire BQ
Bosnie-Herzégovine BA
Botswana BW
Bouvet (Île) BV
Brésil Brésil
Territoire britannique de l’Océan Indien IO
Îles Vierges britanniques VG
Brunéi Darussalam BN
Bulgarie BG
Burkina Faso BF
Burundi BI
Cambodge KH
Cameroun CM
Canada CA
Cabo Verde curriculum vitae
Cayman (îles) KY
République centrafricaine CF
Tchad TD
Chili CL
Chine CN
Christmas (Île) CX
Îles Cocos CC
Colombie Monoxyde de carbone
Comores (Les) KILOMÈTRE
Congo CG
Congo (RDC) CD
Cook (Îles) CK
Costa Rica CR
Croatie RH
Curaçao CW
Chypre CY
République tchèque CZ
Côte d’Ivoire Côte d'Ivoire
Danemark DK
Djibouti DJ
Dominique DÉCIMÈTRE
République dominicaine PRATIQUES CONSEILLÉES
Équateur CE
Égypte EG
Salvador SV
Guinée équatoriale GQ
Érythrée Salle d'Urgence
Estonie EE
Éthiopie ET
Îles Malouines FK
Féroé (îles) FO
Fidji (îles) FJ
Finlande FI
France FR
Guyane française GF
Polynésie française PF
Terres australes et antarctiques françaises TF
Gabon Assemblée générale
Gambie General Motors
Géorgie GE
Allemagne Allemagne
Ghana GH
Gibraltar GI
Grèce GR
Groenland GL
Grenade GD
Guadeloupe médecin généraliste
Guam Guam
Guatemala GT
Guernesey GG
Guinée GN
Guinée-Bissau Gigawatt
Guyana GY
Haïti HT
Heard et McDonald (Îles) HM
État de la Cité du Vatican VA
Honduras HN
Hong Kong (R.A.S.) Hong Kong
Hongrie HU
Islande Système d'information État islamique
Inde DANS
Indonésie id
Irak QI
Irlande Internet Explorer
Israël IL
Italie TI
Jamaïque JM
Japon JP
Jersey JE
Jordanie Jeux Olympiques
Kazakhstan KZ
Kenya KE
Kiribati KI
Corée du Sud KR
Koweït kW
Kirghizistan kg
Laos LA
Lettonie LV
Liban LB
Lesotho LS
Libéria LR
Libye AL
Liechtenstein LI
Lituanie LT
Luxembourg LU
Macao (R.A.S.) MO
Macédoine du Nord MK
Madagascar MG
Malawi MW
Malaisie MON
Maldives MV
Mali ML
Malte MT
Man (Île de) messagerie instantanée
Marshall (Îles) MH
Martinique MQ
Mauritanie MONSIEUR
Maurice (île) MU
Mayotte YT
Mexique MX
Micronésie FM
République de Moldova Docteur en médecine
Monaco MC
Mongolie MN
Monténégro - ME
Montserrat MS
Maroc MAMAN
Mozambique MZ
Myanmar MM
Namibie N/D
Nauru NR
Népal NP
Pays-Bas NL
Nouvelle-Calédonie NC
Nouvelle-Zélande NZ
Nicaragua NI
Niger NE
Nigéria NG
Nioué Nunavut
Norfolk (Île) NF
Mariannes du Nord (Îles) député
Norvège NON
Oman OM
Pakistan PK
Palaos Prisonnier de guerre
Autorité palestinienne P.S.
Panama PAPA
Papouasie-Nouvelle-Guinée PG
Paraguay PY
Pérou PE
Philippines PH
Îles Pitcairn PN
Pologne PL
Portugal PT
Qatar QR
La réunion RE
Roumanie RO
Russie Russie
Rwanda L/E
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 Croix de Victoria
Samoa WS
Saint-Marin SM
Arabie Saoudite Société Anonyme
Sénégal SN
Serbie RS
Seychelles SC
Sierra Leone SL
Singapour SG
Saint-Martin (partie néerlandaise) SX
Slovaquie SK
Slovénie Système International
Îles Salomon SB
Somalie AINSI
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 MJ
Timor-Leste TL
Tog - TG
Tokélaou TK
Tonga À
Trinité-et-Tobago - TT
Tunisie Tennessee
Turquie Turquie
Turkménistan TM
Îles Turques-et-Caïques TC
Tuvalu TÉLÉ
États-Unis Îles mineures éloignées Euh
Îles Vierges américaines VI
Ouganda Ouganda
Ukraine UA
Émirats Arabes Unis Æ
Royaume-Uni Go
États-Unis États-Unis
Uruguay UY
Ouzbékistan UZ
Vanuatu VU
Viêt Nam VN
Wallis-et-Futuna WF
Yémen VOUS
Zambie ZM
Zimbabwe ZW
Îles Åland HACHE

Catégories et sous-catégories

Catégorie Sous-catégories
BooksAndReference EReader, Fiction, Non-fiction, Référence
Métier Comptabilité et finance, Collaboration, CRM, Données et analyses, Gestion de fichiers, Inventaire et logistique, Juridique et RH, Gestion de projet, Bureau à distance, Ventes et marketing, Temps et dépenses
DeveloperTools Base de données, Outils de conception, Kits de développement, Mise en réseau, Références et formation, Serveurs, Utilitaires, Hébergement web
Éducation Livres Éducatifs et de Référence, Apprentissage Précoce, Outils Pédagogiques, Langue, Aides à l'Étude
Divertissement (aucune)
FoodAndDining (aucune)
GouvernementEtPolitique (aucune)
Santé et Fitness (aucune)
KidsAndFamily LivresEtRéférencesPourEnfantsEtFamille, DivertissementPourEnfantsEtFamille, LoisirsEtJouets, SportsEtActivités, VoyagePourEnfantsEtFamille
Style de vie Automobile, DYI, HomeAndGarden, Relations, SpecialInterest, StyleAndFashion
Médecine (aucune)
MultimediaDesign Illustration et conception graphique, Production musicale, Production photo et vidéo
Musique (aucune)
NavigationAndMaps (aucune)
ActualitésEtMétéo Actualités et météo
PersonalFinance BanqueEtInvestissements, BudgétisationEtTaxes
Personnalisation RingtonesAndSounds, thèmes, WallpaperAndLockScreens
PhotoAndVideo (aucune)
Productivité (aucune)
Sécurité PCProtection, PersonalSecurity
Achats (aucune)
Réseaux sociaux (aucune)
Sport (aucune)
Déplacements CityGuides, Hôtels
Utilitaires et Outils BackupAndManage, FileManager

Langues

Nom de la langue Codes des langues prises en charge
Afrikaans af, af-za
Albanais sq, sq-al
Amharique matin, am-et
Arménien salut, hy-am
Assamais as, as-in
Azéri az-arab, az-arab-az, az-cyrl, az-cyrl-az, az-latn, az-latn-az-latn-az
Basque (Basque) eu, eu-es
Biélorusse être, be-by
Le 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-Valence
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
Filipin - 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
Goudjrati gu, gu-in
Haoussa ha, ha-latn, ha-latn-ng
Hébreu il, he-il
hindi bonjour, hi-in
Hongrois hu, hu-hu
Islandais est, is-is
Igb - ig-latn, ig-ng
Indonésien id, id-id
Inuktitut (latin) iu-cans, iu-latn, iu-latn-ca
Irlandais ga, ga-ie
isiXhosa xh, xh-za
Zoulou zu, zu-za
Italien il, it-it, it-ch
Japonais ja, ja-jp
kannada kn, kn-in
Kazakh kk, kk-kz
Khmer km, km-kh
Quiché 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
Kirghiz 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
Mongole (cyrillique) mn-cyrl, mn-mong, mn-mn, mn-phag
Népalais ne, ne-np
Norvégien nb, nb-no, nn, nn-no, non, no-no
Odia ou, 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 votre, ur-pk
Ouïgour 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 Catégorie Descriptif
estSucces 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 obtenir l’état d’une soumission en cours
ID de soumission en cours 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": ""
    } 
}

Obtenir l’API de packages brouillons 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 de l’Espace partenaires du produit
packageId ID unique du package à récupérer

En-têtes obligatoires

En-tête Valeur
Authorization: Bearer <Token> Utilisation de l’ID Azure AD App 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 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 Catégorie Descriptif
estSucces 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 pour conserver des données de 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 (InstallationSilencieuse) 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
paramètresD'installation Chaîne
genericDocUrl Chaîne
détails de l'erreur Tableau d’objets
scénario d'erreur Chaîne
errorScenarioDetails Tableau d’objets
errorValue Chaîne
URLd'erreur 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",
        }]
    }
}

Mettre à jour l’API de packages brouillons 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 d'accès [Mise à jour corrective de package unique] : /submission/v1/product/{productId}/packages/{packageId}
Méthode : PATCH

Comportement 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 L’ID de l’Espace partenaires du produit
packageId ID unique du package

En-têtes obligatoires

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

Paramètres de la requête

Nom Catégorie 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 (InstallationSilencieuse) 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
paramètresD'installation 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 pour contenir des codes d’erreur personnalisés et des détails pour les programmes d’installation de type EXE.
scénario d'erreur Chaîne Identifiez le scénario d’erreur spécifique. [installationAnnuléeParLUtilisateur, applicationExisteDéjà, installationDéjàEnCours, espaceDisquePlein, redémarrageRequis, échecRéseau, packageRejetéPendantLInstallation, installationRéussie, divers]
errorScenarioDetails Tableau d’objets
errorValue Chaîne Code d’erreur qui peut être présent pendant l’installation
URLd'erreur 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 Catégorie Descriptif
estSucces 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 de soumission en cas de soumission en cours]
ID de soumission en cours 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": ""
    } 
}

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 Azure AD App 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 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 Catégorie Descriptif
estSucces 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]
ID de soumission en cours 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}/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 L’ID de l’Espace partenaires du produit

Paramètres de requête

Nom Descriptif
langues [Facultatif] Le filtre des langues de liste sous forme de chaîne séparée par des virgules [limite allant jusqu’à 200 langues]. 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 Azure AD App 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 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 Catégorie Descriptif
estSucces 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
listeDesActifs Tableau d’objets Description des détails de la ressource pour chaque langue
langue Chaîne
storeLogos Tableau d’objets
captures d'écran Tableau d’objets
pièce d'identité 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
                    }
                }
            ]
        }]
    }
}

Créer une API De référencement des ressources

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 l’application EXE ou MSI utilise des URL SAS générées par le runtime dans les magasins d’objets blob pour chaque chargement d’éléments d’image individuels, ainsi qu’un appel d’API commit une fois le chargement réussi. 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 Créer une ressource de référencement pour envoyer une demande concernant le chargement des ressources, ainsi que la langue, le type et le nombre de ressources.
  2. En fonction du nombre de ressources demandées, les ID de ressource sont créés à la demande et créent une URL SAP à court terme et les renvoient dans le corps de 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 de l’Espace partenaires du produit

En-têtes obligatoires

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

Paramètres de la requête

Nom Catégorie Descriptif
langue Chaîne Obligatoire
createAssetRequest Objet Obligatoire
Capture d'écran Nombre entier Obligatoire si le fournisseur de logiciel indépendant doit mettre à jour des captures d’écran ou ajouter une nouvelle langue [1 - 10]
Logo Nombre entier Obligatoire si le fournisseur de logiciel indépendant doit mettre à jour les logos ou ajouter une nouvelle langue de référencement [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 Catégorie Descriptif
estSucces 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
listeDesActifs 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
pièce d'identité Chaîne
URL de téléchargement de l'actif principal 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 L’ID de l’Espace partenaires du produit

En-têtes obligatoires

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

Paramètres de la requête

Nom Catégorie Descriptif
listeDesActifs Objet
langue Chaîne
storeLogos Tableau d’objet
captures d'écran Tableau d’objet
pièce d'identité 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 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 Catégorie Descriptif
estSucces 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
ID de soumission en cours 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

API pour vérifier l’aptitude du module avant de pouvoir être créée. 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’ID de l’Espace partenaires du produit

En-têtes obligatoires

En-tête Descriptif
Authorization: Bearer <Token> Utilisation de l’ID Azure AD App 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 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 Catégorie Descriptif
estSucces 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
estPrêt Booléen Indique si tous les modules sont à l’état prêt, y compris le chargement de package
ID de soumission en cours 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 :

  • pour la soumission active et échoue avec le message d’erreur s’il existe une soumission active.
  • si tous les modules sont prêts à l’état 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 Azure AD App 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 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 Catégorie Descriptif
estSucces 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 de préparation du module, y compris le chargement du package pour la soumission
ID de soumission Chaîne ID de la soumission nouvellement créée
ID de soumission en cours 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 case activée l’état de la 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’ID de l’Espace partenaires du produit

En-têtes obligatoires

En-tête Descriptif
Authorization: Bearer <Token> Utilisation de l’ID Azure AD App 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 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 Catégorie Descriptif
estSucces 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
statut de publication 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 Azure AD à votre compte de l’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 Azure Active Directory et des données d’application à chacun des exemples de méthodes qui utilisent l’API de soumission au Microsoft Store.

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

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

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

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

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

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

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


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

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 :

  • Obtenir un jeton d’accès Azure AD à utiliser avec l’API de soumission au 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 Azure Active Directory allowing the caller to invoke the API
        /// on behalf of a user
        /// </param>
        /// <param name="serviceUrl">The service URL.</param>
        public SubmissionClient(string accessToken, string serviceUrl)
        {
            if (string.IsNullOrEmpty(accessToken))
            {
                throw new ArgumentNullException("accessToken");
            }

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

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

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

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

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

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

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

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

            return result.access_token;
        }


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

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

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

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

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

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

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

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


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

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 Azure AD à votre compte de l’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 Azure Active Directory et des données d’application à chacun des exemples de méthodes qui utilisent l’API de soumission au 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;

Assistance IngestionClient à l’aide de 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 :

  • Obtenir un jeton d’accès Azure AD à utiliser avec l’API de soumission au 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.