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 :
- Assurez-vous d'avoir rempli tous les prérequis.
- 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.
- 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.
- Dans l’Espace partenaires, associez le compte Espace partenaires de votre organisation à l’annuaire Azure AD de votre organisation.
- 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.
- 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.
- 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 :
Connectez-vous au portail Azure.
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.
Recherchez et sélectionnez Azure Active Directory.
Sous Gérer, sélectionnez Inscriptions d'applications > sélectionnez votre application.
Sélectionnez Certificats et secrets > Clé secrète client > Nouvelle clé secrète client.
Ajoutez une description pour votre clé secrète client.
Sélectionnez un délai d’expiration pour le secret ou spécifiez une durée de vie personnalisée.
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.
Sélectionnez Ajouter.
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 | Description |
---|---|
productId | L’ID de l’Espace partenaires du produit |
moduleName | Module Espace partenaires : référencements, propriétés ou disponibilité |
Paramètres de requête
Paramètre | Description |
---|---|
languages | 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 | Type | Description |
---|---|---|
accessibilitySupport | Boolean | |
additionalLicenseTerms | Chaîne | |
availability | Object | Données du module de disponibilité |
category | Chaîne | Voir la liste des catégories ci-dessous |
certificationNotes | Chaîne | |
code | Chaîne | Le code d'erreur du message |
contactInfo | Chaîne | |
copyright | Chaîne | |
dependsOnDriversOrNT | Boolean | |
description | Chaîne | |
developedBy | Chaîne | |
découvrabilité | Chaîne | [DISCOVERABLE, DEEPLINK_ONLY] |
enableInFutureMarkets | Boolean | |
erreurs | Tableau d’objets | Liste des messages d’erreur ou d’avertissement le cas échéant |
freeTrial | Chaîne | [NO_FREE_TRIAL, FREE_TRIAL] |
hardwareItemType | Chaîne | |
isPrivacyPolicyRequired | Boolean | |
isRecommended | Boolean | |
isRequired | Boolean | |
isSuccess | Boolean | |
isSystemFeatureRequired | Tableau d’objets | |
langue | Chaîne | Voir la liste des langues ci-dessous |
listes | Tableau d’objets | Répertorie les données de module pour chaque langue |
marchés | Tableau de chaînes | Voir la liste des marchés ci-dessous |
message | Chaîne | La description de l'erreur |
minimumHardware | Chaîne | |
minimumRequirement | Chaîne | |
penAndInkSupport | Boolean | |
Prix | Chaîne | [GRATUIT, FREEMIUM, ABONNEMENT, PAYANT] |
privacyPolicyUrl | Chaîne | |
productDeclarations | Object | |
productFeatures | Tableau de chaînes | |
properties | Object | Données du module Propriétés |
recommendedHardware | Chaîne | |
recommendedRequirement | Chaîne | |
responseData | Object | Contient une charge utile de réponse réelle pour la requête |
spécifications | Tableau d’objets | |
searchTerms | Tableau de chaînes | |
shortDescription | Chaîne | |
subcategory | Chaîne | Voir la liste des sous-catégories ci-dessous |
supportContactInfo | Chaîne | |
systemRequirementDetails | Tableau d’objets | |
cible | Chaîne | L’entité d’où provient l’Erreur. |
website | Chaîne | |
whatsNew | 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 | Description |
---|---|
productId | 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 | Type | Description |
---|---|---|
availability | Object | 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 | Boolean | 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] |
properties | Object | Objet contenant les métadonnées du module de propriétés |
isPrivacyPolicyRequired | Boolean | Obligatoire |
privacyPolicyUrl | Chaîne | Obligatoire si isPrivacyPolicyRequired = true Doit être une URL valide |
website | Chaîne | Doit être un URL valide |
supportContactInfo | Chaîne | Doit être une URL ou une adresse e-mail valide |
certificationNotes | Chaîne | Limite de caractères recommandée = 2 000 |
category | Chaîne | Obligatoire Consultez la liste des catégories ci-dessous |
subcategory | Chaîne | Obligatoire Consultez la liste des sous-catégories ci-dessous |
productDeclarations | Object | Obligatoire |
isSystemFeatureRequired | Tableau d’objets | [Tactile, Clavier, Souris, Caméra, NFC_HCE, NFC_Proximity, Bluetooth_LE, Téléphonie, Microphone] |
isRequired | Boolean | Obligatoire |
isRecommended | Boolean | Obligatoire |
hardwareItemType | Chaîne | Obligatoire |
systemRequirementDetails | Tableau d’objets | [Processeur, Graphics, Mémoire, DirectX, Video_Memory] |
minimumRequirement | Chaîne | Obligatoire pour systemRequirementsText, MaxLength = 200 Valeurs autorisées dans hardwareItemType = Mémoire : [300 Mo, 750 Mo, 1 Go, 2 Go, 4 Go, 6 Go, 8 Go, 12 Go, 16 Go, 20 Go] Valeurs autorisées dans hardwareItemType = DirectX : [DX9, DX10, DX11, DX12-FEATURELEVEL11, DX12-FEATURELEVEL12] Valeurs autorisées dans hardwareItemType = Video_Memory : [1 Go, 2 Go, 4 Go, 6 Go] |
recommendedRequirement | Chaîne | Obligatoire pour systemRequirementsText, MaxLength = 200 Valeurs autorisées dans hardwareItemType = Mémoire : [300 Mo, 750 Mo, 1 Go, 2 Go, 4 Go, 6 Go, 8 Go, 12 Go, 16 Go, 20 Go] Valeurs autorisées dans hardwareItemType = DirectX : [DX9, DX10, DX11, DX12-FEATURELEVEL11, DX12-FEATURELEVEL12] Valeurs autorisées dans hardwareItemType = Video_Memory : [1 Go, 2 Go, 4 Go, 6 Go] |
dependsOnDriversOrNT | Boolean | Obligatoire |
accessibilitySupport | Boolean | Obligatoire |
penAndInkSupport | Boolean | Obligatoire |
listes | Object | Objet pour répertorier les données de module pour une seule langue |
langue | Chaîne | Obligatoire Consultez la liste des langues ci-dessous |
description | Chaîne | Limite de caractères requise = 10 000 |
whatsNew | Chaîne | Limite de caractères = 1 500 |
productFeatures | Tableau de chaînes | 200 caractères par fonctionnalité ; Jusqu’à 20 fonctionnalités |
shortDescription | Chaîne | Limite de caractères = 1 000 |
searchTerms | 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 |
additionalLicenseTerms | Chaîne | Limite de caractères requise = 10 000 |
copyright | Chaîne | Limite de caractères = 200 |
developedBy | Chaîne | Limite de caractères = 255 |
spécifications | Tableau d’objets | 200 caractères par élément ; Jusqu’à 11 éléments TOTAL entre minimum et recommandé] |
minimumHardware | Chaîne | Limite de caractères = 200 |
recommendedHardware | Chaîne | Limite de caractères = 200 |
contactInfo | Chaîne | Limite de caractères = 200 |
listingsToAdd | Tableau de chaînes | Voir la liste des langues ci-dessous |
listingsToRemove | 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 | AS |
Andorre | AD |
Angola | AO |
Anguilla | Intelligence artificielle |
Antarctique | AQ |
Antigua-et-Barbuda | Groupe de disponibilité |
Argentine | AR |
Arménie | AM |
Aruba | AW |
Australie | AU |
Autriche | AT |
Azerbaïdjan | AZ |
Les Bahamas | BS |
Bahreïn | BH |
Bangladesh | BD |
Barbade | BB |
Bélarus | BY |
Belgique | BE |
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 |
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 | CV |
Cayman (îles) | KY |
République centrafricaine | CF |
Tchad | TD |
Chili | CL |
Chine | CN |
Christmas (Île) | CX |
Îles Cocos | CC |
Colombie | CO |
Comores (Les) | KM |
Congo | CG |
Congo (RDC) | CD |
Cook (Îles) | CK |
Costa Rica | CR |
Croatie | HR |
Curaçao | CW |
Chypre | CY |
République tchèque | CZ |
Côte d'Ivoire | CI |
Danemark | DK |
Djibouti | DJ |
Dominique | DM |
République dominicaine | PRATIQUES CONSEILLÉES |
Équateur | EC |
Égypte | EG |
El Salvador | SV |
Guinée équatoriale | GQ |
Érythrée | ER |
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 | GA |
Gambie | GM |
Géorgie | GE |
Allemagne | DE |
Ghana | GH |
Gibraltar | GI |
Grèce | GR |
Groenland | GL |
Grenade | GD |
Guadeloupe | GP |
Guam | GU |
Guatemala | GT |
Guernesey | GG |
Guinée | GN |
Guinée-Bissau | GW |
Guyana | GY |
Haïti | HT |
Heard et McDonald (Îles) | HM |
État de la Cité du Vatican | VA |
Honduras | HN |
Hong Kong (R.A.S.) | HK |
Hongrie | HU |
Islande | IS |
Inde | IN |
Indonésie | id |
Irak | IQ |
Irlande | Internet Explorer |
Israël | IL |
Italie | IT |
Jamaïque | JM |
Japon | JP |
Jersey | JE |
Jordanie | JO |
Kazakhstan | KZ |
Kenya | KE |
Kiribati | KI |
Corée du Sud | KR |
Koweït | KW |
Kirghizistan | KG |
Laos | LA |
Lettonie | LV |
Liban | LB |
Lesotho | LS |
Libéria | LR |
Libye | LY |
Liechtenstein | LI |
Lituanie | LT |
Luxembourg | LU |
Macao (R.A.S.) | MO |
Macédoine du Nord | MK |
Madagascar | MG |
Malawi | MW |
Malaisie | MY |
Maldives | MV |
Mali | ML |
Malte | MT |
Man (Île de) | IM |
Marshall (Îles) | MH |
Martinique | MQ |
Mauritanie | MR |
Maurice (île) | MU |
Mayotte | YT |
Mexique | MX |
Micronésie | FM |
République de Moldova | MD |
Monaco | MC |
Mongolie | MN |
Monténégro - ME | |
Montserrat | MS |
Maroc | MA |
Mozambique | MZ |
Myanmar | MM |
Namibie | NA |
Nauru | NR |
Népal | NP |
Pays-Bas | NL |
Nouvelle-Calédonie | NC |
Nouvelle-Zélande | NZ |
Nicaragua | NI |
Niger | NE |
Nigéria | NG |
Niue | NU |
Norfolk (Île) | NF |
Mariannes du Nord (Îles) | MP |
Norvège | NON |
Oman | OM |
Pakistan | PK |
Palaos | PW |
Autorité palestinienne | PS |
Panama | PA |
Papouasie-Nouvelle-Guinée | PG |
Paraguay | PY |
Pérou | PE |
Philippines | PH |
Îles Pitcairn | PN |
Pologne | PL |
Portugal | PT |
Qatar | QR |
La réunion | RE |
Roumanie | RO |
Russie | RU |
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 | VC |
Samoa | WS |
Saint-Marin | SM |
Arabie Saoudite | SA |
Sénégal | SN |
Serbie | RS |
Seychelles | SC |
Sierra Leone | SL |
Singapour | SG |
Saint-Martin (partie néerlandaise) | SX |
Slovaquie | SK |
Slovénie | SI |
Îles Salomon | SB |
Somalie | SO |
Afrique du Sud | ZA |
Géorgie du Sud et îles Sandwich du Sud | GS |
Espagne | ES |
Sri Lanka | LK |
Suriname | SR |
Svalbard et Jan Mayen | SJ |
Swaziland | SZ |
Suède | SE |
Suisse | CH |
Sao Tomé-et-Principe | ST |
Taïwan | TW |
Tadjikistan | TJ |
Tanzanie | TZ |
Thaïlande | MJ |
Timor-Leste | TL |
Tog - TG | |
Tokelau | TK |
Tonga | TO |
Trinité-et-Tobago - TT | |
Tunisie | TN |
Turquie | TR |
Turkménistan | TM |
Îles Turques-et-Caïques | TC |
Tuvalu | TV |
États-Unis Îles mineures éloignées | UM |
Îles Vierges américaines | VI |
Ouganda | UG |
Ukraine | UA |
Émirats Arabes Unis | AE |
Royaume-Uni | Go |
États-Unis | US |
Uruguay | UY |
Ouzbékistan | UZ |
Vanuatu | VU |
Vietnam | VN |
Wallis-et-Futuna | WF |
Yémen | YE |
Zambie | ZM |
Zimbabwe | ZW |
Îles Åland | AX |
Catégories et sous-catégories
Catégorie | Sous-catégories |
---|---|
BooksAndReference | EReader, Fiction, Non-fiction, Référence |
Métier | AccountingAndfinance, Collaboration, CRM, DataAndAnalytics, FileManagement, InventoryAndlogistics, LegalAndHR, ProjectManagement, RemoteDesktop, SalesAndMarketing, TimeAndExpenses |
DeveloperTools | Database, DesignTools, DevelopmentKits, Networking, ReferenceAndTraining, Servers, Utilities, WebHosting |
Education | EducationBooksAndReference, EarlyLearning, InstructionalTools, Language, StudyAids |
Divertissement | (aucune) |
FoodAndDining | (aucune) |
GovernmentAndPolitics | (aucune) |
HealthAndFitness | (aucune) |
KidsAndFamily | KidsAndFamilyBooksAndReference, KidsAndFamilyEntertainment, HobbiesAndToys, SportsAndActivities, KidsAndFamilyTravel |
Style de vie | Automobile, DYI, HomeAndGarden, Relations, SpecialInterest, StyleAndFashion |
Médecine | (aucune) |
MultimediaDesign | IllustrationAndGraphicDesign, MusicProduction, PhotoAndVideoProduction |
Musique | (aucune) |
NavigationAndMaps | (aucune) |
NewsAndWeather | Actualités et météo |
PersonalFinance | BankingAndInvestments, BudgetingAndTaxes |
Personnalisation | RingtonesAndSounds, thèmes, WallpaperAndLockScreens |
PhotoAndVideo | (aucune) |
Productivité | (aucune) |
Sécurité | PCProtection, PersonalSecurity |
Achats | (aucune) |
Réseaux sociaux | (aucune) |
Sports | (aucune) |
Déplacements | CityGuides, Hôtels |
UtilitiesAndTools | BackupAndManage, FileManager |
Langues
Nom de la langue | Codes des langues prises en charge |
---|---|
Afrikaans | af, af-za |
Albanais | sq, sq-al |
Amharique | am, am-et |
Arménien | hy, hy-am |
Assamais | as, as-in |
Azéri | az-arab, az-arab-az, az-cyrl, az-cyrl-az, az-latn, az-latn-az |
Basque (Basque) | eu, eu-es |
Biélorusse | be, be-by |
Bangla | bn, bn-bd, bn-in |
Bosniaque | bs, bs-cyrl, bs-cyrl-ba, bs-latn, bs-latn-ba |
Bulgare | bg, bg-bg |
Catalan | ca, ca-es, ca-es-valencia |
Cherokee | chr-cher, chr-cher-us, chr-latn |
Chinois (simplifié) | zh-Hans, zh-cn, zh-hans-cn, zh-sg, zh-hans-sg |
Chinois (traditionnel) | zh-Hant, zh-hk, zh-mo, zh-tw, zh-hant-hk, zh-hant-mo, zh-hant-tw, zh-mo, zh-tw, zh-hant-hk, zh-hant-mo, zh-hant-tw |
Croate | hr, hr-hr, hr-ba |
Tchèque | cs, cs-cz |
Danois | da, da-dk |
Dari | prs, prs-af, prs-arab |
Néerlandais | nl, nl-nl, nl-be |
Anglais | en, en-au, en-ca, en-gb, en-ie, en-in, en-nz, en-sg, en-us, en-za, en-bz, en-hk, en-id, en-jm, en-kz, en-mt, en-my, en-ph, en-pk, en-tt, en-vn, en-zw |
Estonien | et, et-ee |
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 |
Hausa | ha, ha-latn, ha-latn-ng |
Hébreu | he, he-il |
Hindi | hi, hi-in |
Hongrois | hu, hu-hu |
Islandais | is, 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 | it, 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 |
KiSwahili | 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, no, no-no |
Odia | or, or-in |
Persan | fa, fa-ir |
Polonais | pl, pl-pl |
Portugais (Brésil) | pt-br |
Portugais (Portugal) | pt, pt-pt |
Pendjabi | pa, pa-arab, pa-arab-pk, pa-deva, pa-in |
Quechua | quz, quz-bo, quz-ec, quz-pe |
Roumain | ro, ro-ro |
Russe | ru, ru-ru |
Gaélique écossais | gd-gb, gd-latn |
Serbe (latin) | sr-Latn, sr-latn-cs, sr, sr-latn-ba, sr-latn-me, sr-latn-rs |
Serbe (cyrillique) | sr-cyrl, sr-cyrl-ba, sr-cyrl-cs, sr-cyrl-me, sr-cyrl-rs |
Sotho du Nord | nso, nso-za |
Setswana | tn, tn-bw, tn-za |
Sindhi | sd-arab, sd-arab-pk, sd-deva |
Cingalais | si, si-lk |
Slovaque | sk, sk-sk |
Slovène | sl, sl-si |
Espagnol | es, es-cl, es-co, es-es, es-mx, es-ar, es-bo, es-cr, es-do, es-ec, es-gt, es-hn, es-ni, es-pa, es-pe, es-pr, es-py, es-sv, es-us, es-uy, es-ve |
Suédois | sv, sv-se, sv-fi |
Tadjik (cyrillique) | tg-arab, tg-cyrl, tg-cyrl-tj, tg-latn |
Tamoul | ta, ta-in |
Tatar | tt-arab, tt-cyrl, tt-latn, tt-ru |
Télougou | te, te-in |
Thaï | th, th-th |
Tigrigna | ti, ti-et |
Turc | tr, tr-tr |
Turkmène | tk-cyrl, tk-latn, tk-tm, tk-latn-tr, tk-cyrl-tr |
Ukrainien | uk, uk-ua |
Ourdou | ur, ur-pk |
Ouï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 | Type | Description |
---|---|---|
isSuccess | Boolean | |
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. |
responseData | Object | Contient une charge utile de réponse réelle pour la requête |
pollingUrl | Chaîne | URL d’interrogation pour obtenir l’état d’une soumission en cours |
ongoingSubmissionId | Chaîne | ID de soumission d’une soumission déjà en cours |
Exemple de réponse
{
"isSuccess": true,
"errors": [{
"code": "badrequest",
"message": "Error Message 1",
"target": "listings"
}, {
"code": "warning",
"message": "Warning Message 1",
"target": "properties"
}],
"responseData": {
"pollingUrl": "/submission/v1/product/{productId}/submission/{submissionId}/status",
"ongoingSubmissionId": ""
}
}
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 | Description |
---|---|
productId | 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 | Type | Description |
---|---|---|
isSuccess | Boolean | |
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. |
responseData | Object | |
packages | Tableau d’objets | Objet pour conserver des données de module de package |
packageId | Chaîne | |
packageUrl | Chaîne | |
languages | Tableau de chaînes | |
architectures | Tableau de chaînes | [Neutre, X86, X64, Arm, Arm64] |
isSilentInstall | Boolean | Cela doit être marqué comme vrai si votre programme d’installation s’exécute en mode silencieux sans nécessiter de commutateurs ou d’autres valeurs false |
installerParameters | Chaîne | |
genericDocUrl | Chaîne | |
errorDetails | Tableau d’objets | |
errorScenario | Chaîne | |
errorScenarioDetails | Tableau d’objets | |
errorValue | Chaîne | |
errorUrl | Chaîne | |
packageType | 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 | Description |
---|---|
productId | 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 | Type | Description |
---|---|---|
packages | Tableau d’objets | Objet pour contenir les données du module de package [Obligatoire uniquement pour la mise à jour intégrale du module] |
packageUrl | Chaîne | Obligatoire |
languages | Tableau de chaînes | Obligatoire |
architectures | Tableau de chaînes | Obligatoire doit contenir une architecture unique - Neutre, X86, X64, Arm, Arm64 |
isSilentInstall | Boolean | Obligatoire : cette propriété doit être marquée comme true si votre programme d’installation s’exécute en mode silencieux sans nécessiter de commutateurs ou d’autres valeurs false |
installerParameters | Chaîne | Obligatoire si isSilentInstall a la valeur false |
genericDocUrl | Chaîne | Obligatoire si packageType est exe Lien vers le document contenant les détails des codes d’erreur personnalisés pour le programme d’installation de type EXE |
errorDetails | 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. |
errorScenario | Chaîne | Identifiez le scénario d’erreur spécifique. [installationCancelledByUser, applicationAlreadyExists, installationAlreadyInProgress, diskSpaceIsFull, rebootRequired, networkFailure, packageRejectedDuringInstallation, installationSuccessful, miscellaneous] |
errorScenarioDetails | Tableau d’objets | |
errorValue | Chaîne | Code d’erreur qui peut être présent pendant l’installation |
errorUrl | Chaîne | URL pour obtenir des détails sur l’erreur |
packageType | Chaîne | Obligatoire [exe, msi] |
Exemple de requête [Mise à jour intégrale du module]
{
"packages":[{
"packageUrl": "https://www.contoso.com/downloads/1.1/setup.exe",
"languages": ["en-us"],
"architectures": ["X86"],
"isSilentInstall": true,
"installerParameters": "/s",
"genericDocUrl": "https://docs.contoso.com/doclink",
"errorDetails": [{
"errorScenario": "rebootRequired",
"errorScenarioDetails": [{
"errorValue": "ERR001001",
"errorUrl": "https://errors.contoso.com/errors/ERR001001"
}]
}],
"packageType": "exe",
}]
}
Exemple de requête [Mise à jour corrective d’un package unique]
{
"packageUrl": "https://www.contoso.com/downloads/1.1/setup.exe",
"languages": ["en-us"],
"architectures": ["X86"],
"isSilentInstall": true,
"installerParameters": "/s",
"genericDocUrl": "https://docs.contoso.com/doclink",
"errorDetails": [{
"errorScenario": "rebootRequired",
"errorScenarioDetails": [{
"errorValue": "ERR001001",
"errorUrl": "https://errors.contoso.com/errors/ERR001001"
}]
}],
"packageType": "exe",
}
En-têtes de réponse
En-tête | Valeur |
---|---|
X-Correlation-ID |
ID unique de type GUID pour chaque requête. Cela peut être partagé avec l’équipe de support technique pour analyser n’importe quel problème. |
Retry-After |
Temps en secondes pendant lequel le client doit attendre avant d’appeler à nouveau les API en raison de la limitation de débit. |
Paramètres de réponse
Nom | Type | Description |
---|---|---|
isSuccess | Boolean | |
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. |
responseData | Object | |
pollingUrl | Chaîne | [URL d’interrogation pour obtenir l’état de soumission en cas de soumission en cours] |
ongoingSubmissionId | Chaîne | [ID de soumission d’une soumission déjà en cours] |
Exemple de réponse
{
"isSuccess": true,
"errors": [{
"code": "badrequest",
"message": "Error Message 1",
"target": "listings"
}, {
"code": "warning",
"message": "Warning Message 1",
"target": "properties"
}],
"responseData": {
"pollingUrl": "/submission/v1/product/{productId}/submission/{submissionId}/status",
"ongoingSubmissionId": ""
}
}
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 | Description |
---|---|
productId | 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 | Type | Description |
---|---|---|
isSuccess | Boolean | |
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. |
responseData | Object | |
pollingUrl | Chaîne | [URL d’interrogation pour obtenir l’état du chargement ou de l’état de soumission du package en cas de soumission en cours] |
ongoingSubmissionId | Chaîne | [ID de 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 | Description |
---|---|
productId | L’ID de l’Espace partenaires du produit |
Paramètres de requête
Nom | Description |
---|---|
languages | [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 | Type | Description |
---|---|---|
isSuccess | Boolean | |
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. |
responseData | Object | |
listingAssets | 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 | |
id | Chaîne | |
assetUrl | Chaîne | Doit être un URL valide |
imageSize | Object | |
largeur | Integer | |
hauteur | Integer |
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 :
- 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.
- 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].
- 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.
- 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 | Description |
---|---|
productId | L’ID de l’Espace partenaires du produit |
En-têtes obligatoires
En-tête | Description |
---|---|
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 | Type | Description |
---|---|---|
langage | Chaîne | Obligatoire |
createAssetRequest | Object | Obligatoire |
Capture d'écran | Integer | Obligatoire si le fournisseur de logiciel indépendant doit mettre à jour des captures d’écran ou ajouter une nouvelle langue [1 - 10] |
Logo | Integer | 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 | Description |
---|---|
X-Correlation-ID |
ID unique de type GUID pour chaque requête. Cela peut être partagé avec l’équipe de support technique pour analyser n’importe quel problème. |
Retry-After |
Temps en secondes pendant lequel le client doit attendre avant d’appeler à nouveau les API en raison de la limitation de débit. |
Paramètres de réponse
Nom | Type | Description |
---|---|---|
isSuccess | Boolean | |
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. |
responseData | Object | |
listingAssets | Object | Objet contenant les détails du StoreLogos et des captures d’écran à charger |
langue | Chaîne | |
storeLogos | Tableau d’objets | |
captures d'écran | Tableau d’objets | |
id | Chaîne | |
primaryAssetUploadUrl | Chaîne | URL principale pour charger une ressource de référencement à l’aide de l’API REST Blob Azure |
secondaryAssetUploadUrl | Chaîne | URL secondaire pour charger une ressource de référencement à l’aide de l’API REST Blob Azure |
httpMethod | Méthode HTTP | La méthode HTTP doit être utilisée pour charger des ressources via les URL de chargement de ressources – principal ou secondaire |
httpHeaders | Object | 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 | Description |
---|---|
productId | L’ID de l’Espace partenaires du produit |
En-têtes obligatoires
En-tête | Description |
---|---|
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 | Type | Description |
---|---|---|
listingAssets | Object | |
langue | Chaîne | |
storeLogos | Tableau d’objet | |
captures d'écran | Tableau d’objet | |
id | Chaîne | Doit être un ID existant que l’utilisateur souhaite conserver à partir de l’API Obtenir les ressources de référencement actuelles ou un nouvel ID sous lequel une nouvelle ressource a été chargée dans l’API Créer des ressources de référencement. |
assetUrl | Chaîne | Doit être l’URL de l’élément multimédia existant que l’utilisateur souhaite conserver à partir de l’API Obtenir les ressources de référencement actuelles ou l’URL de chargement (principal ou secondaire) à l’aide de laquelle un nouvel élément multimédia a été chargé dans l’API Créer des ressources de référencement. Doit être un URL valide |
Exemple de demande
{
"listingAssets": {
"language": "en-us",
"storeLogos": [
{
"id": "1234567890abcdefgh",
"assetUrl": "https://contoso.com/blob=1234567890abcdefgh",
}
],
"screenshots": [
{
"id": "1234567891abcdefgh",
"assetUrl": "https://contoso.com/blob=1234567891abcdefgh",
}
]
}
}
En-têtes de réponse
En-tête | Description |
---|---|
X-Correlation-ID |
ID unique de type GUID pour chaque requête. Cela peut être partagé avec l’équipe de support technique pour analyser n’importe quel problème. |
Retry-After |
Temps en secondes pendant lequel le client doit attendre avant d’appeler à nouveau les API en raison de la limitation de débit. |
Paramètres de réponse
Nom | Type | Description |
---|---|---|
isSuccess | Boolean | |
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. |
responseData | Object | |
pollingUrl | Chaîne | URL d’interrogation pour obtenir l’état d’une soumission en cours |
ongoingSubmissionId | Chaîne | ID de soumission d’une soumission déjà en cours |
Exemple de réponse
{
"isSuccess": true,
"errors": [{
"code": "badrequest",
"message": "Error Message 1",
"target": "listings"
}, {
"code": "warning",
"message": "Warning Message 1",
"target": "properties"
}],
"responseData": {
"pollingUrl": "/submission/v1/product/{productId}/submission/{submissionId}/status",
"ongoingSubmissionId": ""
}
}
API d’interrogation de l’état du module
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 | Description |
---|---|
productId | L’ID de l’Espace partenaires du produit |
En-têtes obligatoires
En-tête | Description |
---|---|
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 | Description |
---|---|
X-Correlation-ID |
ID unique de type GUID pour chaque requête. Cela peut être partagé avec l’équipe de support technique pour analyser n’importe quel problème. |
Retry-After |
Temps en secondes pendant lequel le client doit attendre avant d’appeler à nouveau les API en raison de la limitation de débit. |
Paramètres de réponse
Nom | Type | Description |
---|---|---|
isSuccess | Boolean | |
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. |
responseData | Object | |
isReady | Boolean | Indique si tous les modules sont à l’état prêt, y compris le chargement de package |
ongoingSubmissionId | Chaîne | ID de soumission d’une soumission déjà en cours |
Exemple de réponse
{
"isSuccess": true,
"errors": [{
"code": "badrequest",
"message": "Error Message 1",
"target": "listings"
}, {
"code": "warning",
"message": "Warning Message 1",
"target": "properties"
}],
"responseData": {
"isReady": true,
"ongoingSubmissionId": ""
}
}
Créer une API de soumission
Crée une soumission à partir du brouillon actuel pour l’application MSI ou EXE. Les vérifications API :
- 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 | Description |
---|---|
productId | L’ID de l’Espace partenaires du produit |
En-têtes obligatoires
En-tête | Description |
---|---|
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 | Description |
---|---|
X-Correlation-ID |
ID unique de type GUID pour chaque requête. Cela peut être partagé avec l’équipe de support technique pour analyser n’importe quel problème. |
Retry-After |
Temps en secondes pendant lequel le client doit attendre avant d’appeler à nouveau les API en raison de la limitation de débit. |
Paramètres de réponse
Nom | Type | Description |
---|---|---|
isSuccess | Boolean | |
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. |
responseData | Object | |
pollingUrl | Chaîne | URL d’interrogation pour obtenir l’état de préparation du module, y compris le chargement du package pour la soumission |
submissionId | Chaîne | ID de la soumission nouvellement créée |
ongoingSubmissionId | Chaîne | ID de soumission d’une soumission déjà en cours |
Exemple de réponse
{
"isSuccess": true,
"errors": [{
"code": "badrequest",
"message": "Error Message 1",
"target": "listings"
}, {
"code": "warning",
"message": "Warning Message 1",
"target": "properties"
}],
"responseData": {
"submissionId": "1234567890",
"pollingUrl": "/submission/v1/product/{productId}/submission/{submissionId}/status",
"ongoingSubmissionId": ""
}
}
API d’interrogation de l’état de soumission
API pour 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 | Description |
---|---|
productId | L’ID de l’Espace partenaires du produit |
En-têtes obligatoires
En-tête | Description |
---|---|
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 | Description |
---|---|
X-Correlation-ID |
ID unique de type GUID pour chaque requête. Cela peut être partagé avec l’équipe de support technique pour analyser n’importe quel problème. |
Retry-After |
Temps en secondes pendant lequel le client doit attendre avant d’appeler à nouveau les API en raison de la limitation de débit. |
Paramètres de réponse
Nom | Type | Description |
---|---|---|
isSuccess | Boolean | |
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. |
responseData | Object | |
publishingStatus | Chaîne | État de publication de la soumission - [INPROGRESS, PUBLISHED, FAILED, UNKNOWN] |
hasFailed | Boolean | 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 [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.
Windows developer