API di invio a Microsoft Store per l'app MSI o EXE
Usare l'API di invio a Microsoft Store per l'app MSI o EXE per eseguire query a livello di codice e creare invii per le app MSI o EXE per l'account del Partner Center dell'organizzazione. Questa API è utile se l'account gestisce molte app e si desidera automatizzare e ottimizzare il processo di invio per queste risorse. Questa API usa Azure Active Directory (Azure AD) per autenticare le chiamate dall'app o dal servizio.
I passaggi seguenti descrivono il processo end-to-end di uso dell'API di invio di Microsoft Store:
- Assicurarsi di aver completato tutti i prerequisiti.
- Prima di chiamare un metodo nell'API di invio di Microsoft Store, ottenere un token di accesso di Azure AD. Dopo aver ottenuto un token, hai 60 minuti per usare questo token nelle chiamate all'API di invio a Microsoft Store prima della scadenza del token. Dopo la scadenza del token, è possibile generare un nuovo token.
- Richiamare l'API di invio a Microsoft Store per l'app MSI o EXE.
Passaggio 1: completare i prerequisiti per l'uso dell'API di invio a Microsoft Store
Prima di iniziare a scrivere il codice per richiamare l'API di invio a Microsoft Store per app MSI o EXE, verificare di aver completato i prerequisiti seguenti.
- L'utente o l'organizzazione deve disporre di una directory di Azure AD e dell'autorizzazione come amministratore aziendale per la directory. Se si usa già Microsoft 365 o altri servizi aziendali Microsoft, si dispone già di una directory di Azure AD. In caso contrario, è possibile creare una nuova directory di Azure AD nel Partner Center senza costi aggiuntivi.
- È necessario associare un'applicazione Azure AD all'account del Centro per i partner e ottenere l'ID tenant, l'ID client e la chiave. Questi valori sono necessari per ottenere un token di accesso di Azure AD, che sarà usato nelle chiamate all'API di invio di Microsoft Store.
- Preparare l'app per l'uso con l'API di invio a Microsoft Store:
- Se l'app non esiste ancora nel Partner Center, è necessario crearla riservandone il nome nel Partner Center. Non è possibile usare un API di invio a Microsoft Store per creare un'app nel Partner Center. È necessario lavorare nel Partner Center per crearla e quindi è possibile usare l'API per accedere all'app e creare invii per essa a livello di codice.
- Per poter creare un invio per una determinata app usando questa API, è innanzitutto necessario creare un invio per 'app nel Centro per i partner, includendo le risposte al questionario sulle classificazioni in base all'età. Dopo aver eseguito questa operazione, sarà possibile creare nuovi invii a livello di codice per questa app usando l'API.
- Se si sta creando o aggiornando un invio di un'app ed è necessario includere un nuovo pacchetto, preparare i dettagli del pacchetto.
- Se si sta creando o aggiornando un invio di un'app ed è necessario includere screenshot o immagini per la presentazione nello Store, preparare gli screenshot e le immagini dell'app.
Procedura di associazione di un'applicazione Azure AD all'account del Centro per i partner
Per poter usare l'API di invio a Microsoft Store per app MSI o EXE, è necessario associare un'applicazione Azure AD al proprio account del Partner Center, recuperare l'ID tenant e l'ID client per l'applicazione e generare una chiave. L'applicazione Azure AD rappresenta l'app o il servizio da cui si vuole chiamare l'API di invio di Microsoft Store. Per ottenere un token di accesso di Azure AD da passare all'API, sono necessari l'ID tenant, l'ID client e la chiave.
Nota
È sufficiente eseguire questa attività una sola volta. Quando si dispone di ID tenant, ID client e chiave, è possibile riutilizzarli ogni volta che è necessario creare un nuovo token di accesso Azure AD.
- Nel Centro per i partner, associare l'account del Centro per i partner dell'organizzazione alla directory di Azure AD dell'organizzazione.
- Quindi, dalla pagina Utenti nella sezione Impostazioni account del Centro per i partner, aggiungere l'applicazione Azure AD che rappresenta l'app o il servizio che verrà usato per accedere agli invii per l'account del Centro per i partner. Assicurarsi di assegnare a questa applicazione il ruolo di Manager. Se l'applicazione non esiste ancora nella directory di Azure AD, è possibile creare una nuova applicazione Azure AD nel Centro per i partner.
- Tornare alla pagina Utenti, fare clic sul nome dell'applicazione Azure AD per passare alle impostazioni e copiare i valori di ID tenant e ID client.
- Per aggiungere una nuova chiave o client segreto, vedere le istruzioni seguenti o fare riferimento alle istruzioni per registrare l'app tramite il portale Azure:
Per registrare l'app:
Accedi al portale di Azure.
Se si ha accesso a più tenant, usare il filtro Directory e sottoscrizioni nel menu in alto e passare al tenant in cui si vuole registrare l'applicazione.
Cerca e seleziona Azure Active Directory.
In Gestisci selezionare Registrazioni app, > quindi selezionare l'applicazione.
Selezionare Certificati & segreti > Segreti client > Nuovo segreto client.
Aggiungere una descrizione per il segreto client.
Selezionare una scadenza per il segreto o specificare una durata personalizzata.
La durata del segreto client è limitata a due anni (24 mesi) o meno. Non è possibile specificare una durata personalizzata di più di 24 mesi.
Nota
Microsoft consiglia di impostare un valore di scadenza inferiore a 12 mesi.
Selezionare Aggiungi.
Registrare il valore del segreto da usare nel codice dell'applicazione client. Questo valore del segreto non viene mai più visualizzato dopo aver lasciato questa pagina.
Passaggio 2: ottenere un token di accesso di Azure AD
Prima di chiamare un metodo nell'API di invio a Microsoft Store per app MSI o EXE, è necessario ottenere un token di accesso di Azure AD da passare all'intestazione Autorizzazione di ogni metodo nell'API. Dopo aver ottenuto un token di accesso, questo sarà disponibile per 60 minuti prima della scadenza. Dopo la scadenza del token, è possibile aggiornarlo in modo da continuare a usarlo nelle successive chiamate all'API.
Per ottenere il token di accesso, seguire le istruzioni in [Chiamate da servizio a servizio tramite credenziali client]/azure/active-directory/azuread-dev/v1-oauth2-client-creds-grant-flow) per inviare un POST HTTP all'endpoint https://login.microsoftonline.com/<tenant_id>/oauth2/token. Di seguito è riportata una richiesta di esempio.
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
Per il tenant_id
valore in POST URI e i parametri client_id
e client_secret
, specificare l'ID tenant, l'ID client e la chiave per l'applicazione recuperata dal Centro per i partner nella sezione precedente. Per il parametro ambito, è necessario specificare https://api.store.microsoft.com/.default
.
Dopo la scadenza del token di accesso, è possibile aggiornarlo seguendo le istruzioni riportate qui.
Per esempi che illustrano come ottenere un token di accesso usando C# o Node.js, vedere gli esempi di codice per l'API di invio a Microsoft Store per app MSI o EXE.
Passaggio 3: usare l''API di invio di Microsoft Store
Dopo aver ottenuto un token di accesso Azure AD, è possibile richiamare i metodi nell'API di invio a Microsoft Store per app MSI o EXE. L'API include molti metodi raggruppati in scenari per le app. Per creare o aggiornare invii, in genere si richiamano più metodi in un ordine specifico. Per informazioni su ogni scenario e sulla sintassi di ogni metodo, vedere le sezioni seguenti:
Nota
Dopo aver ottenuto un token di accesso, si hanno 60 minuti per richiamare i metodi nell'API di invio a Microsoft Store per app MSI o EXE prima della scadenza del token.
URL di base
L'URL di base per l'API di invio a Microsoft Store per app EXE o MSI è: https://api.store.microsoft.com
API Contracts
Ottenere API metadati di invio della bozza corrente
Recupera i metadati in ogni modulo (elenchi, proprietà o disponibilità) nell'invio della bozza attuale.
Percorso [Tutti i moduli]: /submission/v1/product/{productId}/metadata?languages={languages}&includelanguagelist={true/false}
Percorso [Modulo singolo]: /submission/v1/product/{productId}/metadata/{moduleName}?languages={languages}&includelanguagelist={true/false}
Metodo: GET
Parametri del percorso
Parametro | Descrizione |
---|---|
productId | ID del Partner Center del prodotto |
moduleName | Modulo del Partner Center: presentazioni, proprietà o disponibilità |
Parametri della query
Parametro | Descrizione |
---|---|
lingue | Facoltativo : le lingue in elenco vengono filtrate come stringa delimitata da virgole [limite massimo 200 lingue]. Se assente, vengono recuperati i primi 200 metadati delle lingue disponibili in elenco. [ad esempio: "en-us, en-gb"]. |
includelanguagelist | Valore booleano facoltativo: se true, restituisce l'elenco delle lingue aggiunte all'elenco e il relativo stato di completezza. |
Intestazioni obbligatorie
Intestazione | Valore |
---|---|
Authorization: Bearer <Token> |
ID dell'app Azure AD registrato con l'account del Partner Center |
X-Seller-Account-Id |
ID venditore dell'account del Partner Center |
Intestazioni di risposta
Intestazione | Valore |
---|---|
X-Correlation-ID |
ID univoco del tipo GUID per ogni richiesta. Questa operazione può essere condivisa con il team di supporto per l'analisi di qualsiasi problema. |
Retry-After |
Tempo in secondi che il client deve attendere prima di richiamare nuovamente le API a causa della limitazione della frequenza. |
Parametri di risposta
Nome | Tipo | Descrizione |
---|---|---|
accessibilitySupport | Booleano | |
additionalLicenseTerms | String | |
availability | Object | Dati del modulo di disponibilità |
category | String | Vedere l'elenco delle categorie riportato di seguito |
certificationNotes | String | |
codice | String | Il codice di errore del messaggio |
contactInfo | String | |
copyright | String | |
dependsOnDriversOrNT | Booleano | |
description | Stringa | |
developedBy | String | |
individuabilità | String | [DISCOVERABLE, DEEPLINK_ONLY] |
enableInFutureMarkets | Booleano | |
errori | Matrice di oggetti | Elenco di messaggi di errore o di avvertenza, se presenti |
freeTrial | String | [NO_FREE_TRIAL, FREE_TRIAL] |
hardwareItemType | String | |
isPrivacyPolicyRequired | Booleano | |
isRecommended | Booleano | |
isRequired | Booleano | |
isSuccess | Booleano | |
isSystemFeatureRequired | Matrice di oggetti | |
lingua | String | Visualizzare l'elenco delle lingue riportato di seguito |
presentazioni | Matrice di oggetti | Elencare i dati del modulo per ogni lingua |
mercati | Matrice di stringhe | Vedere l'elenco dei mercati di seguito |
messaggio | String | Descrizione dell'errore |
minimumHardware | String | |
minimumRequirement | String | |
penAndInkSupport | Booleano | |
prezzi | String | [FREE, FREEMIUM, SUBSCRIPTION, PAID] |
privacyPolicyUrl | String | |
productDeclarations | Object | |
productFeatures | Matrice di stringhe | |
proprietà | Object | Dati del modulo Proprietà |
recommendedHardware | String | |
recommendedRequirement | String | |
responseData | Object | Contiene il payload di risposta effettivo per la richiesta |
requisiti | Matrice di oggetti | |
searchTerms | Matrice di stringhe | |
shortDescription | String | |
sottocategoria | String | Vedere l'elenco delle sottocategorie riportato di seguito |
supportContactInfo | String | |
systemRequirementDetails | Matrice di oggetti | |
bersaglio | String | Entità da cui ha avuto origine l'errore |
sito web | String | |
whatsNew | String |
Risposta di esempio
{
"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}]
}
}
Aggiornare l'API dei metadati di invio bozza attuale
Aggiorna i metadati in ogni modulo sotto invi della bozza. Controlli dell'API
- Per Invio Active. Se esiste, errore con messaggio di errore.
- Se tutti i moduli sono in stato pronto per consentire l'operazione Salva bozza.
- Ogni campo nell'invio viene convalidato in base ai requisiti dello Store
- Regole di convalida dei dettagli dei requisiti di sistema:
- Valori consentiti in hardwareItemType = Memoria: 300 MB, 750 MB, 1 GB, 2 GB, 4 GB, 6 GB, 8 GB, 12 GB, 16 GB, 20 GB
- Valori consentiti in hardwareItemType = DirectX: DX9, DX10, DX11, DX12-FEATURELEVEL11, DX12-FEATURELEVEL12
- Valori consentiti in hardwareItemType = Video_Memory: 1 GB, 2 GB, 4 GB, 6 GB
Percorso [Aggiornamento modulo completo]: /submission/v1/product/{productId}/metadata
Metodo: PUT
Percorso [Aggiornamento patch modulo]: /submission/v1/product/{productId}/metadata
Metodo: PATCH
Comportamento API:
Nel caso dell'API di aggiornamento del modulo completo, è necessario che tutti i dati del modulo siano presenti nella richiesta di aggiornamento completo di ogni campo. Se il campo non è presente nella richiesta, viene usato il relativo valore predefinito per sovrascrivere il valore corrente per tale modulo specifico.
Nel caso dell'API di aggiornamento del modulo patch: solo i campi da aggiornare devono essere presenti nella richiesta. Questi valori di campo della Richiesta sovrascriveranno i valori esistenti, mantenendo tutti gli altri campi che non sono presenti nella Richiesta, come quello corrente per quel modulo specifico.
Parametri del percorso
Parametro | Descrizione |
---|---|
productId | ID del Partner Center del prodotto |
Intestazioni obbligatorie
Intestazione | Valore |
---|---|
Authorization: Bearer <Token> |
ID dell'app Azure AD registrato con l'account del Partner Center |
X-Seller-Account-Id |
ID venditore dell'account del Partner Center |
Parametri della richiesta
Nome | Tipo | Descrizione |
---|---|---|
availability | Object | Oggetto per contenere i metadati del modulo disponibilità |
mercati | Matrice di stringhe | Obbligatorio Vedere l'elenco dei mercati di seguito |
individuabilità | String | Obbligatorio [DISCOVERABLE, DEEPLINK_ONLY] |
enableInFutureMarkets | Booleano | Obbligatorio |
prezzi | String | Obbligatorio [FREE, FREEMIUM, SUBSCRIPTION, PAID] |
freeTrial | String | Obbligatorio se i prezzi sono in PAGAMENTO o ABBONAMENTO [NO_FREE_TRIAL, FREE_TRIAL] |
proprietà | Object | Oggetto in cui contenere i metadati del modulo proprietà |
isPrivacyPolicyRequired | Booleano | Obbligatorio |
privacyPolicyUrl | String | Obbligatorio se isPrivacyPolicyRequired = true Deve essere un URL valido |
sito web | String | Deve essere un URL valido |
supportContactInfo | String | Deve essere un indirizzo URL o un indirizzo e-mail valido |
certificationNotes | String | Consigliato Limite di caratteri = 2000 |
category | String | Obbligatorio Vedere l'elenco delle categorie di seguito |
sottocategoria | String | Obbligatorio Vedere l'elenco delle sottocategorie di seguito |
productDeclarations | Object | Obbligatorio |
isSystemFeatureRequired | Matrice di oggetti | [Touch, tastiera, mouse, fotocamera, NFC_HCE, NFC_Proximity, Bluetooth_LE, telefonia, microfono] |
isRequired | Booleano | Obbligatorio |
isRecommended | Booleano | Obbligatorio |
hardwareItemType | String | Obbligatorio |
systemRequirementDetails | Matrice di oggetti | [Processore, Grafica, Memoria, DirectX, Video_Memory] |
minimumRequirement | String | Obbligatorio per systemRequirementsText, lunghezza massima = 200 Valori consentiti in hardwareItemType = Memoria: [300 MB, 750 MB, 1 GB, 2 GB, 4 GB, 6 GB, 8 GB, 12 GB, 16 GB, 20 GB] Valori consentiti in hardwareItemType = DirectX: [DX9, DX10, DX11, DX12-FEATURELEVEL11, DX12-FEATURELEVEL12] Valori consentiti in hardwareItemType = Video_Memory: [1 GB, 2 GB, 4 GB, 6 GB] |
recommendedRequirement | String | Obbligatorio per systemRequirementsText, lunghezza massima = 200 Valori consentiti in hardwareItemType = Memoria: [300 MB, 750 MB, 1 GB, 2 GB, 4 GB, 6 GB, 8 GB, 12 GB, 16 GB, 20 GB] Valori consentiti in hardwareItemType = DirectX: [DX9, DX10, DX11, DX12-FEATURELEVEL11, DX12-FEATURELEVEL12] Valori consentiti in hardwareItemType = Video_Memory: [1 GB, 2 GB, 4 GB, 6 GB] |
dependsOnDriversOrNT | Booleano | Obbligatorio |
accessibilitySupport | Booleano | Obbligatorio |
penAndInkSupport | Booleano | Obbligatorio |
presentazioni | Object | Oggetto per elencare i dati del modulo per una singola lingua |
lingua | String | Obbligatorio Vedere l'elenco delle lingue seguenti |
description | Stringa | Obbligatorio Limite caratteri = 10000 |
whatsNew | String | Limite di caratteri = 1500 |
productFeatures | Matrice di stringa | 200 caratteri per funzionalità; Fino a 20 funzionalità |
shortDescription | String | Limite di caratteri = 1000 |
searchTerms | Matrice di stringa | 30 caratteri per termine di ricerca; Fino a 7 termini di ricerca 21 parole univoche in TOTALE in tutti i termini di ricerca |
additionalLicenseTerms | String | Obbligatorio Limite caratteri = 10000 |
copyright | String | Limite di caratteri = 200 |
developedBy | String | Limite di caratteri = 255 |
requisiti | Matrice di oggetti | 200 caratteri per voce; Fino a 11 voci in TOTALE tra minimo e consigliato] |
minimumHardware | String | Limite di caratteri = 200 |
recommendedHardware | String | Limite di caratteri = 200 |
contactInfo | String | Limite di caratteri = 200 |
listingsToAdd | Matrice di stringhe | Visualizzare l'elenco delle lingue riportato di seguito |
listingsToRemove | Matrice di stringhe | Visualizzare l'elenco delle lingue riportato di seguito |
Mercati
Mercato | Abbreviazione |
---|---|
Afghanistan | AF |
Albania | AL |
Algeria | DZ |
Samoa americane | AS |
Andorra | AD |
Angola | AO |
Anguilla | AI |
Antartide | AQ |
Antigua e Barbuda | AG |
Argentina | AR |
Armenia | Mattina |
Aruba | AW |
Australia | AU |
Austria | AT |
Azerbaigian | AZ |
Bahamas | BS |
Bahrein | BH |
Bangladesh | BD |
Barbados | BB |
Bielorussia | BY |
Belgio | BE |
Belize | BZ |
Benin | BJ |
Bermuda | BM |
Bhutan | BT |
Repubblica bolivariana del Venezuela | VE |
Bolivia | BO |
Bonaire | BQ |
Bosnia ed Erzegovina | BA |
Botswana | BW |
Isola Bouvet | BV |
Brasile | BR |
Territorio britannico dell’Oceano Indiano | IO |
Isole Vergini Britanniche | VG |
Brunei | BN |
Bulgaria | BG |
Burkina Faso | BF |
Burundi | BI |
Cambogia | KH |
Camerun | CA |
Canada | CA |
Capo Verde | CV |
Isole Cayman | KY |
Repubblica Centrafricana | CF |
Ciad | TD |
Cile | CL |
Cina | CN |
Isola Christmas | CX |
Isole Cocos (Keeling) | CC |
Colombia | CO |
Comore | KM |
Congo | CG |
Congo (RDC) | CD |
Isole Cook | CK |
Costa Rica | CR |
Croazia | HR |
Curaçao | CW |
Cipro | CY |
Repubblica Ceca | CZ |
Costa d'Avorio | CI |
Danimarca | DK |
Gibuti | DJ |
Dominica | DM |
Repubblica Dominicana | DO |
Ecuador | EC |
Egitto | EG |
El Salvador | SV |
Guinea Equatoriale | GQ |
Eritrea | ER |
Estonia | EE |
Etiopia | ET |
Isole Falkland | FK |
Isole Fær Øer | FO |
Figi | FJ |
Finlandia | FI |
Francia | FR |
Guyana francese | GF |
Polinesia Francese | PF |
Terre australi e antartiche francesi | TF |
Gabon | Disponibilità generale |
Gambia | GM |
Georgia | GE |
Germania | DE |
Ghana | GH |
Gibilterra | GI |
Grecia | GR |
Groenlandia | GL |
Grenada | GD |
Guadalupa | GP |
Guam | GU |
Guatemala | GT |
Guernsey | GG |
Guinea | GN |
Guinea-Bissau | GW |
Guyana | GY |
Haiti | HT |
Heard e McDonald | HM |
Città del Vaticano | VA |
Honduras | HN |
Hong Kong SAR | HK |
Ungheria | HU |
Islanda | IS |
India | IN |
Indonesia | ID |
Iraq | IQ |
Irlanda | Internet Explorer |
Israele | IL |
Italia | IT |
Giamaica | JM |
Giappone | JP |
Jersey | JE |
Giordania | JO |
Kazakistan | KZ |
Kenya | KE |
Kiribati | KI |
Corea del Sud | KR |
Kuwait | KW |
Kirghizistan | KG |
Laos | LA |
Lettonia | LV |
Libano | LB |
Lesotho | LS |
Liberia | LR |
Libia | LY |
Liechtenstein | LI |
Lituania | LT |
Lussemburgo | LU |
Macao SAR | MO |
Macedonia del Nord | MK |
Madagascar | MG |
Malawi | MW |
Malaysia | MY |
Maldive | MV |
Mali | ML |
Malta | MT |
Isola di Man | IM |
Isole Marshall | MH |
Martinica | MQ |
Mauritania | MR |
Mauritius | MU |
Mayotte | YT |
Messico | MX |
Micronesia | FM |
Moldavia | MD |
Monaco | MC |
Mongolia | MN |
Montenegro - ME | |
Montserrat | MS |
Marocco | MA |
Mozambico | MZ |
Myanmar | MM |
Namibia | ND |
Nauru | NR |
Nepal | NP |
Paesi Bassi | NL |
Nuova Caledonia | NC |
Nuova Zelanda | NZ |
Nicaragua | NI |
Niger | NE |
Nigeria | NG |
Niue | NU |
Isola Norfolk | NF |
Isole Marianne settentrionali | Punto di gestione (MP) |
Norvegia | NO |
Oman | OM |
Pakistan | PK |
Palau | PW |
Autorità Palestinese | PS |
Panama | PA |
Papua Nuova Guinea | PG |
Paraguay | PY |
Perù | PE |
Filippine | PH |
Isole Pitcairn | PN |
Polonia | PL |
Portogallo | PT |
Qatar | QA |
Riunione | RE |
Romania | RO |
Russia | RU |
Ruanda | RW |
Saint Barthélemy | BL |
Sant'Elena, Ascensione e Tristan da Cunha | SH |
Saint Kitts e Nevis | KN |
Saint Lucia | LC |
Saint Martin (Parte francese) | MF |
Saint Pierre e Miquelon | Pomeriggio |
Saint Vincent e Grenadine | VC |
Samoa | WS |
San Marino | SM |
Arabia Saudita | SA |
Senegal | SN |
Serbia | RS |
Seychelles | SC |
Sierra Leone | SL |
Singapore | SG |
Sint Maarten (Parte olandese) | SX |
Slovacchia | SK |
Slovenia | SI |
Isole Salomone | SB |
Somalia | SO |
Sudafrica | ZA |
Georgia del Sud e Sandwich Australi | GS |
Spagna | ES |
Sri Lanka | LK |
Suriname | SR |
Svalbard e Jan Mayen | SJ |
Swaziland | SZ |
Svezia | SE |
Svizzera | CH |
São Tomé e Príncipe | ST |
Taiwan | TW |
Tagikistan | TJ |
Tanzania | TZ |
Thailandia | TH |
Timor Leste | TL |
Tog - TG | |
Tokelau | TK |
Tonga | TO |
(Trinidad e Tobago) - TT | |
Tunisia | TN |
Türkiye | TR |
Turkmenistan | TM |
Isole Turks e Caicos | TC |
Tuvalu | TV |
Altre isole americane del Pacifico | UM |
U.S. Vergini Americane | VI |
Uganda | UG |
Ucraina | UA |
Emirati Arabi Uniti (EAU) | AE |
Regno Unito | GB |
Stati Uniti | Stati Uniti |
Uruguay | UY |
Uzbekistan | UZ |
Vanuatu | VU |
Vietnam | VN |
Wallis e Futuna | WF |
Yemen | YE |
Zambia | ZM |
Zimbabwe | ZW |
Isole Åland | AX |
Categorie e sottocategorie
Categoria | Sottocategorie |
---|---|
BooksAndReference | EReader, Fiction, Nonfiction, Riferimento |
Azienda | AccountingAndfinance, Collaboration, CRM, DataAndAnalytics, FileManagement, InventoryAndlogistics, LegalAndHR, ProjectManagement, RemoteDesktop, SalesAndMarketing, TimeAndExpenses |
DeveloperTools | Database, DesignTools, DevelopmentKits, Networking, ReferenceAndTraining, Servers, Utilities, WebHosting |
Istruzione | EducationBooksAndReference, EarlyLearning, InstructionalTools, Language, StudyAids |
Entertainment | (Nessuno) |
FoodAndDining | (Nessuno) |
GovernmentAndPolitics | (Nessuno) |
HealthAndFitness | (Nessuno) |
KidsAndFamily | KidsAndFamilyBooksAndReference, KidsAndFamilyEntertainment, HobbiesAndToys, SportsAndActivities, KidsAndFamilyTravel |
Lifestyle | Automotive, DYI, HomeAndGarden, Relationships, SpecialInterest, StyleAndFashion |
Medical | (Nessuno) |
MultimediaDesign | IllustrationAndGraphicDesign, MusicProduction, PhotoAndVideoProduction |
Musica | (Nessuno) |
NavigationAndMaps | (Nessuno) |
NewsAndWeather | Notizie, meteo |
PersonalFinance | BankingAndInvestments, BudgetingAndTaxes |
Personalization | RingtonesAndSounds, themes, WallpaperAndLockScreens |
PhotoAndVideo | (Nessuno) |
Produttività | (Nessuno) |
Sicurezza | PCProtection, PersonalSecurity |
Acquisti | (Nessuno) |
Social | (Nessuno) |
Sport | (Nessuno) |
Viaggi | CityGuides, Hotels |
UtilitiesAndTools | BackupAndManage, FileManager |
Lingue
Nome della lingua | Codici lingua supportati |
---|---|
Afrikaans | af, af-za |
Albanese | sq, sq-al |
Amharico | am, am-et |
Armeno | hy, hy-am |
Assamese | as, as-in |
Azero | az-arab, az-arab-az, az-cyrl, az-cyrl-az, az-latn, az-latn-az |
Basco (Province basche) | eu, eu-es |
Bielorusso | be, be-by |
Bengalese | bn, bn-bd, bn-in |
Bosniaco | bs, bs-cyrl, bs-cyrl-ba, bs-latn, bs-latn-ba |
Bulgaro | bg, bg-bg |
Catalano | ca, ca-es, ca-es-valencia |
Cherokee | chr-cher, chr-cher-us, chr-latn |
Cinese semplificato | zh-Hans, zh-cn, zh-hans-cn, zh-sg, zh-hans-sg |
Cinese tradizionale | 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 |
Croato | hr, hr-hr, hr-ba |
Ceco | cs, cs-cz |
Danese | da, da-dk |
Dari | prs, prs-af, prs-arab |
Olandese | nl, nl-nl, nl-be |
italiano | 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 |
Estone | et, et-ee |
Filippino - fil, fil-latn, fil-ph | |
Finlandese | fi, fi-fi |
Francese | 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 |
Galiziano | gl, gl-es |
Georgiano | ka, ka-ge |
Tedesco | de, de-at, de-ch, de-de, de-lu, de-li |
Greco | el, el-gr |
Gujarati | gu, gu-in |
Hausa | ha, ha-latn, ha-latn-ng |
Ebraico | he, he-il |
Hindi | hi, hi-in |
Ungherese | hu, hu-hu |
Islandese | is, is-is |
Igb - ig-latn, ig-ng | |
Indonesiano | id, id-id |
Inuktitut (Latino) | iu-cans, iu-latn, iu-latn-ca |
Irlandese | ga, ga-ie |
isiXhosa | xh, xh-za |
isiZulu | zu, zu-za |
Italiano | it, it-it, it-ch |
Giapponese | ja, ja-jp |
Kannada | kn, kn-in |
Kazako | kk, kk-kz |
Khmer | km, km-kh |
K'iche' | quc-latn, qut-gt, qut-latn |
Kinyarwanda | rw, rw-rw |
KiSwahili | sw, sw-ke |
Konkani | kok, kok-in |
Coreano | ko, ko-kr |
Curdo | ku-arab, ku-arab-iq |
Kirghiso | ky-kg, ky-cyrl |
Lao | lo, lo-la |
Lettone | lv, lv-lv |
Lituano | lt, lt-lt |
Lussemburghese | lb, lb-lu |
Macedone | mk, mk-mk |
Malese | ms, ms-bn, ms-my |
Malayalam | ml, ml-in |
Maltese | mt, mt-mt |
Maori | mi, mi-latn, mi-nz |
Marathi | mr, mr-in |
Mongolo (cirillico) | mn-cyrl, mn-mong, mn-mn, mn-phag |
Nepalese | ne, ne-np |
Norvegese | nb, nb-no, nn, nn-no, no, no-no |
Odia | or, or-in |
Persiano | fa, fa-ir |
Polacco | pl, pl-pl |
Portoghese (Brasile) | pt-br |
Portoghese (Portogallo) | pt, pt-pt |
Punjabi | pa, pa-arab, pa-arab-pk, pa-deva, pa-in |
Quechua | quz, quz-bo, quz-ec, quz-pe |
Rumeno | ro, ro-ro |
Russo | ru, ru-ru |
Scozzese Gaelico | gd-gb, gd-latn |
Serbo (alfabeto latino) | sr-Latn, sr-latn-cs, sr, sr-latn-ba, sr-latn-me, sr-latn-rs |
Serbo (alfabeto cirillico) | sr-cyrl, sr-cyrl-ba, sr-cyrl-cs, sr-cyrl-me, sr-cyrl-rs |
Sotho del nord | nso, nso-za |
Setswana | tn, tn-bw, tn-za |
Sindhi | sd-arab, sd-arab-pk, sd-deva |
Sinhala | si, si-lk |
Slovacco | sk, sk-sk |
Sloveno | sl, sl-si |
Spagnolo | 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 |
Svedese | sv, sv-se, sv-fi |
Tagico (cirillico) | tg-arab, tg-cyrl, tg-cyrl-tj, tg-latn |
Tamil | ta, ta-in |
Tataro | tt-arab, tt-cyrl, tt-latn, tt-ru |
Telugu | te, te-in |
Thai | th, th-th |
Tigrino | ti, ti-et |
Turco | tr, tr-tr |
Turkmeno | tk-cyrl, tk-latn, tk-tm, tk-latn-tr, tk-cyrl-tr |
Ucraino | uk, uk-ua |
Urdu | ur, ur-pk |
Uiguro | ug-arab, ug-cn, ug-cyrl, ug-latn |
Uzbeco (alfabeto latino) | uz, uz-cyrl, uz-latn, uz-latn-uz |
Vietnamita | vi, vi-vn |
Gallese | cy, cy-gb |
Wolof | wo, wo-sn |
Yoruba | yo-latn, yo-ng |
Richiesta di esempio
{
"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"]
}
Intestazioni di risposta
Intestazione | Valore |
---|---|
X-Correlation-ID |
ID univoco del tipo GUID per ogni richiesta. Questa operazione può essere condivisa con il team di supporto per l'analisi di qualsiasi problema. |
Retry-After |
Tempo in secondi che il client deve attendere prima di richiamare nuovamente le API a causa della limitazione della frequenza |
Parametri di risposta
Nome | Tipo | Descrizione |
---|---|---|
isSuccess | Booleano | |
errori | Matrice di oggetti | Elenco di messaggi di errore o di avvertenza, se presenti |
codice | String | Il codice di errore del messaggio |
messaggio | String | Descrizione dell'errore |
bersaglio | String | Entità da cui ha avuto origine l'errore |
responseData | Object | Contiene il payload di risposta effettivo per la richiesta |
pollingUrl | String | URL di polling per ottenere lo stato di qualsiasi invio in corso |
ongoingSubmissionId | String | ID invio di qualsiasi invio già in corso |
Risposta di esempio
{
"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": ""
}
}
Get Current Draft Packages API
Recupera i dettagli del pacchetto nell'invio corrente della bozza.
Percorso [Tutti i pacchetti]: /submission/v1/product/{productId}/packages
Metodo: GET
Percorso [Pacchetto singolo]: /submission/v1/product/{productId}/packages/{packageId}
Metodo: GET
Parametri del percorso
Nome | Descrizione |
---|---|
productId | ID del Partner Center del prodotto |
packageId | ID univoco del pacchetto da recuperare |
Intestazioni obbligatorie
Intestazione | Valore |
---|---|
Authorization: Bearer <Token> |
Uso dell'ID dell'app Azure AD registrato con l'account del Partner Center |
X-Seller-Account-Id |
ID venditore dell'account del Partner Center |
Intestazioni di risposta
Intestazione | Valore |
---|---|
X-Correlation-ID |
ID univoco del tipo GUID per ogni richiesta. Questa operazione può essere condivisa con il team di supporto per l'analisi di qualsiasi problema. |
Retry-After |
Tempo in secondi che il client deve attendere prima di richiamare nuovamente le API a causa della limitazione della frequenza. |
Parametri di risposta
Nome | Tipo | Descrizione |
---|---|---|
isSuccess | Booleano | |
errori | Matrice di oggetti | Elenco di messaggi di errore o di avvertenza, se presenti |
codice | String | Il codice di errore del messaggio |
messaggio | String | Descrizione dell'errore |
bersaglio | String | Entità da cui ha avuto origine l'errore |
responseData | Object | |
packages | Matrice di oggetti | Oggetto per contenere i dati del modulo del pacchetto |
packageId | String | |
packageUrl | String | |
lingue | Matrice di stringhe | |
architetture | Matrice di stringhe | [Neutral, X86, X64, Arm, Arm64] |
isSilentInstall | Booleano | Questo valore deve essere contrassegnato come true se il programma di installazione viene eseguito in modalità invisibile all'utente senza richiedere commutatori o false |
installerParameters | String | |
genericDocUrl | String | |
errorDetails | Matrice di oggetti | |
errorScenario | String | |
errorScenarioDetails | Matrice di oggetti | |
errorValue | String | |
errorUrl | String | |
packageType | String |
Risposta di esempio
{
"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",
}]
}
}
Aggiornare l'API Current Draft Packages
Aggiorna i dettagli del pacchetto nell'invio corrente della bozza.
Percorso [Aggiornamento modulo completo]: /submission/v1/product/{productId}/packages
Metodo: PUT
Percorso [Aggiornamento patch pacchetto singolo]: /submission/v1/product/{productId}/packages/{packageId}
Metodo: PATCH
Comportamento API:
Nel caso dell'API di aggiornamento del modulo completo, è necessario che tutti i dati dei pacchetti siano presenti nella richiesta di aggiornamento completo di ogni campo. Se il campo non è presente nella richiesta, viene usato il relativo valore predefinito per sovrascrivere il valore corrente per tale modulo specifico. Ciò comporta la sovrascrittura di tutti i pacchetti esistenti con un nuovo set di pacchetti dalla richiesta. Ciò comporterà la rigenerazione degli ID pacchetto e l'utente deve chiamare l'API GET Packages per gli ID pacchetto più recenti.
Nel caso dell'API aggiornamento patch pacchetto singolo: solo i campi da aggiornare per un determinato pacchetto devono essere presenti nella richiesta. Questi valori di campo della richiesta sovrascriveranno i valori esistenti, mantenendo tutti gli altri campi che non sono presenti nella richiesta, come quello corrente per quel pacchetto specifico. Gli altri pacchetti nel set rimangono invariati.
Parametri del percorso
Nome | Descrizione |
---|---|
productId | ID del Partner Center del prodotto |
packageId | L'ID univoco del pacchetto |
Intestazioni obbligatorie
Intestazione | Valore |
---|---|
Authorization: Bearer <Token> |
Uso dell'ID dell'app Azure AD registrato con l'account del Partner Center |
X-Seller-Account-Id |
ID venditore dell'account del Partner Center |
Parametri della richiesta
Nome | Tipo | Descrizione |
---|---|---|
packages | Matrici di oggetti | Oggetto per contenere i dati del modulo del pacchetto [Obbligatorio solo per l'aggiornamento completo del modulo] |
packageUrl | String | Obbligatorio |
lingue | Matrice di stringhe | Obbligatorio |
architetture | Matrice di stringhe | Obbligatorio Dovrebbe contenere un'architettura singola - Neutro, X86, X64, Arm, Arm64 |
isSilentInstall | Booleano | Necessario Questo valore deve essere contrassegnato come true se il programma di installazione viene eseguito in modalità invisibile all'utente senza richiedere commutatori o false |
installerParameters | String | Obbligatorio se isSilentInstall è false |
genericDocUrl | String | Obbligatorio se packageType è exe Link al documento contenente i dettagli dei codici di errore personalizzati per il programma di installazione del tipo EXE |
errorDetails | Matrici di oggetti | Metadati per contenere codici di errore personalizzati e dettagli per i programmi di installazione di tipo EXE. |
errorScenario | String | Identificare lo scenario di errore specifico. [installationCancelledByUser, applicationAlreadyExists, installationAlreadyInProgress, diskSpaceIsFull, rebootRequired, networkFailure, packageRejectedDuringInstallation, installationSuccessful, miscellaneous] |
errorScenarioDetails | Matrici di oggetti | |
errorValue | String | Codice di errore che può essere presente durante l'installazione |
errorUrl | String | URL per informazioni dettagliate sull'errore |
packageType | String | Obbligatorio [exe, msi] |
Richiesta di esempio [aggiornamento completo del modulo]
{
"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",
}]
}
Richiesta di esempio [Aggiornamento patch pacchetto singolo]
{
"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",
}
Intestazioni di risposta
Intestazione | Valore |
---|---|
X-Correlation-ID |
ID univoco del tipo GUID per ogni richiesta. Questa operazione può essere condivisa con il team di supporto per l'analisi di qualsiasi problema. |
Retry-After |
Tempo in secondi che il client deve attendere prima di richiamare nuovamente le API a causa della limitazione della frequenza. |
Parametri di risposta
Nome | Tipo | Descrizione |
---|---|---|
isSuccess | Booleano | |
errori | Matrice di oggetti | [Elenco di messaggi di errore o di avvertenza, se presenti] |
codice | String | Il codice di errore del messaggio |
messaggio | String | Descrizione dell'errore |
bersaglio | String | Entità da cui ha avuto origine l'errore |
responseData | Object | |
pollingUrl | String | [URL di polling per ottenere lo stato dell'invio in caso di invio già in corso] |
ongoingSubmissionId | String | [ID invio di qualsiasi invio già in corso] |
Risposta di esempio
{
"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 pacchetti commit
Esegue il commit del nuovo set di pacchetti aggiornato usando le API di aggiornamento dei pacchetti nell'invio bozza corrente. Questa API restituisce un URL di polling per tenere traccia del caricamento del pacchetto.
Percorso: /submission/v1/product/{productId}/packages/commit
Metodo: POST
Parametri del percorso
Nome | Descrizione |
---|---|
productId | ID del Partner Center del prodotto |
Intestazioni obbligatorie
Intestazione | Valore |
---|---|
Authorization: Bearer <Token> |
Uso dell'ID dell'app App AD registrato con l'account del Partner Center |
X-Seller-Account-Id |
ID venditore dell'account del Partner Center |
Intestazioni di risposta
Intestazione | Valore |
---|---|
X-Correlation-ID |
ID univoco del tipo GUID per ogni richiesta. Questa operazione può essere condivisa con il team di supporto per l'analisi di qualsiasi problema. |
Retry-After |
Tempo in secondi che il client deve attendere prima di richiamare nuovamente le API a causa della limitazione della frequenza. |
Parametri di risposta
Nome | Tipo | Descrizione |
---|---|---|
isSuccess | Booleano | |
errori | Matrice di oggetti | [Elenco di messaggi di errore o di avvertenza, se presenti] |
codice | String | Il codice di errore del messaggio |
messaggio | String | Descrizione dell'errore |
bersaglio | String | Entità da cui ha avuto origine l'errore |
responseData | Object | |
pollingUrl | String | [URL di polling per ottenere lo stato di caricamento o invio del pacchetto in caso di invio già in corso] |
ongoingSubmissionId | String | [ID invio di qualsiasi invio già in corso] |
Risposta di esempio
{
"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": ""
}
}
Ottenere l'API corrente di listato bozza di asset
Recupera i dettagli dell'asset di inserzione sotto l'invio della bozza corrente.
Percorso: /submission/v1/product/{productId}/listings/assets?languages={languages}
Metodo: GET
Parametri del percorso
Nome | Descrizione |
---|---|
productId | ID del Partner Center del prodotto |
Parametri della query
Nome | Descrizione |
---|---|
lingue | [Facoltativo] le lingue in elenco vengono filtrate come stringa delimitata da virgole [limite massimo 200 lingue]. Se assente, vengono recuperati i primi 200 dati relativi alle risorse della lingua di presentazione disponibili. (per es, “en-us, en-gb") |
Intestazioni obbligatorie
Intestazione | Valore |
---|---|
Authorization: Bearer <Token> |
Uso dell'ID dell'app App AD registrato con l'account del Partner Center |
X-Seller-Account-Id |
ID venditore dell'account del Partner Center |
Intestazioni di risposta
Intestazione | Valore |
---|---|
X-Correlation-ID |
ID univoco del tipo GUID per ogni richiesta. Questa operazione può essere condivisa con il team di supporto per l'analisi di qualsiasi problema. |
Retry-After |
Tempo in secondi che il client deve attendere prima di richiamare nuovamente le API a causa della limitazione della frequenza. |
Parametri di risposta
Nome | Tipo | Descrizione |
---|---|---|
isSuccess | Booleano | |
errori | Matrice di oggetti | Elenco di messaggi di errore o di avvertenza, se presenti |
codice | String | Il codice di errore del messaggio |
messaggio | String | Descrizione dell'errore |
bersaglio | String | Entità da cui ha avuto origine l'errore |
responseData | Object | |
listingAssets | Matrice di oggetti | Elencare i dettagli dell'asset per ogni lingua |
lingua | String | |
storeLogos | Matrice di oggetti | |
screenshot | Matrice di oggetti | |
id | String | |
assetUrl | String | Deve essere un URL valido |
imageSize | Object | |
width | Intero | |
height | Intero |
Risposta di esempio
{
"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
}
}
]
}]
}
}
Crea API elenco di asset
Crea un nuovo caricamento asset elenco nell'invio della bozza corrente.
Aggiornamento degli asset di presentazione
L'API per l'invio in Microsoft Store per l'app EXE o MSI usa URL SAS generati da runtime nei Blob Store per ogni singolo caricamento di asset immagine, insieme a una chiamata API Commit dopo che il caricamento ha esito positivo. Per poter aggiornare gli asset di presentazione e, a sua volta, per poter aggiungere/rimuovere le impostazioni locali nel modulo di presentazione, è possibile usare l'approccio seguente:
- Usare l'API Crea asset di presentazione per inviare richieste relative al caricamento degli asset insieme a lingua, tipo e numero di asset.
- In base al numero di asset richiesti, gli ID asset vengono creati su richiesta e creerebbero un URL di firma di accesso condiviso a breve termine e lo inviano nuovamente nel corpo della risposta nel tipo di asset. È possibile usare questo URL per caricare asset immagine di tipo specifico usando client HTTP [Put Blob (API REST) - Archiviazione di Azure | Microsoft Docs].
- Dopo il caricamento, è possibile usare l'API Commit Listing Assets per inviare anche le nuove informazioni sull'ID risorsa ricevute in precedenza dalla chiamata API precedente. L'API singola esegue il commit interno dei dati dell'elenco degli asset dopo la convalida.
- Questo approccio sovrascrive efficacemente l'intero set di immagini precedenti del tipo di asset in una lingua specifica che viene inviata nella richiesta. Di conseguenza, gli asset caricati in precedenza verranno rimossi.
Percorso: /submission/v1/product/{productId}/listings/assets/create
Metodo: POST
Parametri del percorso
Nome | Descrizione |
---|---|
productId | ID del Partner Center del prodotto |
Intestazioni obbligatorie
Intestazione | Descrizione |
---|---|
Authorization: Bearer <Token> |
Uso dell'ID dell'app App AD registrato con l'account del Partner Center |
X-Seller-Account-Id |
ID venditore dell'account del Partner Center |
Parametri della richiesta
Nome | Tipo | Descrizione |
---|---|---|
lingua | String | Obbligatorio |
createAssetRequest | Object | Obbligatorio |
Schermata | Intero | Obbligatorio se ISV deve aggiornare gli screenshot o aggiungere una nuova lingua di presentazione [1 - 10] |
Logo | Intero | Obbligatorio se ISV deve aggiornare i loghi o aggiungere una nuova lingua di presentazione [1 o 2] |
Intestazioni di risposta
Intestazione | Descrizione |
---|---|
X-Correlation-ID |
ID univoco del tipo GUID per ogni richiesta. Questa operazione può essere condivisa con il team di supporto per l'analisi di qualsiasi problema. |
Retry-After |
Tempo in secondi che il client deve attendere prima di richiamare nuovamente le API a causa della limitazione della frequenza. |
Parametri di risposta
Nome | Tipo | Descrizione |
---|---|---|
isSuccess | Booleano | |
errori | Matrice di oggetti | Elenco di messaggi di errore o di avvertenza, se presenti |
codice | String | Il codice di errore del messaggio |
messaggio | String | Descrizione dell'errore |
bersaglio | String | Entità da cui ha avuto origine l'errore |
responseData | Object | |
listingAssets | Object | Oggetto contenente i dettagli di StoreLogos e Screenshot da caricare |
lingua | String | |
storeLogos | Matrice di oggetti | |
screenshot | Matrice di oggetti | |
id | String | |
primaryAssetUploadUrl | String | URL principale per caricare l'asset di presentazione con l'API REST Blob Azure |
secondaryAssetUploadUrl | String | URL secondario per caricare l'asset di presentazione con l'API REST Blob Azure |
httpMethod | Metodo HTTP | Il metodo HTTP deve essere usato per caricare gli asset tramite gli URL di caricamento asset , principale o secondario |
httpHeaders | Object | Oggetto con chiavi come intestazioni obbligatorie da presentare nella chiamata API di caricamento degli asset agli URL di caricamento degli asset. Se il valore non è vuoto, le intestazioni devono avere valori specifici. In caso contrario, i valori vengono calcolati durante la chiamata API. |
Risposta di esempio
{
"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"}
}]
}
}
}
Commit Listing Assets API
Esegue il commit del nuovo asset di presentazione caricato usando i dettagli dell'API Crea asset nell'invio bozza corrente.
Percorso: /submission/v1/product/{productId}/listings/assets/commit
Metodo: PUT
Parametri del percorso
Nome | Descrizione |
---|---|
productId | ID del Partner Center del prodotto |
Intestazioni obbligatorie
Intestazione | Descrizione |
---|---|
Authorization: Bearer <Token> |
Uso dell'ID dell'app App AD registrato con l'account del Partner Center |
X-Seller-Account-Id |
ID venditore dell'account del Partner Center |
Parametri della richiesta
Nome | Tipo | Descrizione |
---|---|---|
listingAssets | Object | |
lingua | String | |
storeLogos | Matrici oggetto | |
screenshot | Matrici oggetto | |
id | String | Deve essere un ID esistente che l'utente vuole rendere persistente dall'API Recupera asset di presentazione corrente o nuovo ID con cui è stato caricato un nuovo asset nell'API Crea asset di presentazione. |
assetUrl | String | Deve essere l'URL dell'asset esistente che l'utente vuole rendere persistente dall'API Recupera asset di presentazione corrente o dall'URL di caricamento - Principale o Secondario, usando il quale è stato caricato un nuovo asset nell'API Crea asset di presentazione. Deve essere un URL valido |
Richiesta di esempio
{
"listingAssets": {
"language": "en-us",
"storeLogos": [
{
"id": "1234567890abcdefgh",
"assetUrl": "https://contoso.com/blob=1234567890abcdefgh",
}
],
"screenshots": [
{
"id": "1234567891abcdefgh",
"assetUrl": "https://contoso.com/blob=1234567891abcdefgh",
}
]
}
}
Intestazioni di risposta
Intestazione | Descrizione |
---|---|
X-Correlation-ID |
ID univoco del tipo GUID per ogni richiesta. Questa operazione può essere condivisa con il team di supporto per l'analisi di qualsiasi problema. |
Retry-After |
Tempo in secondi che il client deve attendere prima di richiamare nuovamente le API a causa della limitazione della frequenza. |
Parametri di risposta
Nome | Tipo | Descrizione |
---|---|---|
isSuccess | Booleano | |
errori | Matrice di oggetti | Elenco di messaggi di errore o di avvertenza, se presenti |
codice | String | Il codice di errore del messaggio |
messaggio | String | Descrizione dell'errore |
bersaglio | String | Entità da cui ha avuto origine l'errore |
responseData | Object | |
pollingUrl | String | URL di polling per ottenere lo stato di qualsiasi invio in corso |
ongoingSubmissionId | String | ID invio di qualsiasi invio già in corso |
Risposta di esempio
{
"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 di polling dello stato del modulo
API per verificare l'idoneità del modulo prima di poter creare l'invio. Convalida anche lo stato di caricamento del pacchetto.
Percorso: /submission/v1/product/{productId}/status
Metodo: GET
Parametri del percorso
Nome | Descrizione |
---|---|
productId | ID del Partner Center del prodotto |
Intestazioni obbligatorie
Intestazione | Descrizione |
---|---|
Authorization: Bearer <Token> |
Uso dell'ID dell'app App AD registrato con l'account del Partner Center |
X-Seller-Account-Id |
ID venditore dell'account del Partner Center |
Intestazioni di risposta
Intestazione | Descrizione |
---|---|
X-Correlation-ID |
ID univoco del tipo GUID per ogni richiesta. Questa operazione può essere condivisa con il team di supporto per l'analisi di qualsiasi problema. |
Retry-After |
Tempo in secondi che il client deve attendere prima di richiamare nuovamente le API a causa della limitazione della frequenza. |
Parametri di risposta
Nome | Tipo | Descrizione |
---|---|---|
isSuccess | Booleano | |
errori | Matrice di oggetti | Elenco di messaggi di errore o di avvertenza, se presenti |
codice | String | Il codice di errore del messaggio |
messaggio | String | Descrizione dell'errore |
bersaglio | String | Entità da cui ha avuto origine l'errore |
responseData | Object | |
isReady | Booleano | Indica se tutti i moduli sono in stato pronto, incluso il caricamento del pacchetto |
ongoingSubmissionId | String | ID invio di qualsiasi invio già in corso |
Risposta di esempio
{
"isSuccess": true,
"errors": [{
"code": "badrequest",
"message": "Error Message 1",
"target": "listings"
}, {
"code": "warning",
"message": "Warning Message 1",
"target": "properties"
}],
"responseData": {
"isReady": true,
"ongoingSubmissionId": ""
}
}
API di creazione dell'invio
Crea un invio dalla bozza corrente per l'app MSI o EXE. Controlli dell'API:
- per l'invio attivo e ha esito negativo con messaggio di errore se esiste un invio attivo.
- se tutti i moduli sono in stato pronto per creare l'invio.
- ogni campo nell'invio viene convalidato in base ai requisiti dello Store
Percorso:/submission/v1/product/{productId}/submit
Metodo: POST
Parametri del percorso
Nome | Descrizione |
---|---|
productId | ID del Partner Center del prodotto |
Intestazioni obbligatorie
Intestazione | Descrizione |
---|---|
Authorization: Bearer <Token> |
Uso dell'ID dell'app App AD registrato con l'account del Partner Center |
X-Seller-Account-Id |
ID venditore dell'account del Partner Center |
Intestazioni di risposta
Intestazione | Descrizione |
---|---|
X-Correlation-ID |
ID univoco del tipo GUID per ogni richiesta. Questa operazione può essere condivisa con il team di supporto per l'analisi di qualsiasi problema. |
Retry-After |
Tempo in secondi che il client deve attendere prima di richiamare nuovamente le API a causa della limitazione della frequenza. |
Parametri di risposta
Nome | Tipo | Descrizione |
---|---|---|
isSuccess | Booleano | |
errori | Matrice di oggetti | Elenco di messaggi di errore o di avvertenza, se presenti |
codice | String | Il codice di errore del messaggio |
messaggio | String | Descrizione dell'errore |
bersaglio | String | Entità da cui ha avuto origine l'errore |
responseData | Object | |
pollingUrl | String | URL di polling per ottenere lo stato di idoneità del modulo, incluso il caricamento del pacchetto per l'invio |
submissionId | String | ID per l'invio appena creato |
ongoingSubmissionId | String | ID invio di qualsiasi invio già in corso |
Risposta di esempio
{
"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 di polling dello stato dell'invio
API per controllare lo stato di invio.
Percorso: /submission/v1/product/{productId}/submission/{submissionId}/status
Metodo: GET
Parametri del percorso
Nome | Descrizione |
---|---|
productId | ID del Partner Center del prodotto |
Intestazioni obbligatorie
Intestazione | Descrizione |
---|---|
Authorization: Bearer <Token> |
Uso dell'ID dell'app App AD registrato con l'account del Partner Center |
X-Seller-Account-Id |
ID venditore dell'account del Partner Center |
Intestazioni di risposta
Intestazione | Descrizione |
---|---|
X-Correlation-ID |
ID univoco del tipo GUID per ogni richiesta. Questa operazione può essere condivisa con il team di supporto per l'analisi di qualsiasi problema. |
Retry-After |
Tempo in secondi che il client deve attendere prima di richiamare nuovamente le API a causa della limitazione della frequenza. |
Parametri di risposta
Nome | Tipo | Descrizione |
---|---|---|
isSuccess | Booleano | |
errori | Matrice di oggetti | Elenco di messaggi di errore o di avvertenza, se presenti |
codice | String | Il codice di errore del messaggio |
messaggio | String | Descrizione dell'errore |
bersaglio | String | Entità da cui ha avuto origine l'errore |
responseData | Object | |
publishingStatus | String | Stato di pubblicazione dell'invio - [INPROGRESS, PUBLISHED, FAILED, UNKNOWN] |
hasFailed | Booleano | Indica se la pubblicazione non è riuscita e non verrà ritentata |
Risposta di esempio
{
"isSuccess": true,
"errors": [{
"code": "badrequest",
"message": "Error Message 1",
"target": "listings"
}, {
"code": "warning",
"message": "Warning Message 1",
"target": "properties"
}],
"responseData": {
"publishingStatus": "INPROGRESS",
"hasFailed": false
}
}
Esempi di codice
Gli articoli seguenti forniscono esempi di codice dettagliati che illustrano come usare l'API di invio di Microsoft Store in linguaggi di programmazione diversi:
Esempio C#: API di invio a Microsoft Store per l'app MSI o EXE
Questo articolo fornisce esempi di codice C# che illustrano come usare l'API di invio di Microsoft Store per l'app MSI o EXE. È possibile esaminare ogni esempio per altre informazioni sull'attività illustrata oppure compilare tutti gli esempi di codice in questo articolo in un'applicazione da console.
Prerequisiti Questi esempi usano la libreria seguente:
- Pacchetto NuGet Newtonsoft.Json da Newtonsoft.
Programma principale L'esempio seguente implementa un programma da riga di comando che chiama gli altri metodi di esempio di questo articolo per illustrare diversi modi di uso dell'API di invio di Microsoft Store. Per adattare questo programma per l'uso personale:
- Assegnare la proprietà SellerId all'ID venditore dell'account del Partner Center.
- Assegnare la proprietà ApplicationId all'ID dell'app che si vuole gestire.
- Assegnare le proprietà ClientId e ClientSecret all'ID client e alla chiave per l'app e sostituire la stringa tenantid nell'URL TokenEndpoint con l'ID tenant dell'app. Per altre informazioni, vedere Come associare un'applicazione Azure AD all'account del Centro per i partner
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 helper ClientConfiguration con C#
L'app di esempio usa la classe helper ClientConfiguration per passare i dati di Azure Active Directory e i dati dell'app a ogni metodo di esempio che usa l'API di invio di 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" ba3c223b-03ab-4a44-aa32-38aa10c27e32
/// </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; }
}
}
Creare un invio di app usando C#
L'esempio seguente implementa una classe che usa diversi metodi nell'API di invio di Microsoft Store per aggiornare un invio di un'app.
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 helper di IngestionClient con C#
La classe IngestionClient fornisce metodi helper che vengono usati da altri metodi nella stessa app di esempio per eseguire le attività seguenti:
- Ottenere il token di accesso di Azure AD che può essere usato per chiamare metodi nell'API di invio di Microsoft Store. Dopo aver ottenuto un token, hai 60 minuti per usare questo token nelle chiamate all'API di invio a Microsoft Store prima della scadenza del token. Dopo la scadenza del token, è possibile generare un nuovo token.
- Elaborare le richieste HTTP per l'API di invio di 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" ba3c223b-03ab-4a44-aa32-38aa10c27e32</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;
}
}
}
Esempio Node.js: API di invio a Microsoft Store per l'app MSI o EXE
Questo articolo fornisce esempi di codice Node.js che illustrano come usare l'API di invio di Microsoft Store per l'app MSI o EXE. È possibile esaminare ogni esempio per altre informazioni sull'attività illustrata oppure compilare tutti gli esempi di codice in questo articolo in un'applicazione da console.
Prerequisiti Questi esempi usano la libreria seguente:
- node-fetch v2 [npm install node-fetch@2]
Creare un invio di app usando node.js
L'esempio seguente chiama gli altri metodi di esempio in questo articolo per illustrare diversi modi per usare l'API di invio a Microsoft Store. Per adattare questo programma per l'uso personale:
- Assegnare la proprietà SellerId all'ID venditore dell'account del Partner Center.
- Assegnare la proprietà ApplicationId all'ID dell'app che si vuole gestire.
- Assegnare le proprietà ClientId e ClientSecret all'ID client e alla chiave per l'app e sostituire la stringa tenantid nell'URL TokenEndpoint con l'ID tenant dell'app. Per altre informazioni, vedere Come associare un'applicazione Azure AD all'account del Centro per i partner
L'esempio seguente implementa una classe che usa diversi metodi nell'API di invio di Microsoft Store per aggiornare un invio di un'app.
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();
Helper ClientConfiguration
L'app di esempio usa la classe helper ClientConfiguration per passare i dati di Azure Active Directory e i dati dell'app a ogni metodo di esempio che usa l'API di invio di 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;
Helper di IngestionClient con node.js
La classe IngestionClient fornisce metodi helper che vengono usati da altri metodi nella stessa app di esempio per eseguire le attività seguenti:
- Ottenere il token di accesso di Azure AD che può essere usato per chiamare metodi nell'API di invio di Microsoft Store. Dopo aver ottenuto un token, hai 60 minuti per usare questo token nelle chiamate all'API di invio a Microsoft Store prima della scadenza del token. Dopo la scadenza del token, è possibile generare un nuovo token.
- Elaborare le richieste HTTP per l'API di invio di 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;
Informazioni aggiuntive
Per eventuali domande sull'API di invio di Microsoft Store o per assistenza nella gestione degli invii con questa API, usare le risorse seguenti:
- Porre le domande sui nostri forum.
- Visitare la nostra pagina di supporto e richiedere una delle opzioni di assistenza del Centro per i partner. Se viene richiesto di scegliere un tipo di problema e una categoria, scegliere rispettivamente Invio e certificazione di un'app e Invio di un'app.