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 de aplicativos MSI ou EXE de forma programática para a sua conta do Partner Center ou a 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 a ID do Microsoft Entra para autenticar as chamadas de seu aplicativo ou serviço.

As etapas a seguir descrevem o processo de uso ponta a ponta da API de envio da Microsoft Store:

  1. Verifique se todos os pré-requisitos foram atendidos.
  2. Antes de chamar um método da API de submissão da Microsoft Store, obtenha um token de acesso do Microsoft Entra ID. 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.
  3. Chame a API de submissão da Microsoft Store de 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 Microsoft Entra ID e ter permissão de administrador global para o diretório. Se você já usa o Microsoft 365 ou outros serviços comerciais da Microsoft, já tem o diretório da ID do Microsoft Entra. Caso contrário, você poderá criar uma nova ID do Microsoft Entra no Partner Center sem custo adicional.
  • Você deve associar um aplicativo de ID do Microsoft Entra à sua conta do Partner Center e obter sua ID de locatário, ID do cliente e chave. Você precisa desses valores para obter um token de acesso do Microsoft Entra ID, que você usará em chamadas para a API de submissão 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 novas submissões deste 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 de ID do Microsoft Entra à sua conta do Partner Center

Antes de usar a API de submissão da Microsoft Store para aplicativos MSI ou EXE, você deve associar um aplicativo do Microsoft Entra ID à sua conta do Partner Center, obter a ID do locatário e a ID do cliente do aplicativo e gerar uma chave. O aplicativo Microsoft Entra ID 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 da ID do Microsoft Entra que você passa para a API.

Observação

É necessário executar essa tarefa apenas uma vez. Depois de ter a ID do locatário, a ID do cliente e a chave, você poderá reutilizá-los sempre que precisar criar um novo token de acesso da ID do Microsoft Entra.

  1. No Partner Center, associe a conta do Partner Center da sua organização ao diretório do Microsoft Entra ID da sua organização.
  2. Em seguida, na página Usuários na seção Configurações de conta do Partner Center, adicione o aplicativo Microsoft Entra ID que representa o aplicativo ou serviço que você usará para acessar envios para sua conta do Partner Center. Lembre-se de atribuir esse aplicativo à função de Gerenciador. Se o aplicativo ainda não existir no diretório da ID do Microsoft Entra, você poderá criar um novo aplicativo de ID do Microsoft Entra no Partner Center.
  3. Retorne à página Usuários, clique no nome do aplicativo microsoft Entra ID para acessar as configurações do aplicativo e copie os valores da ID do Locatário e da ID do Cliente.
  4. 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:

  1. Entre no portal do Azure.

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

  3. Pesquise e selecione o Diretório de ID do Microsoft Entra.

  4. Em Gerenciar, selecione Registros de aplicativo > Selecionar seu aplicativo.

  5. Selecione Certificados e segredos > Segredos do cliente > Novo segredo do cliente.

  6. Adicione uma descrição para o segredo do cliente.

  7. Selecione uma data de expiração para o segredo ou especifique um tempo de vida personalizado.

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

  9. Selecione Adicionar.

  10. 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 Microsoft Entra ID

Antes de chamar qualquer um dos métodos da API de submissão da Microsoft Store para aplicativos MSI ou EXE, você deve primeiro obter um token de acesso do Microsoft Entra ID, que será passado para o cabeçalho de Autorização de cada método da 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 Chamadas de Serviço para Serviço usando credenciais do cliente para enviar um HTTP POST para o endpoint 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 Microsoft Entra ID, você poderá chamar os métodos da API de submissão 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 submissões, normalmente você chama 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 chamar métodos na API de envio da Microsoft Store para aplicativos MSI ou EXE antes que o token expire.

URL de 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 da submissão de rascunho 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: GET

Parâmetros de caminho

Parâmetro Descrição
ID do produto A ID do produto no Partner Center
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> O ID do aplicativo Microsoft Entra ID registrado na conta do Partner Center
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 booleano
termos adicionais da licença fio
disponibilidade Objeto Dados do módulo de disponibilidade
categoria fio Confira a lista de categorias abaixo
notas de certificação fio
codificar fio O código de erro da mensagem
informações de contato fio
copyright fio
dependsOnDriversOrNT booleano
descrição fio
desenvolvido por fio
detectabilidade fio [DETECTÁVEL, DEEPLINK_ONLY]
enableInFutureMarkets booleano
erros Matriz de objetos A lista de mensagens de aviso ou de erro, se houver
freeTrial fio [NO_FREE_TRIAL, FREE_TRIAL]
hardwareItemType fio
isPrivacyPolicyRequired booleano
isRecommended booleano
isRequired booleano
isSuccess booleano
isSystemFeatureRequired Matriz de objetos
linguagem fio Confira a lista de idiomas abaixo
listagens Matriz de objetos Dados do módulo de listagens para cada idioma
mercados Matriz de cadeias de caracteres Confira a lista de mercados abaixo
mensagem fio A descrição do erro
minimumHardware fio
requisito mínimo fio
suporte para caneta e tinta booleano
preço fio [GRATUITO, FREEMIUM, ASSINATURA, PAGO]
Url da Política de Privacidade fio
declarações de produto Objeto
característicasDoProduto Matriz de cadeias de caracteres
propriedades Objeto Dados do módulo de propriedades
recommendedHardware fio
requisito recomendado fio
responseData Objeto Contém payload de resposta real para a solicitação
requisitos Matriz de objetos
termos de busca Matriz de cadeias de caracteres
Descrição Curta fio
Subcategoria fio Confira a lista de subcategorias abaixo
supportContactInfo fio
Detalhes dos requisitos do sistema Matriz de objetos
destino fio A entidade que originou o erro
site fio
Novidades fio

Atualizar a API de metadados da submissão de rascunho atual

Atualiza os metadados de cada módulo em uma submissão em rascunho. A API verifica

  • Para submissão ativa. Se existir, falha com mensagem de erro.
  • Se todos os módulos estiverem com status "Pronto", será possível realizar a operação de salvar rascunho.
  • Cada campo no envio é validado de acordo com os requisitos da Store
  • Regras de validação para os detalhes dos requisitos 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 do módulo]: /submission/v1/product/{productId}/metadata
Método: PUT

Caminho [Atualização de Patch do 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
ID do produto A ID do produto no Partner Center

Cabeçalhos necessários

Cabeçalho Valor
Authorization: Bearer <Token> O ID do aplicativo Microsoft Entra ID registrado na conta do Partner Center
X-Seller-Account-Id A ID do vendedor da conta da Central de Parceiros

Parâmetros de solicitação

Nome Tipo Descrição
disponibilidade Objeto Objeto para armazenar os metadados do Módulo de Disponibilidade
mercados Matriz de cadeias de caracteres Obrigatório Confira a lista de mercados abaixo
detectabilidade fio Obrigatório [DISCOVERABLE, DEEPLINK_ONLY]
enableInFutureMarkets booleano Obrigatório
preço fio Obrigatório [GRÁTIS, FREEMIUM, ASSINATURA, PAGO]
freeTrial fio Obrigatório se o preço for PAGO ou ASSINATURA [NO_FREE_TRIAL, FREE_TRIAL]
propriedades Objeto Objeto para armazenar os metadados do módulo de propriedades
isPrivacyPolicyRequired booleano Obrigatório
Url da Política de Privacidade fio Obrigatório se isPrivacyPolicyRequired = true Deve ser uma URL válida
site fio Deve ser um URL válido
supportContactInfo fio Deve ser uma URL ou um endereço de e-mail válido
notas de certificação fio Limite recomendado de caracteres = 2.000
categoria fio Obrigatório Confira a lista de categorias abaixo
Subcategoria fio Obrigatório Confira a lista de subcategorias abaixo
declarações de produto Objeto Obrigatório
isSystemFeatureRequired Matriz de objetos [Toque, Teclado, Mouse, Câmera, NFC_HCE, NFC_Proximity, Bluetooth_LE, Telefonia, Microfone]
isRequired booleano Obrigatório
isRecommended booleano Obrigatório
hardwareItemType fio Obrigatório
Detalhes dos requisitos do sistema Matriz de objetos [Processador, Gráficos, Memória, DirectX Video_Memory]
requisito mínimo fio 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]
requisito recomendado fio 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 booleano Obrigatório
Suporte de acessibilidade booleano Obrigatório
suporte para caneta e tinta booleano Obrigatório
listagens Objeto Objeto para listar os dados de módulo de um único idioma
linguagem fio Obrigatório Confira a lista de idiomas abaixo
descrição fio Limite obrigatório de caracteres = 10.000
Novidades fio Limite de caracteres = 1.500
característicasDoProduto Array de strings 200 caracteres por recurso; até 20 recursos
Descrição Curta fio Limite de caracteres = 1.000
termos de busca Matriz de sequência 30 caracteres por termo de pesquisa; até 7 termos de pesquisa

21 palavras únicas no total em todos os termos de pesquisa
termos adicionais da licença fio Limite obrigatório de caracteres = 10.000
copyright fio Limite de caracteres = 200
desenvolvido por fio 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 fio Limite de caracteres = 200
recommendedHardware fio Limite de caracteres = 200
informações de contato fio Limite de caracteres = 200
listagensParaAdicionar Matriz de cadeias de caracteres Confira a lista de idiomas abaixo
listingsToRemove Matriz de cadeias de caracteres Confira a lista de idiomas abaixo

Mercados

Ver tabela | Mercado | Abreviação | |--------|--------------| | Afeganistão | AF | | Albânia | AL | | Argélia | DZ | | Samoa Americana | AS | | Andorra | AD | | Angola | AO | | Anguilla | AI | | 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 | | Benim | BJ | | Bermudas | BM | | Butão | BT | | República Bolivariana da Venezuela | VE | | Bolívia | BO | | Bonaire | BQ | | Bósnia and 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 | | Burkina 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 (DRC) | CD | | Ilhas Cook | CK | | Costa Rica | CR | | Croácia | HR | | Curaçao | CW | | Chipre | CY | | República Tcheca | CZ | | Costa do Marfim | CI | | Dinamarca | DK | | Djibuti | DJ | | Dominica | DM | | República Dominicana | DO | | Equador | EC | | Egito | EG | | El Salvador | SV | | Guiné Equatorial | GQ | | Eritrea | 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 Francesas do Sul e da Antártida | TF | | Gabão | GA | | Gâmbia | GM | | Georgia | 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 | | Ilha Heard e Ilhas McDonald | HM | | Cidade do Vaticano | VA | | Honduras | HN | | Região Administrativa Especial 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 | | Jordânia | JO | | Cazaquistão | KZ | | Quênia | KE | | Quiribáti | KI | | Coréia | 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 | | Macao SAR | MO | | Macedônia do Norte | MK | | Madagáscar | MG | | Maláui | PM | | Malásia | MEU | | Maldivas | VM | | Mali | AM | | Malta | MT | | Ilha de Man | IM | | Ilhas Marshall | MH | | Martinica | QM | | Mauritânia | SR | | Maurício | UM | | Maiote | YT | | México | MX | | Micronésia | FM | | Moldávia | Médico | | Mônaco | MC | | Mongólia | MN | | Montenegro — ME | | Montserrate | EM | | Marrocos | MA | | Moçambique | MZ | | Mianmar | Milímetros | | Namíbia | NA | | Nauru | NR | | Nepal | PN | | Holanda | Holanda | | Nova Caledônia | NC | | Nova Zelândia | Nova Zelândia | | Nicarágua | IN | | Níger | NE | | Nigéria | GN | | Niue | NU | | Ilha Norfolk | NF | | Ilhas Marianas do Norte | Deputado | | Noruega | NÃO | | 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 | | Catar | 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 Névis | KN | | Santa Lúcia | LC | | São Martinho (Parte Francesa) | MF | | São Pedro e Miquelão | 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 | | São Martinho (Parte Holandesa) | SX | | Eslováquia | SK | | Eslovênia | SI | | Ilhas Salomão | SB | | Somália | SO | | África do Sul | ZA | | Geórgia do Sul e Ilhas 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 | | Ilhas Menores Distantes dos EUA | UM | | Ilhas Virgens dos EUA | VI | | Uganda | UG | | Ucrânia | UA | | Emirados Árabes Unidos | EA | | Reino Unido | GB | | Estados Unidos | EUA | | Uruguai | UY | | Uzbequistão | UZ | | Vanuatu | VU | | Vietnã | VN | | Wallis e Futuna | WF | | Iémen | SIM | | Zâmbia | ZM | | Zimbabué | ZW | | Ilhas Alanda | AX |

Categorias e subcategorias

Ver tabela | Categoria | Subcategorias | |-----------------------|---------------| | BooksAndReference | EReader, Ficção, Não ficção, Referência | | Negócios | AccountingAndfinance, Collaboration, CRM, DataAndAnalytics, FileManagement, InventoryAndlogistics, LegalAndHR, ProjectManagement, RemoteDesktop, SalesAndMarketing, TimeAndExpenses | | DeveloperTools | Database, DesignTools, DevelopmentKits, Networking, ReferenceAndTraining, Servers, Utilities, WebHosting | Educação | EducationBooksAndReference, EarlyLearning, InstructionalTools, Language, StudyAids | | Entretenimento| (Nenhuma) | | FoodAndDining | (Nenhuma) | | GovernmentAndPolitics | (Nenhuma) | | HealthAndFitness | (Nenhuma) | | KidsAndFamily | KidsAndFamilyBooksAndReference, KidsAndFamilyEntertainment, HobbiesAndToys, SportsAndActivities, KidsAndFamilyTravel | | Estilo de Vida | Automotive, DYI, HomeAndGarden, Relationships, SpecialInterest, StyleAndFashion | | Médico | (Nenhuma) | | MultimediaDesign | IllustrationAndGraphicDesign, MusicProduction, PhotoAndVideoProduction | | Music | (Nenhuma) | | NavigationAndMaps | (Nenhuma) | | NewsAndWeather | News, Weather | | PersonalFinance | BankingAndInvestments, BudgetingAndTaxes | | Personalização | RingtonesAndSounds, themes, WallpaperAndLockScreens | | PhotoAndVideo | (Nenhuma) | | Produtividade | (Nenhuma) | | Security | PCProtection, PersonalSecurity | | Compra | (Nenhuma) | | Social | (Nenhuma) | | Esportes | (Nenhuma) | | Viagem | CityGuides, Hotéis | | UtilitiesAndTools | BackupAndManage, FileManager ||

Idiomas

Ver tabela | Nome do idioma | Códigos de idioma suportados | |---------------|--------------------------| | Afrikaans | af, af-za | | Albanês | sq, sq-al | | Amárico | am, am-et | | Armênio | hy, hy-am | | Assamês | as, as-in | | Azerbaijano | az-arab, az-arab-az, az-cyrl, az-cyrl-az, az-latn, az-latn-az | | Basco (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 | | Hauçá | ha, ha-latn, ha-latn-ng | | Hebraico | he, he-il | | Hindi | hi, hi-in | | Húngaro | hu, hu-hu | | Islandês | is, is-is | | Igbo | 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 | | Canarês | kn, kn-in | | Cazaque | kk, kk-kz | | Khmer | km, km-kh | | K'iche' | quc-latn, qut-gt, qut-latn | | Kinyarwanda | rw, rw-rw | | KiSwahili | sw, sw-ke | | Concani | kok, kok-in | | Coreano | ko, ko-kr | | Curdo | ku-arab, ku-arab-iq | | Quirguiz | ky-kg, ky-cyrl | | Laosiano | 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 | | Marathi | mr, mr-in | | Mongol (Cirílico) | mn-cyrl, mn-mong, mn-mn, mn-phag | | Nepalês | ne, ne-np | | Norueguês | nb, nb-no, nn, nn-no, no, no-no | | Odia | or, or-in | | Persa | fa, fa-ir | | Polonês | pl, pl-pl | | Português (Brasil) | pt-br | | Português (Portugal) | pt, pt-pt | | Punjabi | 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 | | Sesotho sa Leboa | nso, nso-za | | Setswana | tn, tn-bw, tn-za | | Sindi | sd-arab, sd-arab-pk, sd-deva | | Cingalês | 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 | | Tajique (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 | | Telugu | te, te-in | | Tailandês | th, th-th | | Tigrínia | 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 | | Uigur | 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 | | Iorubá | 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 ID exclusivo do tipo GUID 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 booleano
erros Matriz de objetos A lista de mensagens de aviso ou de erro, se houver
codificar fio O código de erro da mensagem
mensagem fio A descrição do erro
destino fio A entidade que originou o erro
responseData Objeto Contém payload de resposta real para a solicitação
pollingUrl fio URL de sondagem para obter o status de qualquer submissão em andamento
ongoingSubmissionId fio ID de qualquer submissão 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 para obter os pacotes de rascunho atuais

Busca detalhes do pacote no envio de escalação atual.

Caminho [Todos os pacotes]: /submission/v1/product/{productId}/packages
Método: GET

Caminho [Pacote único]: /submission/v1/product/{productId}/packages/{packageId}
Método: GET

Parâmetros de caminho

Nome Descrição
ID do produto A ID do produto no Partner Center
packageId O ID exclusivo do pacote a ser obtido

Cabeçalhos necessários

Cabeçalho Valor
Authorization: Bearer <Token> Usando a ID do aplicativo Microsoft Entra ID registrada com a conta do Partner Center
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 booleano
erros Matriz de objetos A lista de erros ou mensagens de aviso, se houver
codificar fio O código de erro da mensagem
mensagem fio A descrição do erro
destino fio A entidade que originou o erro
responseData Objeto
pacotes Matriz de objetos Objeto para armazenar dados do módulo de pacote
packageId fio
URL do pacote fio
idiomas Matriz de cadeias de caracteres
arquiteturas Matriz de cadeias de caracteres [Neutro, X86, X64, Arm, Arm64]
isSilentInstall booleano Deve ser marcado como verdadeiro se o instalador for executado no modo sem confirmação sem exigir opções, ou então como falso
Parâmetros do Instalador fio
genericDocUrl fio
detalhes do erro Matriz de objetos
errorScenario fio
errorScenarioDetails Matriz de objetos
errorValue fio
errorUrl fio
tipo de pacote fio

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 um único pacote]: /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
ID do produto A ID do produto no Partner Center
packageId A ID exclusiva do pacote

Cabeçalhos necessários

Cabeçalho Valor
Authorization: Bearer <Token> Usando a ID do aplicativo Microsoft Entra ID registrada com a conta do Partner Center
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]
URL do pacote fio Obrigatório
idiomas Matriz de cadeias de caracteres Obrigatório
arquiteturas Matriz de cadeias de caracteres Obrigatório Deve conter uma única arquitetura - Neutro, X86, X64, Arm, Arm64
isSilentInstall booleano Obrigatório Isso deve ser marcado como verdadeiro se o instalador for executado no modo silencioso sem exigir parâmetros; caso contrário, como falso
Parâmetros do Instalador fio Obrigatório se isSilentInstall for falso
genericDocUrl fio Obrigatório se packageType for exe Link para o documento contendo detalhes dos códigos de erro personalizados para o instalador do tipo EXE
detalhes do erro Matriz de objetos Metadados para armazenar códigos de erro personalizados e detalhes para instaladores do tipo EXE.
errorScenario fio Identificar o cenário de erro específico. [instalacaoCanceladaPeloUsuario, aplicacaoJaExiste, instalacaoJaEmAndamento, espacoNoDiscoCheio, reinicializacaoNecessaria, falhaDeRede, pacoteRejeitadoDuranteInstalacao, instalacaoBemSucedida, diversos]
errorScenarioDetails Matriz de objetos
errorValue fio Código de erro que pode estar presente durante a instalação
errorUrl fio URL para obter detalhes sobre o erro
tipo de pacote fio 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 booleano
erros Matriz de objetos [A lista de mensagens de aviso ou de erro, se houver]
codificar fio O código de erro da mensagem
mensagem fio A descrição do erro
destino fio A entidade que originou o erro
responseData Objeto
pollingUrl fio URL para consultar o status da submissão caso já exista alguma submissão em andamento
ongoingSubmissionId fio [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. Esta API retorna uma URL de polling para acompanhar o upload do pacote.

Caminho: /submission/v1/product/{productId}/packages/commit
Método: POST

Parâmetros de caminho

Nome Descrição
ID do produto A ID do produto no Partner Center

Cabeçalhos necessários

Cabeçalho Valor
Authorization: Bearer <Token> Usando a ID do aplicativo Microsoft Entra ID registrada com a conta do Partner Center
X-Seller-Account-Id A ID do vendedor da conta da Central de Parceiros

Cabeçalhos de resposta

Cabeçalho Valor
X-Correlation-ID ID exclusivo do tipo GUID 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 booleano
erros Matriz de objetos [A lista de mensagens de aviso ou de erro, se houver]
codificar fio O código de erro da mensagem
mensagem fio A descrição do erro
destino fio A entidade que originou o erro
responseData Objeto
pollingUrl fio URL de consulta para obter o status do upload do pacote ou o status da submissão, no caso de já haver alguma submissão em andamento
ongoingSubmissionId fio [ID de qualquer submissão 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: GET

Parâmetros de caminho

Nome Descrição
ID do produto 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> Usando a ID do aplicativo Microsoft Entra ID registrada com a conta do Partner Center
X-Seller-Account-Id A ID do vendedor da conta da Central de Parceiros

Cabeçalhos de resposta

Cabeçalho Valor
X-Correlation-ID ID exclusivo do tipo GUID 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 booleano
erros Matriz de objetos A lista de mensagens de aviso ou de erro, se houver
codificar fio O código de erro da mensagem
mensagem fio A descrição do erro
destino fio A entidade que originou o erro
responseData Objeto
listagem de ativos Matriz de objetos Listando os detalhes dos ativos para cada idioma
linguagem fio
logotipos da loja Matriz de objetos
capturas de tela Matriz de objetos
id fio
assetUrl fio Deve ser um URL válido
tamanhoDaImagem Objeto
largura 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 dos ativos da listagem

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:

  1. Use a API Create Listing Asset para enviar uma solicitação relacionada ao upload de ativos, juntamente com o idioma, o tipo e a quantidade de ativos.
  2. 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 esta URL para fazer upload de recursos de imagem de um tipo específico usando clientes HTTP [Put Blob (API REST) - Armazenamento do Azure | Microsoft Docs].
  3. Após o upload, você pode usar a API Commit Listing Assets para também enviar as novas informações do ID do ativo recebidas anteriormente na chamada anterior da API. A única API confirmará internamente os dados dos ativos da listagem após a validação.
  4. 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: POST

Parâmetros de caminho

Nome Descrição
ID do produto A ID da Central de Parceiros do produto

Cabeçalhos necessários

Cabeçalho Descrição
Authorization: Bearer <Token> Usando a ID do aplicativo Microsoft Entra ID registrada com a conta do Partner Center
X-Seller-Account-Id A ID do vendedor da conta da Central de Parceiros

Parâmetros de solicitação

Nome Tipo Descrição
linguagem fio 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

Cabeçalho 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 booleano
erros Matriz de objetos A lista de mensagens de aviso ou de erro, se houver
codificar fio O código de erro da mensagem
mensagem fio A descrição do erro
destino fio A entidade que originou o erro
responseData Objeto
listagem de ativos Objeto Objeto contendo detalhes de StoreLogos e Screenshots a serem carregados
linguagem fio
storeLogos Matriz de objetos
capturas de tela Matriz de objetos
id fio
primaryAssetUploadUrl fio URL primária para carregar o recurso da listagem usando a API REST do Azure Blob
secondaryAssetUploadUrl fio URL secundária para enviar o recurso da listagem usando a API REST do Azure Blob
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"}

            }]
        }
    } 
}

API para confirmar ativos listados

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
ID do produto A ID do produto no Partner Center

Cabeçalhos necessários

Cabeçalho Descrição
Authorization: Bearer <Token> Usando a ID do aplicativo Microsoft Entra ID registrada com a conta do Partner Center
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 fio
storeLogos Matriz de objetos
capturas de tela Matriz de objetos
id fio 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 fio Deve ser a URL de um ativo existente que o usuário deseja persistir da API Get Current Listing Assets ou a URL de upload — primária ou secundária — por meio da qual um novo ativo foi enviado na API Create Listing Assets. 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

Cabeçalho 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 booleano
erros Matriz de objetos A lista de mensagens de aviso ou de erro, se houver
codificar fio O código de erro da mensagem
mensagem fio A descrição do erro
destino fio A entidade que originou o erro
responseData Objeto
pollingUrl fio URL de sondagem para obter o status de qualquer solicitação em andamento
ongoingSubmissionId fio 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

Pode ser criada uma API para verificar se o módulo está pronto antes da submissão. Também valida o status de upload do pacote.

Caminho: /submission/v1/product/{productId}/status
Método: GET

Parâmetros de caminho

Nome Descrição
ID do produto O ID do produto no Partner Center

Cabeçalhos necessários

Cabeçalho Descrição
Authorization: Bearer <Token> Usando a ID do aplicativo Microsoft Entra ID registrada com a conta do Partner Center
X-Seller-Account-Id A ID do vendedor da conta da Central de Parceiros

Cabeçalhos de resposta

Cabeçalho 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 booleano
erros Matriz de objetos A lista de mensagens de aviso ou de erro, se houver
codificar fio O código de erro da mensagem
mensagem fio A descrição do erro
destino fio A entidade que originou o erro
responseData Objeto
isReady booleano Indica se todos os módulos estão no estado pronto, incluindo o upload do pacote
ongoingSubmissionId fio ID de submissão de qualquer submissão 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 uma submissão a partir do rascunho atual para aplicativo 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: POST

Parâmetros de caminho

Nome Descrição
ID do produto A ID do produto no Partner Center

Cabeçalhos necessários

Cabeçalho Descrição
Authorization: Bearer <Token> Usando a ID do aplicativo Microsoft Entra ID registrada com a conta do Partner Center
X-Seller-Account-Id A ID do vendedor da conta da Central de Parceiros

Cabeçalhos de resposta

Cabeçalho 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 booleano
erros Matriz de objetos A lista de mensagens de aviso ou de erro, se houver
codificar fio O código de erro da mensagem
mensagem fio A descrição do erro
destino fio A entidade que originou o erro
responseData Objeto
pollingUrl fio URL de pesquisa para obter o status de preparação do módulo, incluindo o upload de pacotes para envio
ID de submissão fio O ID da submissão recém-criada
ongoingSubmissionId fio ID de submissão de qualquer submissão 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: GET

Parâmetros de caminho

Nome Descrição
ID do produto A ID do produto no Partner Center

Cabeçalhos necessários

Cabeçalho Descrição
Authorization: Bearer <Token> Usando a ID do aplicativo Microsoft Entra ID registrada com a conta do Partner Center
X-Seller-Account-Id A ID do vendedor da conta da Central de Parceiros

Cabeçalhos de resposta

Cabeçalho 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 booleano
erros Matriz de objetos A lista de mensagens de aviso ou de erro, se houver
codificar fio O código de erro da mensagem
mensagem fio A descrição do erro
destino fio A entidade que originou o erro
responseData Objeto
publishingStatus fio Status de publicação da envio — [INPROGRESS, PUBLISHED, FAILED, UNKNOWN]
hasFailed booleano 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, consulte Como associar um aplicativo de ID do Microsoft Entra à sua conta do Partner Center
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 dados do Diretório do Microsoft Entra ID e 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 Microsoft Entra ID Directory app.
        /// Example" 00001111-aaaa-2222-bbbb-3333cccc4444
        /// </summary>
        public string ClientId { get; set; }

        /// <summary>
        /// Client secret of your Microsoft Entra ID Directory app
        /// </summary>
        public string ClientSecret { get; set; }

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

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

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

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


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

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:

  • Obtenha um token de acesso do Microsoft Entra ID que pode ser usado para chamar métodos na API de submissão 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 Microsoft Entra ID Directory allowing the caller to invoke the API
        /// on behalf of a user
        /// </param>
        /// <param name="serviceUrl">The service URL.</param>
        public SubmissionClient(string accessToken, string serviceUrl)
        {
            if (string.IsNullOrEmpty(accessToken))
            {
                throw new ArgumentNullException("accessToken");
            }

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

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

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

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

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

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

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

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

            return result.access_token;
        }


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

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

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

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

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

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

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

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


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

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 exemplificados neste artigo para demonstrar diferentes formas de usar a API de submissão 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, consulte Como associar um aplicativo de ID do Microsoft Entra à sua conta do Partner Center

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

Assistente de ClientConfiguration

O aplicativo de exemplo usa a classe auxiliar ClientConfiguration para passar dados do Diretório do Microsoft Entra ID e 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;

Assistente do IngestionClient usando 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:

  • Obtenha um token de acesso do Microsoft Entra ID que pode ser usado para chamar métodos na API de submissão 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.

Perguntas frequentes

  1. O que posso fazer por meio da API de envio de Microsoft Store?

    A API de envio da Microsoft Store permite que os desenvolvedores automatizem tarefas de gerenciamento de aplicativos, incluindo:

    • Criando e enviando novas atualizações de aplicativo.
    • Carregar e gerenciar pacotes de aplicativos.
    • Atualização de metadados e listagens da loja.

    Você pode integrar essa API à integração contínua ou criar fluxos de trabalho, automatizando tarefas rotineiras para simplificar o processo de publicação.