API de Envio da Microsoft Store para aplicativos MSI ou EXE
Use a API de envio da Microsoft Store para aplicativos MSI ou EXE para consultar e criar envios programaticamente para aplicativos MSI ou EXE para sua conta na Central de Parceiros ou da sua organização. Essa API é útil caso sua conta gerencie muitos aplicativos e você queira automatizar e otimizar o processo de envio desses ativos. Essa API usa o Azure Active Directory (Azure AD) para autenticar as chamadas do aplicativo ou serviço.
As etapas a seguir descrevem o processo de uso ponta a ponta da API de envio da Microsoft Store:
- Verifique se todos os pré-requisitos foram atendidos.
- Antes de chamar um método na API de envio da Microsoft Store, obtenha um token de acesso do Azure AD. Depois de obter um token, você tem 60 minutos para usá-lo em chamadas para a API de envio da Microsoft Store antes que ele expire. Depois que o token expirar, será possível gerar um novo.
- Chamar a API de Envio da Microsoft Store para aplicativos MSI ou EXE.
Etapa 1: concluir os pré-requisitos para usar a API de envio da Microsoft Store
Antes de começar a escrever o código para chamar a API de envio da Microsoft Store para aplicativos MSI ou EXE, verifique se os pré-requisitos a seguir foram atendidos.
- Você (ou sua organização) deve ter um diretório do Azure AD e você deve ter permissão de Administrador global para o diretório. Se já usa o Microsoft 365 ou outros serviços empresariais da Microsoft, você já tem o diretório do Azure AD. Caso contrário, crie um Azure AD na Central de Parceiros sem custo adicional.
- Associe um aplicativo do Azure AD à sua conta da Central de Parceiros e obtenha a ID do locatário, a ID do cliente e a chave. Esses valores são necessários para obter um token de acesso do Azure AD, que será usado em chamadas para a API de envio da Microsoft Store.
- Prepare seu aplicativo para uso com a API de envio da Microsoft Store:
- Se seu aplicativo ainda não existir na Central de Parceiros, você deverá criá-lo reservando seu nome na Central de Parceiros. Não é possível usar a API de envio da Microsoft Store para criar um aplicativo na Central de Parceiros; você deve trabalhar na Central de Parceiros para criá-lo e, depois disso, pode usar a API para acessar o aplicativo e criar envios programaticamente para ele.
- Antes de criar um envio para um determinado aplicativo usando essa API, você deve primeiro criar um envio para o aplicativo no Partner Center, incluindo responder ao questionário de classificações etárias. Depois de fazer isso, você poderá criar programaticamente envios para esse aplicativo usando a API.
- Se você estiver criando ou atualizando um envio de aplicativo e precisar incluir um novo pacote, prepare os detalhes do pacote.
- Se você estiver criando ou atualizando um envio de aplicativo e precisar incluir capturas de tela ou imagens para a listagem da Store, prepare as capturas de tela e imagens do aplicativo.
Como associar um aplicativo do Azure AD à sua conta da Central de Parceiros
Para usar a API de envio da Microsoft Store para aplicativos MSI ou EXE, você deve associar um aplicativo do Azure AD à sua conta da Central de Parceiros, recuperar a ID do locatário e a ID do cliente do aplicativo e gerar uma chave. O aplicativo do Azure AD representa o aplicativo ou serviço do qual você deseja chamar a API de envio da Microsoft Store. Você precisa da ID do locatário, da ID do cliente e da chave para obter um token de acesso do Azure AD que é passado para a API.
Observação
É necessário executar essa tarefa apenas uma vez. Depois de obter a ID do locatário, a ID do cliente e a chave, você poderá reutilizá-las sempre que precisar criar um novo token de acesso do Azure AD.
- Na Central de Parceiros, associe a conta da Central de Parceiros da sua organização ao diretório do Azure AD da sua organização.
- Em seguida, na página Usuários na seção Configurações da conta da Central de Parceiros, adicione o aplicativo do Azure AD que representa o aplicativo ou serviço que você usará para acessar os envios para sua conta da Central de Parceiros. Lembre-se de atribuir esse aplicativo à função de Gerenciador. Se o aplicativo ainda não existir no diretório do Azure AD, crie um novo aplicativo do Azure AD na Central de Parceiros.
- Retorne à página Usuários, clique no nome do seu aplicativo do Azure AD para acessar as configurações do aplicativo e copie os valores de ID do Locatário e ID do Cliente.
- Para adicionar uma nova chave ou segredo do cliente, confira as instruções a seguir ou confira as instruções para registrar o aplicativo por meio do Portal do Azure:
Para registrar seu aplicativo:
Entre no portal do Azure.
Se você tem acesso a vários locatários, use o filtro Diretórios + assinaturas no menu superior para mudar para o locatário no qual você deseja registrar o aplicativo.
Pesquise Azure Active Directory e selecione-o.
Em Gerenciar, selecione Registros de aplicativo > Selecionar seu aplicativo.
Selecione Certificados e segredos > Segredos do cliente > Novo segredo do cliente.
Adicione uma descrição para o segredo do cliente.
Selecione uma data de expiração para o segredo ou especifique um tempo de vida personalizado.
O tempo de vida do segredo do cliente é limitado a dois anos (24 meses) ou menos. Você não pode especificar um tempo de vida personalizado por mais de 24 meses.
Observação
A Microsoft recomenda definir um valor de expiração inferior a 12 meses.
Selecione Adicionar.
Registre o valor do segredo para uso no código do aplicativo cliente. Esse valor secreto nunca será exibido novamente depois que você sair dessa página.
Etapa 2: obter um token de acesso do Azure AD
Antes de chamar qualquer um dos métodos na API de envio da Microsoft Store para o aplicativo Microsoft ou EXE, primeiro você deve obter um token de acesso do Azure AD que é passado para o cabeçalho de Autorização de cada método na API. Após obter um token de acesso, você tem 60 minutos para usá-lo antes dele expirar. Depois de expirar, é possível renovar o token para que você possa continuar a usá-lo em chamadas futuras para a API.
Para obter o token de acesso, siga as instruções em [Service to Service Calls Using Client Credentials]/azure/active-directory/azuread-dev/v1-oauth2-client-creds-grant-flow) para enviar um HTTP POST para o ponto de extremidade https://login.microsoftonline.com/<tenant_id>/oauth2/token. Confira a seguir um exemplo de solicitação.
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
Para o valor tenant_id
no URI POST e nos parâmetros client_id
e client_secret
, especifique a ID do locatário, a ID do cliente e a chave do aplicativo recuperado da Central de Parceiros na seção anterior. Para o parâmetro de escopo, especifique https://api.store.microsoft.com/.default
.
Depois que o token de acesso expirar, você poderá renová-lo seguindo as instruções aqui.
Para obter exemplos que demonstram como obter um token de acesso usando C# ou Node.js, confira os exemplos de código da API de envio da Microsoft Store para aplicativos MSI ou EXE.
Etapa 3: Uso da API de envio da Microsoft Store
Depois de obter um token de acesso do Azure AD, você pode chamar métodos na API de envio da Microsoft Store para aplicativos MSI ou EXE. A API inclui muitos métodos que são agrupados em cenários para aplicativos. Para criar ou atualizar envios, normalmente chamam-se vários métodos em uma ordem específica. Para obter informações sobre cada cenário e a sintaxe de cada método, confira as seguintes seções:
Observação
Depois de obter um token de acesso, você tem 60 minutos para usá-lo em chamadas para a API de envio da Microsoft Store para aplicativos MSI ou EXE antes que ele expire.
URL base
A URL base para API de Envio da Microsoft Store para aplicativos MSI ou EXE é: https://api.store.microsoft.com
Contratos de API
Obter a API de metadados de envio de escalação atual
Busca metadados em cada módulo (listagens, propriedades ou disponibilidade) no envio de escalação atual.
Caminho [Todos os módulos]: /submission/v1/product/{productId}/metadata?languages={languages}&includelanguagelist={true/false}
Caminho [Módulo único]: /submission/v1/product/{productId}/metadata/{moduleName}?languages={languages}&includelanguagelist={true/false}
Método: OBTER
Parâmetros de caminho
Parâmetro | Descrição |
---|---|
productId | A ID da Central de Parceiros do produto |
moduleName | Módulo Central de Parceiros – listagens, propriedades ou disponibilidade |
Parâmetros de consulta
Parâmetro | Descrição |
---|---|
idiomas | Opcional Os idiomas de listagem filtram como sequência separada por vírgulas [limite de até 200 idiomas]. Se ausentes, os primeiros 200 metadados de idiomas de listagem disponíveis serão recuperados. [ por exemplo, "en-US, en-GB"]. |
includelanguagelist | Booliano opcional – se verdadeiro, retorna a lista de idiomas de listagem adicionados e seu status de completude. |
Cabeçalhos necessários
Cabeçalho | Valor |
---|---|
Authorization: Bearer <Token> |
A ID do aplicativo Azure AD registrada com a conta da Central de Parceiros |
X-Seller-Account-Id |
A ID do vendedor da conta da Central de Parceiros |
Cabeçalhos de resposta
Cabeçalho | Valor |
---|---|
X-Correlation-ID |
O GUID tipo ID exclusivo para cada solicitação. Pode ser compartilhado com a equipe de suporte para analisar qualquer issue. |
Retry-After |
O tempo, em segundos, que o cliente precisa esperar antes de chamar as APIs novamente devido à limitação de fluxo. |
Parâmetros de resposta
Nome | Tipo | Descrição |
---|---|---|
accessibilitySupport | Booliano | |
additionalLicenseTerms | String | |
availability | Objeto | Dados do módulo de disponibilidade |
category | String | Confira a lista de categorias abaixo |
certificationNotes | String | |
código | String | O código de erro da mensagem |
contactInfo | String | |
copyright | String | |
dependsOnDriversOrNT | Booliano | |
descrição | String | |
desenvolvido por | String | |
detectabilidade | String | [DETECTÁVEL, DEEPLINK_ONLY] |
enableInFutureMarkets | Booliano | |
erros | Matriz de objetos | A lista de mensagens de aviso ou de erro, se houver |
freeTrial | String | [NO_FREE_TRIAL, FREE_TRIAL] |
hardwareItemType | String | |
isPrivacyPolicyRequired | Booliano | |
isRecommended | Booliano | |
IsRequired | Booliano | |
isSuccess | Booliano | |
isSystemFeatureRequired | Matriz de objetos | |
linguagem | String | Confira a lista de idiomas abaixo |
listagens | Matriz de objetos | Dados do módulo de listagens para cada idioma |
mercados | Matriz das cadeias de caracteres | Confira a lista de mercados abaixo |
message | String | A descrição do erro |
minimumHardware | String | |
minimumRequirement | String | |
penAndInkSupport | Booliano | |
preços | String | [GRATUITO, FREEMIUM, ASSINATURA, PAGO] |
privacyPolicyUrl | String | |
productDeclarations | Objeto | |
productFeatures | Matriz das cadeias de caracteres | |
properties | Objeto | Dados do módulo de propriedades |
recommendedHardware | String | |
recommendedRequirement | String | |
responseData | Objeto | Contém payload de resposta real para a solicitação |
requisitos | Matriz de objetos | |
searchTerms | Matriz das cadeias de caracteres | |
shortDescription | String | |
subcategory | String | Confira a lista de subcategorias abaixo |
supportContactInfo | String | |
systemRequirementDetails | Matriz de objetos | |
destino | String | A entidade que originou o erro |
website | String | |
novidades | String |
Resposta de exemplo
{
"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}]
}
}
Atualizar a API de metadados de envio de escalação atual
Atualiza os metadados em cada módulo no envio de escalação. A API verifica
- Para envio ativo. Se existir, falha com mensagem de erro.
- Se todos os módulos estiverem no status pronto para permitir a operação Salvar rascunho.
- Cada campo no envio é validado de acordo com os requisitos da Store
- Regras de validação dos detalhes do requisito do sistema:
- Valores permitidos em hardwareItemType = Memória: 300MB, 750MB, 1GB, 2GB, 4GB, 6GB, 8GB, 12GB, 16GB, 20GB
- Valores permitidos em hardwareItemType = DirectX: DX9, DX10, DX11, DX12-FEATURELEVEL11, DX12-FEATURELEVEL12
- Valores permitidos em hardwareItemType = Video_Memory: 1GB, 2GB, 4GB, 6GB
Caminho [Atualização completa de módulo]: /submission/v1/product/{productId}/metadata
Método: PUT
Caminho [Atualização de patch de módulo]: /submission/v1/product/{productId}/metadata
Método: PATCH
Comportamento da API
No caso da API de Atualização Completa de Módulo – todos os dados de módulo precisam estar presentes na solicitação de atualização completa de cada campo. Qualquer campo que não esteja presente na solicitação, seu valor padrão é usado para substituir o valor atual desse módulo específico.
No caso da API de Atualização do Módulo de Patch – apenas os campos que devem ser atualizados precisam estar presentes na solicitação. Esses valores de campo da Solicitação substituirão os valores existentes, mantendo todos os outros campos que não estão presentes na solicitação, iguais aos atuais para esse módulo específico.
Parâmetros de caminho
Parâmetro | Descrição |
---|---|
productId | A ID da Central de Parceiros do produto |
Cabeçalhos necessários
Cabeçalho | Valor |
---|---|
Authorization: Bearer <Token> |
A ID do aplicativo Azure AD registrada com a conta da Central de Parceiros |
X-Seller-Account-Id |
A ID do vendedor da conta da Central de Parceiros |
Parâmetros de solicitação
Nome | Tipo | Descrição |
---|---|---|
availability | Objeto | Objeto para armazenar os metadados do Módulo de Disponibilidade |
mercados | Matriz das cadeias de caracteres | Obrigatório Confira a lista de mercados abaixo |
detectabilidade | String | Obrigatório [DETECTÁVEL, DEEPLINK_ONLY] |
enableInFutureMarkets | Booliano | Obrigatório |
preços | String | Obrigatório [FREE, FREEMIUM, SUBSCRIPTION, PAID] |
freeTrial | String | Obrigatório se o preço for PAGO ou ASSINATURA [NO_FREE_TRIAL, FREE_TRIAL] |
properties | Objeto | Objeto para armazenar os metadados do módulo de propriedades |
isPrivacyPolicyRequired | Booliano | Obrigatório |
privacyPolicyUrl | String | Obrigatório se isPrivacyPolicyRequired = true Deve ser uma URL válida |
website | String | Deve ser um URL válido |
supportContactInfo | String | Deve ser um URL ou end. email válido |
certificationNotes | String | Limite recomendado de caracteres = 2.000 |
category | String | Obrigatório Confira a lista de categorias abaixo |
subcategory | String | Obrigatório Confira a lista de subcategorias abaixo |
productDeclarations | Objeto | Obrigatório |
isSystemFeatureRequired | Matriz de objetos | [Toque, Teclado, Mouse, Câmera, NFC_HCE, NFC_Proximity, Bluetooth_LE, Telefonia, Microfone] |
IsRequired | Booliano | Obrigatório |
isRecommended | Booliano | Obrigatório |
hardwareItemType | String | Obrigatório |
systemRequirementDetails | Matriz de objetos | [Processador, Gráficos, Memória, DirectX Video_Memory] |
minimumRequirement | String | Obrigatório para systemRequirementsText, MaxLength = 200 Valores permitidos em hardwareItemType = Memória: [300MB, 750MB, 1GB, 2GB, 4GB, 6GB, 8GB, 12GB, 16GB, 20GB] Valores permitidos em hardwareItemType = DirectX: [DX9, DX10, DX11, DX12-FEATURELEVEL11, DX12-FEATURELEVEL12] Valores permitidos em hardwareItemType = Video_Memory: [1GB, 2GB, 4GB, 6GB] |
recommendedRequirement | String | Obrigatório para systemRequirementsText, MaxLength = 200 Valores permitidos em hardwareItemType = Memória: [300MB, 750MB, 1GB, 2GB, 4GB, 6GB, 8GB, 12GB, 16GB, 20GB] Valores permitidos em hardwareItemType = DirectX: [DX9, DX10, DX11, DX12-FEATURELEVEL11, DX12-FEATURELEVEL12] Valores permitidos em hardwareItemType = Video_Memory: [1GB, 2GB, 4GB, 6GB] |
dependsOnDriversOrNT | Booliano | Obrigatório |
accessibilitySupport | Booliano | Obrigatório |
penAndInkSupport | Booliano | Obrigatório |
listagens | Objeto | Objeto para listar os dados de módulo de um único idioma |
linguagem | String | Obrigatório Confira a lista de idiomas abaixo |
descrição | String | Limite obrigatório de caracteres = 10.000 |
novidades | String | Limite de caracteres = 1.500 |
productFeatures | Matriz de sequência | 200 caracteres por recurso; até 20 recursos |
shortDescription | String | Limite de caracteres = 1.000 |
searchTerms | Matriz de sequência | 30 caracteres por termo de pesquisa; até 7 termos de pesquisa TOTAL de 21 palavras únicas em todos os termos de pesquisa |
additionalLicenseTerms | String | Limite obrigatório de caracteres = 10.000 |
copyright | String | Limite de caracteres = 200 |
desenvolvido por | String | Limite de caracteres = 255 |
requisitos | Matriz de objetos | 200 caracteres por item; TOTAL de até 11 itens entre o mínimo e o recomendado] |
minimumHardware | String | Limite de caracteres = 200 |
recommendedHardware | String | Limite de caracteres = 200 |
contactInfo | String | Limite de caracteres = 200 |
listagensToAdd | Matriz das cadeias de caracteres | Confira a lista de idiomas abaixo |
listagensToRemove | Matriz das cadeias de caracteres | Confira a lista de idiomas abaixo |
Mercados
Mercado | Abreviação |
---|---|
Afeganistão | AF |
Albânia | AL |
Argélia | DZ |
Samoa Americana | AS |
Andorra | AD |
Angola | AO |
Anguila | IA |
Antártica | AQ |
Antígua e Barbuda | AG |
Argentina | AR |
Armênia | AM |
Aruba | AW |
Austrália | AU |
Áustria | AT |
Azerbaijão | AZ |
Bahamas | BS |
Bahrein | BH |
Bangladesh | BD |
Barbados | BB |
Bielorrússia | BY |
Bélgica | BE |
Belize | BZ |
Benin | BJ |
Bermudas | BM |
Butão | BT |
República Bolivariana da Venezuela | VE |
Bolívia | BO |
Bonaire | BQ |
Bósnia e Herzegovina | BA |
Botsuana | BW |
Ilha Bouvet | BV |
Brasil | BR |
Território Britânico do Oceano Índico | IO |
Ilhas Virgens Britânicas | VG |
Brunei | BN |
Bulgária | BG |
Burquina Faso | BF |
Burundi | BI |
Camboja | KH |
Camarões | CM |
Canadá | CA |
Cabo Verde | CV |
Ilhas Cayman | KY |
República Centro-Africana | CF |
Chade | TD |
Chile | CL |
China | CN |
Ilha Christmas | CX |
Ilhas Cocos (Keeling) | CC |
Colômbia | CO |
Comores | KM |
Congo | CG |
Congo (RDC) | CD |
Ilhas Cook | CK |
Costa Rica | CR |
Croácia | RH |
Curaçao | CW |
Chipre | CY |
República Tcheca | CZ |
Côte d’Ivoire | CI |
Dinamarca | DK |
Djibuti | DJ |
Dominica | DM |
República Dominicana | O QUE FAZER |
Equador | EC |
Egito | EG |
El Salvador | SV |
Guiné Equatorial | GQ |
Eritreia | ER |
Estônia | EE |
Etiópia | ET |
Ilhas Malvinas | FK |
Ilhas Faroé | FO |
Fiji | FJ |
Finlândia | FI |
França | FR |
Guiana Francesa | GF |
Polinésia Francesa | PF |
Terras Austrais e Antárticas Francesas | TF |
Gabão | GA |
Gâmbia | GM |
Geórgia | GE |
Alemanha | DE |
Gana | GH |
Gibraltar | GI |
Grécia | GR |
Groenlândia | GL |
Granada | GD |
Guadalupe | GP |
Guam | GU |
Guatemala | GT |
Guernsey | GG |
Guiné | GN |
Guiné-Bissau | GW |
Guiana | GY |
Haiti | HT |
Ilhas Heard e McDonald | HM |
Cidade do Vaticano | VA |
Honduras | HN |
RAE de Hong Kong | HK |
Hungria | HU |
Islândia | IS |
Índia | IN |
Indonésia | ID |
Iraque | IQ |
Irlanda | IE |
Israel | IL |
Itália | IT |
Jamaica | JM |
Japão | JP |
Jersey | JE |
Jordan | JO |
Cazaquistão | KZ |
Quênia | KE |
Quiribati | KI |
Coreia do Sul | KR |
Kuwait | KW |
Quirguistão | KG |
Laos | LA |
Letônia | LV |
Líbano | LB |
Lesoto | LS |
Libéria | LR |
Líbia | LY |
Liechtenstein | LI |
Lituânia | LT |
Luxemburgo | LU |
RAE de Macau | MO |
Macedônia do Norte | MK |
Madagascar | MG |
Malaui | MW |
Malásia | MY |
Maldivas | MV |
Mali | ML |
Malta | MT |
Ilha de Man | IM |
Ilhas Marshall | MH |
Martinica | MQ |
Mauritânia | MR |
Maurício | MU |
Mayotte | YT |
México | MX |
Micronésia | FM |
Moldova | MD |
Mônaco | MC |
Mongólia | MN |
Montenegr - ME | |
Montserrat | MS |
Marrocos | MA |
Moçambique | MZ |
Myanmar | MM |
Namíbia | NA |
Nauru | NR |
Nepal | NP |
Países Baixos | NL |
Nova Caledônia | NC |
Nova Zelândia | NZ |
Nicarágua | NI |
Níger | NE |
Nigéria | NG |
Niue | NU |
Ilha Norfolk | NF |
Ilhas Marianas do Norte | MP |
Noruega | NO |
Omã | OM |
Paquistão | PK |
Palau | PW |
Autoridade Palestina | PS |
Panamá | PA |
Papua-Nova Guiné | PG |
Paraguai | PY |
Peru | PE |
Filipinas | PH |
Ilhas Pitcairn | PN |
Polônia | PL |
Portugal | PT |
Qatar | QA |
Reunião | RE |
Romênia | RO |
Rússia | RU |
Ruanda | RW |
São Bartolomeu | BL |
Santa Helena, Ascensão e Tristão da Cunha | SH |
São Cristóvão e Nevis | KN |
Santa Lúcia | LC |
Saint Martin (parte francesa) | MF |
São Pedro e Miquelon | PM |
São Vicente e Granadinas | VC |
Samoa | WS |
San Marino | SM |
Arábia Saudita | SA |
Senegal | SN |
Sérvia | RS |
Seicheles | SC |
Serra Leoa | SL |
Singapura | SG |
Sint Maarten (parte holandesa) | SX |
Eslováquia | SK |
Eslovênia | SI |
Ilhas Salomão | SB |
Somália | SO |
África do Sul | ZA |
Ilhas Geórgia do Sul e Sandwich do Sul | GS |
Espanha | ES |
Sri Lanka | LK |
Suriname | SR |
Svalbard e Jan Mayen | SJ |
Suazilândia | SZ |
Suécia | SE |
Suíça | CH |
São Tomé e Príncipe | ST |
Taiwan | TW |
Tadjiquistão | TJ |
Tanzânia | TZ |
Tailândia | TH |
Timor-Leste | TL |
Tog - TG | |
Tokelau | TK |
Tonga | TO |
Trinidad e Tobago - TT | |
Tunísia | TN |
Turquia | TR |
Turcomenistão | TM |
Ilhas Turcas e Caicos | TC |
Tuvalu | TV |
EUA Ilhas Menores Distantes | UM |
Ilhas Virgens Americanas | VI |
Uganda | UG |
Ucrânia | UA |
Emirados Árabes Unidos | AE |
Reino Unido | GB |
Estados Unidos | EUA |
Uruguai | UY |
Uzbequistão | UZ |
Vanuatu | VU |
Vietnã | VN |
Wallis e Futuna | WF |
Iêmen | YE |
Zâmbia | ZM |
Zimbábue | ZW |
Ilhas Aland | AX |
Categorias e subcategorias
Categoria | Subcategorias |
---|---|
Livros e Referência | EReader, Ficção, Não-ficção, Referência |
Negócios | Contabilidade e finanças, colaboração, CRM, dados e análises, gerenciamento de arquivos, inventário e logística, jurídico e RH, gerenciamento de projetos, desktop remoto, vendas e marketing, tempo e despesas |
DeveloperTools | Banco de Dados, ferramentas de design, Kits de Desenvolvimento, Redes, Referência e Treinamento, Servidores, Utilitários, WebHosting |
Education | Educação, livros e referências, aprendizagem precoce, ferramentas instrucionais, idiomas, materiais de estudo |
Entretenimento | (Nenhuma) |
FoodAndDining | (Nenhuma) |
Governo e política | (Nenhuma) |
Saúde e fitness | (Nenhuma) |
Crianças e família | Crianças e Família, Livros e Referência, Crianças, Família e Entretenimento, Hobbies e brinquedos, Esportes e atividades, Crianças, Família e Viagem |
Estilo de vida | Automotivo, DYI, Casa e jardim, Relacionamentos, Interesse especial, Moda e estilo |
Médicos | (Nenhuma) |
Design multimídia | Ilustração e design gráfico, Produção musical, Produção de foto e vídeo |
Música | (Nenhuma) |
Navegação e mapas | (Nenhuma) |
Notícias e meteorologia | Notícias e Meteorologia |
Finanças Pessoais | Bancos e investimentos, Orçamento e impostos |
Personalização | Toques e sons, temas, papéis de parede e telas de bloqueio |
Foto e vídeo | (Nenhuma) |
Produtividade | (Nenhuma) |
Segurança | Proteção de PC, Segurança pessoal |
Compras | (Nenhuma) |
Social | (Nenhuma) |
Esportes | (Nenhuma) |
Viagem | Guias da cidades, Hotéis |
Utilitários e ferramentas | Backup e gerenciamento, Gerenciador de arquivos |
Idiomas
Nome do idioma | Códigos de idioma com suporte |
---|---|
Africâner | af, af-za |
Albanês | sq, sq-al |
Amárico | am, am-et |
Armênia | hy, hy-am |
Assamês | as, as-in |
Azerbaidjano | az-arab, az-arab-az, az-cyrl, az-cyrl-az, az-latn, az-latn-az |
Basco (País Basco) | eu, eu-es |
Bielorrusso | be, be-by |
Bangla | bn, bn-bd, bn-in |
Bósnio | bs, bs-cyrl, bs-cyrl-ba, bs-latn, bs-latn-ba |
Búlgaro | bg, bg-bg |
Catalão | ca, ca-es, ca-es-valencia |
Cherokee | chr-cher, chr-cher-us, chr-latn |
Chinês (simplificado) | zh-Hans, zh-cn, zh-hans-cn, zh-sg, zh-hans-sg |
Chinês (tradicional) | 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 |
Croata | hr, hr-hr, hr-ba |
Tcheco | cs, cs-cz |
Dinamarquês | da, da-dk |
Dari | prs, prs-af, prs-arab |
Holandês | nl, nl-nl, nl-be |
Inglês | 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 |
Estoniano | et, et-ee |
Filipino - fil, fil-latn, fil-ph | |
Finlandês | fi, fi-fi |
Francês | 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 |
Galego | gl, gl-es |
Georgiano | ka, ka-ge |
Alemão | de, de-at, de-ch, de-de, de-lu, de-li |
Grego | el, el-gr |
Guzerate | gu, gu-in |
Hausa | ha, ha-latn, ha-latn-ng |
Hebraico | he, he-il |
Híndi | hi, hi-in |
Húngaro | hu, hu-hu |
Islandês | is, is-is |
Igb - ig-latn, ig-ng | |
Indonésio | id, id-id |
Inuktitut (Latino) | iu-cans, iu-latn, iu-latn-ca |
Irlandês | ga, ga-ie |
isiXhosa | xh, xh-za |
isiZulu | zu, zu-za |
Italiano | it, it-it, it-ch |
Japonês | ja , ja-jp |
canarim | kn, kn-in |
Cazaque | kk, kk-kz |
Khmer | km, km-kh |
Quiché | quc-latn, qut-gt, qut-latn |
Quiniaruanda | rw, rw-rw |
KiSwahili | sw, sw-ke |
Concani | kok, kok-in |
Coreano | ko, ko-kr |
Curdo | ku-arab, ku-arab-iq |
Kyrgyz | ky-kg, ky-cyrl |
Lao | lo, lo-la |
Letão | lv, lv-lv |
Lituano | lt, lt-lt |
Luxemburguês | lb, lb-lu |
Macedônio | mk, mk-mk |
Malaio | ms, ms-bn, ms-my |
Malaiala | ml, ml-in |
Maltês | mt, mt-mt |
Maori | mi, mi-latn, mi-nz |
Marati | mr, mr-in |
Mongol (Cirílico) | mn-cyrl, mn-mong, mn-mn, mn-phag |
Nepali | ne, ne-np |
Norueguês | nb, nb-no, nn, nn-no, no, no-no |
Oriá | or, or-in |
Persa | fa, fa-ir |
Polonês | pl, pl-pl |
Português (Brasil) | pt-br |
Português (Portugal) | pt, pt-pt |
Panjabi | pa, pa-arab, pa-arab-pk, pa-deva, pa-in |
Quíchua | quz, quz-bo, quz-ec, quz-pe |
Romeno | ro, ro-ro |
Russo | ru , ru-ru |
Gaélico escocês | gd-gb, gd-latn |
Sérvio (latino) | sr-Latn, sr-latn-cs, sr, sr-latn-ba, sr-latn-me, sr-latn-rs |
Sérvio (cirílico) | sr-cyrl, sr-cyrl-ba, sr-cyrl-cs, sr-cyrl-me, sr-cyrl-rs |
Soto setentrional | nso, nso-za |
Setsuana | tn, tn-bw, tn-za |
Sindhi | sd-arab, sd-arab-pk, sd-deva |
Sinhala | si, si-lk |
Eslovaco | sk, sk-sk |
Esloveno | sl, sl-si |
Espanhol | 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 |
Sueco | sv, sv-se, sv-fi |
Tadjique (Cirílico) | tg-arab, tg-cyrl, tg-cyrl-tj, tg-latn |
Tâmil | ta, ta-in |
Tártaro | tt-arab, tt-cyrl, tt-latn, tt-ru |
Télugo | te, te-in |
Tailandês | th, th-th |
Tigrinya | ti, ti-et |
Turco | tr, tr-tr |
Turcomeno | tk-cyrl, tk-latn, tk-tm, tk-latn-tr, tk-cyrl-tr |
Ucraniano | uk, uk-ua |
Urdu | ur, ur-pk |
Uyghur | ug-arab, ug-cn, ug-cyrl, ug-latn |
Uzbeque (latino) | uz, uz-cyrl, uz-latn, uz-latn-uz |
Vietnamita | vi, vi-vn |
Galês | cy, cy-gb |
Wolof | wo, wo-sn |
Ioruba | yo-latn, yo-ng |
Solicitação de Exemplo
{
"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"]
}
Cabeçalhos de resposta
Cabeçalho | Valor |
---|---|
X-Correlation-ID |
O GUID tipo ID exclusivo para cada solicitação. Pode ser compartilhado com a equipe de suporte para analisar qualquer issue. |
Retry-After |
O tempo, em segundos, que o cliente precisa esperar antes de chamar as APIs novamente devido ao limite de taxa |
Parâmetros de resposta
Nome | Tipo | Descrição |
---|---|---|
isSuccess | Booliano | |
erros | Matriz de objetos | A lista de mensagens de aviso ou de erro, se houver |
código | String | O código de erro da mensagem |
message | String | A descrição do erro |
destino | String | A entidade que originou o erro |
responseData | Objeto | Contém payload de resposta real para a solicitação |
pollingUrl | String | URL de pesquisa para obter o status de qualquer envio em andamento |
ongoingSubmissionId | String | ID de envio de qualquer envio já em andamento |
Resposta de exemplo
{
"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": ""
}
}
Obter a API de pacotes de rascunho atual
Busca detalhes do pacote no envio de escalação atual.
Caminho [Todos os pacotes]: /submission/v1/product/{productId}/packages
Método: OBTER
Caminho [Pacote único]: /submission/v1/product/{productId}/packages/{packageId}
Método: OBTER
Parâmetros de caminho
Nome | Descrição |
---|---|
productId | A ID da Central de Parceiros do produto |
packageId | A ID exclusiva do pacote a ser buscado |
Cabeçalhos necessários
Cabeçalho | Valor |
---|---|
Authorization: Bearer <Token> |
Usar a ID do aplicativo Azure AD registrada com a conta da Central de Parceiros |
X-Seller-Account-Id |
A ID do vendedor da conta da Central de Parceiros |
Cabeçalhos de resposta
Cabeçalho | Valor |
---|---|
X-Correlation-ID |
O GUID tipo ID exclusivo para cada solicitação. Pode ser compartilhado com a equipe de suporte para analisar qualquer issue. |
Retry-After |
O tempo, em segundos, que o cliente precisa esperar antes de chamar as APIs novamente devido à limitação de fluxo. |
Parâmetros de resposta
Nome | Tipo | Descrição |
---|---|---|
isSuccess | Booliano | |
erros | Matriz de objetos | A lista de erros ou mensagens de aviso, se houver |
código | String | O código de erro da mensagem |
message | String | A descrição do erro |
destino | String | A entidade que originou o erro |
responseData | Objeto | |
pacotes | Matriz de objetos | Objeto para armazenar dados do módulo de pacote |
packageId | String | |
packageUrl | String | |
idiomas | Matriz das cadeias de caracteres | |
arquiteturas | Matriz das cadeias de caracteres | [Neutro, X86, X64, Arm, Arm64] |
isSilentInstall | Booliano | Deve ser marcado como verdadeiro se o instalador for executado no modo sem confirmação sem exigir opções, ou então como falso |
installerParameters | String | |
genericDocUrl | String | |
errorDetails | Matriz de objetos | |
errorScenario | String | |
errorScenarioDetails | Matriz de objetos | |
errorValue | String | |
errorUrl | String | |
packageType | String |
Resposta de exemplo
{
"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",
}]
}
}
Atualizar a API de pacotes de rascunho atual
Atualiza os detalhes do pacote no envio de escalação atual.
Caminho [Atualização completa do módulo]: /submission/v1/product/{productId}/packages
Método: PUT
Caminho [Atualização de patch de pacote único]: /submission/v1/product/{productId}/packages/{packageId}
Método: PATCH
Comportamento da API
No caso da API de Atualização Completa de Módulo – todos os dados de pacotes precisam estar presentes na solicitação de atualização completa de cada campo. Qualquer campo que não esteja presente na solicitação, seu valor padrão é usado para substituir o valor atual desse módulo específico. O resultado é a substituição de todos os pacotes existentes por um novo conjunto de pacotes da solicitação. O que causará a regeneração das IDs de Pacote e fará com que o usuário precise chamar a API de Pacotes GET para obter as IDs de Pacote mais recentes.
No caso da API de Atualização de Patch de Pacote Único – somente os campos de um determinado pacote a serem atualizados precisam estar presentes na solicitação. Esses valores de campo da solicitação substituirão os valores existentes, mantendo todos os outros campos que não estão presentes na solicitação iguais aos atuais desse pacote específico. Outros pacotes no conjunto permanecem como estão.
Parâmetros de caminho
Nome | Descrição |
---|---|
productId | A ID da Central de Parceiros do produto |
packageId | A ID exclusiva do pacote |
Cabeçalhos necessários
Cabeçalho | Valor |
---|---|
Authorization: Bearer <Token> |
Usar a ID do aplicativo Azure AD registrada com a conta da Central de Parceiros |
X-Seller-Account-Id |
A ID do vendedor da conta da Central de Parceiros |
Parâmetros de solicitação
Nome | Tipo | Descrição |
---|---|---|
pacotes | Matriz de objetos | Objeto para armazenar os dados do módulo de pacote [Obrigatório somente para a atualização completa do módulo] |
packageUrl | String | Obrigatório |
idiomas | Matriz das cadeias de caracteres | Obrigatório |
arquiteturas | Matriz das cadeias de caracteres | Obrigatório Deve conter uma única arquitetura - Neutro, X86, X64, Arm, Arm64 |
isSilentInstall | Booliano | Obrigatório Deve ser marcado como verdadeiro se o instalador for executado no modo sem confirmação sem exigir opções, ou então como falso |
installerParameters | String | Obrigatório se isSilentInstall for falso |
genericDocUrl | String | Obrigatório se packageType for exe Link para documento que contém detalhes de códigos de erro personalizados para o instalador do tipo EXE |
errorDetails | Matriz de objetos | Metadados para armazenar códigos de erro personalizados e detalhes para instaladores do tipo EXE. |
errorScenario | String | Identificar o cenário de erro específico. [installationCancelledByUser, applicationAlreadyExists, installationAlreadyInProgress, diskSpaceIsFull, rebootRequired, networkFailure, packageRejectedDuringInstallation, installationSuccessful, miscellaneous] |
errorScenarioDetails | Matriz de objetos | |
errorValue | String | Código de erro que pode estar presente durante a instalação |
errorUrl | String | URL para obter detalhes sobre o erro |
packageType | String | Obrigatório [exe, msi] |
Solicitação de exemplo [Atualização completa do módulo]
{
"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",
}]
}
Solicitação de exemplo [Atualização de patch de pacote único]
{
"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",
}
Cabeçalhos de resposta
Cabeçalho | Valor |
---|---|
X-Correlation-ID |
O GUID tipo ID exclusivo para cada solicitação. Pode ser compartilhado com a equipe de suporte para analisar qualquer issue. |
Retry-After |
O tempo, em segundos, que o cliente precisa esperar antes de chamar as APIs novamente devido à limitação de fluxo. |
Parâmetros de resposta
Nome | Tipo | Descrição |
---|---|---|
isSuccess | Booliano | |
erros | Matriz de objetos | [A lista de mensagens de aviso ou de erro, se houver] |
código | String | O código de erro da mensagem |
message | String | A descrição do erro |
destino | String | A entidade que originou o erro |
responseData | Objeto | |
pollingUrl | String | [URL de pesquisa para obter o status de envio no caso de haver qualquer envio já em andamento] |
ongoingSubmissionId | String | [ID de envio de qualquer envio já em andamento] |
Resposta de exemplo
{
"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": ""
}
}
Fazer commit de API de Pacotes
Confirma o novo conjunto de Pacotes atualizados usando APIs de Atualização do Pacote no envio de escalação atual. Essa API retorna uma URL de pesquisa para rastrear o Upload do Pacote.
Caminho: /submission/v1/product/{productId}/packages/commit
Método: LANÇAR
Parâmetros de caminho
Nome | Descrição |
---|---|
productId | A ID da Central de Parceiros do produto |
Cabeçalhos necessários
Cabeçalho | Valor |
---|---|
Authorization: Bearer <Token> |
Usar a ID do aplicativo Azure AD registrada com a conta da Central de Parceiros |
X-Seller-Account-Id |
A ID do vendedor da conta da Central de Parceiros |
Cabeçalhos de resposta
Cabeçalho | Valor |
---|---|
X-Correlation-ID |
O GUID tipo ID exclusivo para cada solicitação. Pode ser compartilhado com a equipe de suporte para analisar qualquer issue. |
Retry-After |
O tempo, em segundos, que o cliente precisa esperar antes de chamar as APIs novamente devido à limitação de fluxo. |
Parâmetros de resposta
Nome | Tipo | Descrição |
---|---|---|
isSuccess | Booliano | |
erros | Matriz de objetos | [A lista de mensagens de aviso ou de erro, se houver] |
código | String | O código de erro da mensagem |
message | String | A descrição do erro |
destino | String | A entidade que originou o erro |
responseData | Objeto | |
pollingUrl | String | [URL de pesquisa para obter o status de upload de pacote ou status de envio no caso de haver qualquer envio Já em andamento] |
ongoingSubmissionId | String | [ID de envio de qualquer envio já em andamento] |
Resposta de exemplo
{
"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": ""
}
}
Obter a API de ativos da listagem de rascunho atual
Busca detalhes de ativos de listagem no envio de escalação atual.
Caminho: /submission/v1/product/{productId}/listings/assets?languages={languages}
Método: OBTER
Parâmetros de caminho
Nome | Descrição |
---|---|
productId | A ID da Central de Parceiros do produto |
Parâmetros de consulta
Nome | Descrição |
---|---|
idiomas | [Opcional] Os idiomas de listagem são filtrados como sequência separada por vírgulas [limite de até 200 idiomas]. Se ausentes, os primeiros 200 dados de ativos de idiomas de listagem disponíveis serão recuperados. (por exemplo, "en-US, en-GB") |
Cabeçalhos necessários
Cabeçalho | Valor |
---|---|
Authorization: Bearer <Token> |
Usar a ID do aplicativo Azure AD registrada com a conta da Central de Parceiros |
X-Seller-Account-Id |
A ID do vendedor da conta da Central de Parceiros |
Cabeçalhos de resposta
Cabeçalho | Valor |
---|---|
X-Correlation-ID |
O GUID tipo ID exclusivo para cada solicitação. Pode ser compartilhado com a equipe de suporte para analisar qualquer issue. |
Retry-After |
O tempo, em segundos, que o cliente precisa esperar antes de chamar as APIs novamente devido à limitação de fluxo. |
Parâmetros de resposta
Nome | Tipo | Descrição |
---|---|---|
isSuccess | Booliano | |
erros | Matriz de objetos | A lista de mensagens de aviso ou de erro, se houver |
código | String | O código de erro da mensagem |
message | String | A descrição do erro |
destino | String | A entidade que originou o erro |
responseData | Objeto | |
listagem de ativos | Matriz de objetos | Listagem dos detalhes de ativos de cada idioma |
linguagem | String | |
storeLogos | Matriz de objetos | |
capturas de tela | Matriz de objetos | |
ID | String | |
assetUrl | String | Deve ser um URL válido |
imageSize | Objeto | |
width | Inteiro | |
altura | Inteiro |
Resposta de exemplo
{
"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
}
}
]
}]
}
}
Criar API de ativos de listagem
Cria o Upload de ativos de listagem no envio de escalação atual.
Atualização da listagem de ativos
A API de Envio da Microsoft Store para aplicativos EXE ou MSI usa as URLs SAS geradas em runtime para Repositórios de Blobs para cada upload de ativo de imagem individual, juntamente com uma chamada de API de commit após o upload ser bem-sucedido. Para ter a capacidade de atualizar ativos de listagem e, por sua vez, para poder adicionar/remover localidades no módulo de listagem, a seguinte abordagem pode ser usada:
- Use a API Criar Ativo de Listagem para enviar solicitações sobre o upload de ativos junto com idioma, tipo e contagem de ativos.
- Com base no número de ativos solicitados, as IDs de ativos são criadas sob demanda e seria criada uma URL SAS de curto prazo que seria enviada de volta no Corpo da resposta sob o tipo de ativos. Você pode usar essa URL para fazer upload de ativos de imagem do tipo específico usando Clientes HTTP [Colocar BLOB (API REST) - Armazenamento do Azure | Microsoft Docs].
- Após o upload, você pode usar a API Fazer Commit de Ativos de Listagem para também enviar as novas informações de ID de Ativo recebidas anteriormente de uma chamada de API anterior. A API única fará commit internamente dos dados dos ativos de listagem após a validação.
- Essa abordagem substituirá efetivamente todo o conjunto de Imagens anteriores do tipo de ativo em linguagem específica que está sendo enviada na solicitação. Assim, os ativos carregados anteriormente serão removidos.
Caminho: /submission/v1/product/{productId}/listings/assets/create
Método: LANÇAR
Parâmetros de caminho
Nome | Descrição |
---|---|
productId | A ID da Central de Parceiros do produto |
Cabeçalhos necessários
parâmetro | Descrição |
---|---|
Authorization: Bearer <Token> |
Usar a ID do aplicativo Azure AD registrada com a conta da Central de Parceiros |
X-Seller-Account-Id |
A ID do vendedor da conta da Central de Parceiros |
Parâmetros de solicitação
Nome | Tipo | Descrição |
---|---|---|
Linguagem | String | Obrigatório |
createAssetRequest | Objeto | Obrigatório |
Captura de tela | Inteiro | Obrigatório se o ISV precisar atualizar capturas de tela ou adicionar novo idioma de listagem [1 - 10] |
Logotipo | Inteiro | Obrigatório se o ISV precisar atualizar logotipos ou adicionar novo idioma de listagem [1 ou 2] |
Cabeçalhos de resposta
parâmetro | Descrição |
---|---|
X-Correlation-ID |
O GUID tipo ID exclusivo para cada solicitação. Pode ser compartilhado com a equipe de suporte para analisar qualquer issue. |
Retry-After |
O tempo, em segundos, que o cliente precisa esperar antes de chamar as APIs novamente devido à limitação de fluxo. |
Parâmetros de resposta
Nome | Tipo | Descrição |
---|---|---|
isSuccess | Booliano | |
erros | Matriz de objetos | A lista de mensagens de aviso ou de erro, se houver |
código | String | O código de erro da mensagem |
message | String | A descrição do erro |
destino | String | A entidade que originou o erro |
responseData | Objeto | |
listagem de ativos | Objeto | Objeto contendo detalhes de StoreLogos e Screenshots a serem carregados |
linguagem | String | |
storeLogos | Matriz de objetos | |
capturas de tela | Matriz de objetos | |
ID | String | |
primaryAssetUploadUrl | String | URL primária para fazer upload do ativo de listagem usando a API REST de BLOB do Azure |
secondaryAssetUploadUrl | String | URL secundária para fazer upload do ativo de listagem usando a API REST de BLOB do Azure |
httpMethod | Método HTTP | O método HTTP precisava ser usado para fazer upload de ativos por meio das URLs de upload de ativos – primária ou secundária |
httpHeaders | Objeto | Um objeto com chaves como cabeçalhos Obrigatórios para estar presente na chamada de API de upload para URLs de upload de ativos. Se o valor não estiver vazio, os cabeçalhos precisarão ter valores específicos. Caso contrário, os valores são calculados durante a chamada de API. |
Resposta de exemplo
{
"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"}
}]
}
}
}
Fazer commit da API de Ativos de Listagem
Faz commit do novo ativo de listagem carregado usando os detalhes da API Criar Ativos no envio de escalação atual.
Caminho: /submission/v1/product/{productId}/listings/assets/commit
Método: PUT
Parâmetros de caminho
Nome | Descrição |
---|---|
productId | A ID da Central de Parceiros do produto |
Cabeçalhos necessários
parâmetro | Descrição |
---|---|
Authorization: Bearer <Token> |
Usar a ID do aplicativo Azure AD registrada com a conta da Central de Parceiros |
X-Seller-Account-Id |
A ID do vendedor da conta da Central de Parceiros |
Parâmetros de solicitação
Nome | Tipo | Descrição |
---|---|---|
listagem de ativos | Objeto | |
linguagem | String | |
storeLogos | Matriz de objetos | |
capturas de tela | Matriz de objetos | |
ID | String | Deve ser uma ID existente que o usuário deseja manter a partir da API Obter Ativos de Listagem Atuais ou uma nova ID sob a qual um novo Ativo foi carregado na API Criar Ativos de Listagem. |
assetUrl | String | Deve ser a URL do ativo existente que o usuário deseja manter a partir da API Obter Ativos de Listagem Atuais ou a URL de Upload – primária ou secundária, usando um novo ativo que foi carregado na API Criar Ativos de Listagem. Deve ser um URL válido |
Solicitação de Exemplo
{
"listingAssets": {
"language": "en-us",
"storeLogos": [
{
"id": "1234567890abcdefgh",
"assetUrl": "https://contoso.com/blob=1234567890abcdefgh",
}
],
"screenshots": [
{
"id": "1234567891abcdefgh",
"assetUrl": "https://contoso.com/blob=1234567891abcdefgh",
}
]
}
}
Cabeçalhos de resposta
parâmetro | Descrição |
---|---|
X-Correlation-ID |
O GUID tipo ID exclusivo para cada solicitação. Pode ser compartilhado com a equipe de suporte para analisar qualquer issue. |
Retry-After |
O tempo, em segundos, que o cliente precisa esperar antes de chamar as APIs novamente devido à limitação de fluxo. |
Parâmetros de resposta
Nome | Tipo | Descrição |
---|---|---|
isSuccess | Booliano | |
erros | Matriz de objetos | A lista de mensagens de aviso ou de erro, se houver |
código | String | O código de erro da mensagem |
message | String | A descrição do erro |
destino | String | A entidade que originou o erro |
responseData | Objeto | |
pollingUrl | String | URL de pesquisa para obter o status de qualquer envio em andamento |
ongoingSubmissionId | String | ID de envio de qualquer envio já em andamento |
Resposta de exemplo
{
"isSuccess": true,
"errors": [{
"code": "badrequest",
"message": "Error Message 1",
"target": "listings"
}, {
"code": "warning",
"message": "Warning Message 1",
"target": "properties"
}],
"responseData": {
"pollingUrl": "/submission/v1/product/{productId}/submission/{submissionId}/status",
"ongoingSubmissionId": ""
}
}
API de pesquisa de status do módulo
API para verificar a prontidão do módulo antes que o envio possa ser criado. Também valida o status de upload do pacote.
Caminho: /submission/v1/product/{productId}/status
Método: OBTER
Parâmetros de caminho
Nome | Descrição |
---|---|
productId | A ID da Central de Parceiros do produto |
Cabeçalhos necessários
parâmetro | Descrição |
---|---|
Authorization: Bearer <Token> |
Usar a ID do aplicativo Azure AD registrada com a conta da Central de Parceiros |
X-Seller-Account-Id |
A ID do vendedor da conta da Central de Parceiros |
Cabeçalhos de resposta
parâmetro | Descrição |
---|---|
X-Correlation-ID |
O GUID tipo ID exclusivo para cada solicitação. Pode ser compartilhado com a equipe de suporte para analisar qualquer issue. |
Retry-After |
O tempo, em segundos, que o cliente precisa esperar antes de chamar as APIs novamente devido à limitação de fluxo. |
Parâmetros de resposta
Nome | Tipo | Descrição |
---|---|---|
isSuccess | Booliano | |
erros | Matriz de objetos | A lista de mensagens de aviso ou de erro, se houver |
código | String | O código de erro da mensagem |
message | String | A descrição do erro |
destino | String | A entidade que originou o erro |
responseData | Objeto | |
isReady | Booliano | Indica se todos os módulos estão no estado pronto, incluindo o upload do pacote |
ongoingSubmissionId | String | ID de envio de qualquer envio já em andamento |
Resposta de exemplo
{
"isSuccess": true,
"errors": [{
"code": "badrequest",
"message": "Error Message 1",
"target": "listings"
}, {
"code": "warning",
"message": "Warning Message 1",
"target": "properties"
}],
"responseData": {
"isReady": true,
"ongoingSubmissionId": ""
}
}
Criar API de envio
Cria um envio de escalação atual para aplicativos MSI ou EXE. A API verifica:
- para envio ativo e falha com mensagem de erro se existir um envio ativo.
- se todos os módulos estiverem no status pronto para criar o envio.
- cada campo no envio é validado de acordo com os requisitos da Store
Caminho:/submission/v1/product/{productId}/submit
Método: LANÇAR
Parâmetros de caminho
Nome | Descrição |
---|---|
productId | A ID da Central de Parceiros do produto |
Cabeçalhos necessários
parâmetro | Descrição |
---|---|
Authorization: Bearer <Token> |
Usar a ID do aplicativo Azure AD registrada com a conta da Central de Parceiros |
X-Seller-Account-Id |
A ID do vendedor da conta da Central de Parceiros |
Cabeçalhos de resposta
parâmetro | Descrição |
---|---|
X-Correlation-ID |
O GUID tipo ID exclusivo para cada solicitação. Pode ser compartilhado com a equipe de suporte para analisar qualquer issue. |
Retry-After |
O tempo, em segundos, que o cliente precisa esperar antes de chamar as APIs novamente devido à limitação de fluxo. |
Parâmetros de resposta
Nome | Tipo | Descrição |
---|---|---|
isSuccess | Booliano | |
erros | Matriz de objetos | A lista de mensagens de aviso ou de erro, se houver |
código | String | O código de erro da mensagem |
message | String | A descrição do erro |
destino | String | A entidade que originou o erro |
responseData | Objeto | |
pollingUrl | String | URL de pesquisa para obter o status de preparação do módulo, incluindo o upload de pacotes para envio |
submissionId | String | A ID do envio recém-criada |
ongoingSubmissionId | String | ID de envio de qualquer envio já em andamento |
Resposta de exemplo
{
"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 de pesquisa de status de envio
API para verificar o status de envio.
Caminho: /submission/v1/product/{productId}/submission/{submissionId}/status
Método: OBTER
Parâmetros de caminho
Nome | Descrição |
---|---|
productId | A ID da Central de Parceiros do produto |
Cabeçalhos necessários
parâmetro | Descrição |
---|---|
Authorization: Bearer <Token> |
Usar a ID do aplicativo Azure AD registrada com a conta da Central de Parceiros |
X-Seller-Account-Id |
A ID do vendedor da conta da Central de Parceiros |
Cabeçalhos de resposta
parâmetro | Descrição |
---|---|
X-Correlation-ID |
O GUID tipo ID exclusivo para cada solicitação. Pode ser compartilhado com a equipe de suporte para analisar qualquer issue. |
Retry-After |
O tempo, em segundos, que o cliente precisa esperar antes de chamar as APIs novamente devido à limitação de fluxo. |
Parâmetros de resposta
Nome | Tipo | Descrição |
---|---|---|
isSuccess | Booliano | |
erros | Matriz de objetos | A lista de mensagens de aviso ou de erro, se houver |
código | String | O código de erro da mensagem |
message | String | A descrição do erro |
destino | String | A entidade que originou o erro |
responseData | Objeto | |
publicandoStatus | String | Status de publicação da envio - [INPROGRESS, PUBLISHED, FAILED, UNKNOWN] |
hasFailed | Booliano | Indica se a publicação falhou e não será tentada novamente |
Resposta de exemplo
{
"isSuccess": true,
"errors": [{
"code": "badrequest",
"message": "Error Message 1",
"target": "listings"
}, {
"code": "warning",
"message": "Warning Message 1",
"target": "properties"
}],
"responseData": {
"publishingStatus": "INPROGRESS",
"hasFailed": false
}
}
Exemplos de código
Os artigos a seguir fornecem exemplos de código detalhados que demonstram como usar a API de envio da Microsoft Store em diferentes linguagens de programação:
Exemplo C#: API de Envio da Microsoft Store para aplicativos MSI ou EXE
Este artigo fornece exemplos de código C# que demonstram como usar a API de envio da Microsoft Store para aplicativos MSI ou EXE. Você pode revisar cada exemplo para saber mais sobre a tarefa que ele demonstra ou pode criar todos os exemplos de código neste artigo em um aplicativo de console.
Pré-requisitos Esses exemplos usam a seguinte biblioteca:
- Pacote Newtonsoft.Json NuGet da Newtonsoft.
Programa Main O exemplo a seguir implementa um programa de linha de comando que chama os outros métodos de exemplo neste artigo para demonstrar maneiras diferentes de usar a API de envio da Microsoft Store. Para adaptar este programa para seu próprio uso:
- Atribua a propriedade SellerId à ID do Vendedor da sua conta da Central de Parceiros.
- Atribua a propriedade ApplicationId à ID do aplicativo que deseja gerenciar.
- Atribua as propriedades ClientId e ClientSecret à ID do cliente e à chave do seu aplicativo e substitua a sequência tenantid na URL do TokenEndpoint pela ID do locatário do seu aplicativo. Para obter mais informações, confira Como associar um aplicativo do Azure AD à sua conta da Central de Parceiros
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 auxiliar ClientConfiguration usando C#
O aplicativo de exemplo usa a classe auxiliar ClientConfiguration para passar os dados do Azure Active Directory e os dados do aplicativo para cada um dos métodos de exemplo que usam a API de envio da 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; }
}
}
Criar um envio de aplicativo usando C#
O exemplo a seguir implementa uma classe que usa diversos métodos na API de envio da Microsoft Store para atualizar um envio de aplicativo.
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 auxiliar IngestionClient usando C#
A classe IngestionClient fornece métodos auxiliares que são usados por outros métodos no aplicativo de exemplo para executar as seguintes tarefas:
- Obter um token de acesso do Azure AD que pode ser usado para chamar métodos na API de envio da Microsoft Store. Depois de obter um token, você tem 60 minutos para usá-lo em chamadas para a API de envio da Microsoft Store antes que ele expire. Depois que o token expirar, será possível gerar um novo.
- Processar as solicitações HTTP para a API de envio da 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;
}
}
}
Exemplo de Node.js: API de Envio da Microsoft Store para aplicativos MSI ou EXE
Este artigo fornece exemplos de código Node.js que demonstram como usar a API de envio da Microsoft Store para aplicativos MSI ou EXE. Você pode revisar cada exemplo para saber mais sobre a tarefa que ele demonstra ou pode criar todos os exemplos de código neste artigo em um aplicativo de console.
Pré-requisitos Esses exemplos usam a seguinte biblioteca:
- node-fetch v2 [npm install node-fetch@2]
Crie um envio de aplicativo usando o Node.js
O exemplo a seguir chama os outros métodos de exemplo neste artigo para demonstrar maneiras diferentes de usar a API de envio da Microsoft Store. Para adaptar este programa para seu próprio uso:
- Atribua a propriedade SellerId à ID do Vendedor da sua conta da Central de Parceiros.
- Atribua a propriedade ApplicationId à ID do aplicativo que deseja gerenciar.
- Atribua as propriedades ClientId e ClientSecret à ID do cliente e à chave do seu aplicativo e substitua a sequência tenantid na URL do TokenEndpoint pela ID do locatário do seu aplicativo. Para obter mais informações, confira Como associar um aplicativo do Azure AD à sua conta da Central de Parceiros
O exemplo a seguir implementa uma classe que usa diversos métodos na API de envio da Microsoft Store para atualizar um envio de aplicativo.
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();
Auxiliar ClientConfiguration
O aplicativo de exemplo usa a classe auxiliar ClientConfiguration para passar os dados do Azure Active Directory e os dados do aplicativo para cada um dos métodos de exemplo que usam a API de envio da 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;
Auxiliar IngestionClient usando o Node.js
A classe IngestionClient fornece métodos auxiliares que são usados por outros métodos no aplicativo de exemplo para executar as seguintes tarefas:
- Obter um token de acesso do Azure AD que pode ser usado para chamar métodos na API de envio da Microsoft Store. Depois de obter um token, você tem 60 minutos para usá-lo em chamadas para a API de envio da Microsoft Store antes que ele expire. Depois que o token expirar, será possível gerar um novo.
- Processar as solicitações HTTP para a API de envio da 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;
Ajuda adicional
Se você tiver dúvidas sobre a API de envio da Microsoft Store ou precisar de assistência para gerenciar seus envios com essa API, use os seguintes recursos:
- Faça perguntas em nossos fóruns.
- Visite nossa página de suporte e solicite uma das opções de suporte assistido para a Central de Parceiros. Se você for solicitado a escolher um tipo e uma categoria de problema, escolha Envio de aplicativo, certificação e Enviar um aplicativo, respectivamente.
Windows developer