API de Envio da Microsoft Store para aplicativos MSI ou EXE

Use a API de envio da Microsoft Store para aplicativos MSI ou EXE para consultar e criar envios programaticamente para aplicativos MSI ou EXE para sua conta na Central de Parceiros ou da sua organização. Essa API é útil caso sua conta gerencie muitos aplicativos e você queira automatizar e otimizar o processo de envio desses ativos. Essa API usa o Azure Active Directory (Azure AD) para autenticar as chamadas do aplicativo ou serviço.

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

  1. Verifique se todos os pré-requisitos foram atendidos.
  2. Antes de chamar um método na API de envio da Microsoft Store, obtenha um token de acesso do Azure AD. Depois de obter um token, você tem 60 minutos para usá-lo em chamadas para a API de envio da Microsoft Store antes que ele expire. Depois que o token expirar, será possível gerar um novo.
  3. Chamar a API de Envio da Microsoft Store para aplicativos MSI ou EXE.

Etapa 1: concluir os pré-requisitos para usar a API de envio da Microsoft Store

Antes de começar a escrever o código para chamar a API de envio da Microsoft Store para aplicativos MSI ou EXE, verifique se os pré-requisitos a seguir foram atendidos.

  • Você (ou sua organização) deve ter um diretório do Azure AD e você deve ter permissão de Administrador global para o diretório. Se já usa o Microsoft 365 ou outros serviços empresariais da Microsoft, você já tem o diretório do Azure AD. Caso contrário, crie um Azure AD na Central de Parceiros sem custo adicional.
  • Associe um aplicativo do Azure AD à sua conta da Central de Parceiros e obtenha a ID do locatário, a ID do cliente e a chave. Esses valores são necessários para obter um token de acesso do Azure AD, que será usado em chamadas para a API de envio da Microsoft Store.
  • Prepare seu aplicativo para uso com a API de envio da Microsoft Store:
    • Se seu aplicativo ainda não existir na Central de Parceiros, você deverá criá-lo reservando seu nome na Central de Parceiros. Não é possível usar a API de envio da Microsoft Store para criar um aplicativo na Central de Parceiros; você deve trabalhar na Central de Parceiros para criá-lo e, depois disso, pode usar a API para acessar o aplicativo e criar envios programaticamente para ele.
    • Antes de criar um envio para um determinado aplicativo usando essa API, você deve primeiro criar um envio para o aplicativo no Partner Center, incluindo responder ao questionário de classificações etárias. Depois de fazer isso, você poderá criar programaticamente envios para esse aplicativo usando a API.
    • Se você estiver criando ou atualizando um envio de aplicativo e precisar incluir um novo pacote, prepare os detalhes do pacote.
    • Se você estiver criando ou atualizando um envio de aplicativo e precisar incluir capturas de tela ou imagens para a listagem da Store, prepare as capturas de tela e imagens do aplicativo.

Como associar um aplicativo do Azure AD à sua conta da Central de Parceiros

Para usar a API de envio da Microsoft Store para aplicativos MSI ou EXE, você deve associar um aplicativo do Azure AD à sua conta da Central de Parceiros, recuperar a ID do locatário e a ID do cliente do aplicativo e gerar uma chave. O aplicativo do Azure AD representa o aplicativo ou serviço do qual você deseja chamar a API de envio da Microsoft Store. Você precisa da ID do locatário, da ID do cliente e da chave para obter um token de acesso do Azure AD que é passado para a API.

Observação

É necessário executar essa tarefa apenas uma vez. Depois de obter a ID do locatário, a ID do cliente e a chave, você poderá reutilizá-las sempre que precisar criar um novo token de acesso do Azure AD.

  1. Na Central de Parceiros, associe a conta da Central de Parceiros da sua organização ao diretório do Azure AD da sua organização.
  2. Em seguida, na página Usuários na seção Configurações da conta da Central de Parceiros, adicione o aplicativo do Azure AD que representa o aplicativo ou serviço que você usará para acessar os envios para sua conta da Central de Parceiros. Lembre-se de atribuir esse aplicativo à função de Gerenciador. Se o aplicativo ainda não existir no diretório do Azure AD, crie um novo aplicativo do Azure AD na Central de Parceiros.
  3. Retorne à página Usuários, clique no nome do seu aplicativo do Azure AD para acessar as configurações do aplicativo e copie os valores de ID do Locatário e ID do Cliente.
  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 Azure Active Directory e selecione-o.

  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 Azure AD

Antes de chamar qualquer um dos métodos na API de envio da Microsoft Store para o aplicativo Microsoft ou EXE, primeiro você deve obter um token de acesso do Azure AD que é passado para o cabeçalho de Autorização de cada método na API. Após obter um token de acesso, você tem 60 minutos para usá-lo antes dele expirar. Depois de expirar, é possível renovar o token para que você possa continuar a usá-lo em chamadas futuras para a API.

Para obter o token de acesso, siga as instruções em [Service to Service Calls Using Client Credentials]/azure/active-directory/azuread-dev/v1-oauth2-client-creds-grant-flow) para enviar um HTTP POST para o ponto de extremidade https://login.microsoftonline.com/<tenant_id>/oauth2/token. Confira a seguir um exemplo de solicitação.

POST https://login.microsoftonline.com/<tenant-id>/oauth2/v2.0/token HTTP/1.1
Host: login.microsoftonline.com
Content-Type: application/x-www-form-urlencoded; charset=utf-8

grant_type=client_credentials
&client_id=<your_client_id>
&client_secret=<your_client_secret>
&scope=https://api.store.microsoft.com/.default

Para o valor tenant_id no URI POST e nos parâmetros client_id e client_secret, especifique a ID do locatário, a ID do cliente e a chave do aplicativo recuperado da Central de Parceiros na seção anterior. Para o parâmetro de escopo, especifique https://api.store.microsoft.com/.default.

Depois que o token de acesso expirar, você poderá renová-lo seguindo as instruções aqui.

Para obter exemplos que demonstram como obter um token de acesso usando C# ou Node.js, confira os exemplos de código da API de envio da Microsoft Store para aplicativos MSI ou EXE.

Etapa 3: Uso da API de envio da Microsoft Store

Depois de obter um token de acesso do Azure AD, você pode chamar métodos na API de envio da Microsoft Store para aplicativos MSI ou EXE. A API inclui muitos métodos que são agrupados em cenários para aplicativos. Para criar ou atualizar envios, normalmente chamam-se vários métodos em uma ordem específica. Para obter informações sobre cada cenário e a sintaxe de cada método, confira as seguintes seções:

Observação

Depois de obter um token de acesso, você tem 60 minutos para usá-lo em chamadas para a API de envio da Microsoft Store para aplicativos MSI ou EXE antes que ele expire.

URL base

A URL base para API de Envio da Microsoft Store para aplicativos MSI ou EXE é: https://api.store.microsoft.com

Contratos de API

Obter a API de metadados de envio de escalação atual

Busca metadados em cada módulo (listagens, propriedades ou disponibilidade) no envio de escalação atual.

Caminho [Todos os módulos]: /submission/v1/product/{productId}/metadata?languages={languages}&includelanguagelist={true/false}
Caminho [Módulo único]: /submission/v1/product/{productId}/metadata/{moduleName}?languages={languages}&includelanguagelist={true/false}
Método: OBTER

Parâmetros de caminho

Parâmetro Descrição
productId A ID da Central de Parceiros do produto
moduleName Módulo Central de Parceiros – listagens, propriedades ou disponibilidade

Parâmetros de consulta

Parâmetro Descrição
idiomas Opcional Os idiomas de listagem filtram como sequência separada por vírgulas [limite de até 200 idiomas].

Se ausentes, os primeiros 200 metadados de idiomas de listagem disponíveis serão recuperados. [ por exemplo, "en-US, en-GB"].
includelanguagelist Booliano opcional – se verdadeiro, retorna a lista de idiomas de listagem adicionados e seu status de completude.

Cabeçalhos necessários

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

Cabeçalhos de resposta

Cabeçalho Valor
X-Correlation-ID O GUID tipo ID exclusivo para cada solicitação. Pode ser compartilhado com a equipe de suporte para analisar qualquer issue.
Retry-After O tempo, em segundos, que o cliente precisa esperar antes de chamar as APIs novamente devido à limitação de fluxo.

Parâmetros de resposta

Nome Tipo Descrição
accessibilitySupport Booliano
additionalLicenseTerms String
availability Objeto Dados do módulo de disponibilidade
category String Confira a lista de categorias abaixo
certificationNotes String
código String O código de erro da mensagem
contactInfo String
copyright String
dependsOnDriversOrNT Booliano
descrição String
desenvolvido por String
detectabilidade String [DETECTÁVEL, DEEPLINK_ONLY]
enableInFutureMarkets Booliano
erros Matriz de objetos A lista de mensagens de aviso ou de erro, se houver
freeTrial String [NO_FREE_TRIAL, FREE_TRIAL]
hardwareItemType String
isPrivacyPolicyRequired Booliano
isRecommended Booliano
IsRequired Booliano
isSuccess Booliano
isSystemFeatureRequired Matriz de objetos
linguagem String Confira a lista de idiomas abaixo
listagens Matriz de objetos Dados do módulo de listagens para cada idioma
mercados Matriz das cadeias de caracteres Confira a lista de mercados abaixo
message String A descrição do erro
minimumHardware String
minimumRequirement String
penAndInkSupport Booliano
preços String [GRATUITO, FREEMIUM, ASSINATURA, PAGO]
privacyPolicyUrl String
productDeclarations Objeto
productFeatures Matriz das cadeias de caracteres
properties Objeto Dados do módulo de propriedades
recommendedHardware String
recommendedRequirement String
responseData Objeto Contém payload de resposta real para a solicitação
requisitos Matriz de objetos
searchTerms Matriz das cadeias de caracteres
shortDescription String
subcategory String Confira a lista de subcategorias abaixo
supportContactInfo String
systemRequirementDetails Matriz de objetos
destino String A entidade que originou o erro
website String
novidades String

Resposta de exemplo

{
    "isSuccess": true,
    "errors": [{
        "code": "badrequest",
        "message": "Error Message 1",
        "target": "listings"
        }, {
        "code": "warning",
        "message": "Warning Message 1",
        "target": "properties"
    }],
    "responseData": {
        "availability":{
            "markets": ["US"],
            "discoverability": "DISCOVERABLE",
            "enableInFutureMarkets": true,
            "pricing": "PAID",
            "freeTrial": "NO_FREE_TRIAL"
        },
        "properties":{
            "isPrivacyPolicyRequired": true,
            "privacyPolicyUrl": "http://contoso.com",
            "website": "http://contoso.com",
            "supportContactInfo": "http://contoso.com",
            "certificationNotes": "Certification Notes",
            "category": "DeveloperTools",
            "subcategory": "Database",
            "productDeclarations": {
                "dependsOnDriversOrNT": false,
                "accessibilitySupport": false,
                "penAndInkSupport": false
            },
            "isSystemFeatureRequired": [
                {
                    "isRequired": true,
                    "isRecommended": false,
                    "hardwareItemType": "Touch"
                },
                {
                    "isRequired": true,
                    "isRecommended": false,
                    "hardwareItemType": "Keyboard"
                },
                {
                    "isRequired": false,
                    "isRecommended": false,
                    "hardwareItemType": "Mouse"
                },
                {
                    "isRequired": false,
                    "isRecommended": false,
                    "hardwareItemType": "Camera"
                },
                {
                    "isRequired": false,
                    "isRecommended": false,
                    "hardwareItemType": "NFC_HCE"
                },
                {
                    "isRequired": false,
                    "isRecommended": false,
                    "hardwareItemType": "NFC_Proximity"
                },
                {
                    "isRequired": false,
                    "isRecommended": false,
                    "hardwareItemType": "Bluetooth_LE"
                },
                {
                    "isRequired": false,
                    "isRecommended": false,
                    "hardwareItemType": "Telephony"
                },
                {
                    "isRequired": false,
                    "isRecommended": false,
                    "hardwareItemType": "Microphone"
                }
            ],
            "systemRequirementDetails": [
                {
                    "minimumRequirement": "1GB",
                    "recommendedRequirement": "4GB",
                    "hardwareItemType": "Memory"
                },
                {
                    "minimumRequirement": "",
                    "recommendedRequirement": "",
                    "hardwareItemType": "DirectX"
                },
                {
                    "minimumRequirement": "",
                    "recommendedRequirement": "",
                    "hardwareItemType": "Video_Memory"
                },
                {
                    "minimumRequirement": "",
                    "recommendedRequirement": "",
                    "hardwareItemType": "Processor"
                },
                {
                    "minimumRequirement": "",
                    "recommendedRequirement": "",
                    "hardwareItemType": "Graphics"
                }
            ]
        },
        "listings":[{
            "language": "en-us",
            "description": "Description",
            "whatsNew": "What's New",
            "productFeatures": ["Feature 1"],
            "shortDescription": "Short Description",
            "searchTerms": ["Search Ter 1"],
            "additionalLicenseTerms": "License Terms",
            "copyright": "Copyright Information",
            "developedBy": "Developer Details",
            "sortTitle": "Product 101",
            "requirements": [
                {
                    "minimumHardware": "Pentium4",
                    "recommendedHardware": "Corei9"
                }
            ],
            "contactInfo": "contactus@contoso.com"               
        }],      
        "listingLanguages": [{"language":"en-us", "isComplete": true}]
    }
}

Atualizar a API de metadados de envio de escalação atual

Atualiza os metadados em cada módulo no envio de escalação. A API verifica

  • Para envio ativo. Se existir, falha com mensagem de erro.
  • Se todos os módulos estiverem no status pronto para permitir a operação Salvar rascunho.
  • Cada campo no envio é validado de acordo com os requisitos da Store
  • Regras de validação dos detalhes do requisito do sistema:
    • Valores permitidos em hardwareItemType = Memória: 300MB, 750MB, 1GB, 2GB, 4GB, 6GB, 8GB, 12GB, 16GB, 20GB
    • Valores permitidos em hardwareItemType = DirectX: DX9, DX10, DX11, DX12-FEATURELEVEL11, DX12-FEATURELEVEL12
    • Valores permitidos em hardwareItemType = Video_Memory: 1GB, 2GB, 4GB, 6GB

Caminho [Atualização completa de módulo]: /submission/v1/product/{productId}/metadata
Método: PUT

Caminho [Atualização de patch de módulo]: /submission/v1/product/{productId}/metadata
Método: PATCH

Comportamento da API

No caso da API de Atualização Completa de Módulo – todos os dados de módulo precisam estar presentes na solicitação de atualização completa de cada campo. Qualquer campo que não esteja presente na solicitação, seu valor padrão é usado para substituir o valor atual desse módulo específico.
No caso da API de Atualização do Módulo de Patch – apenas os campos que devem ser atualizados precisam estar presentes na solicitação. Esses valores de campo da Solicitação substituirão os valores existentes, mantendo todos os outros campos que não estão presentes na solicitação, iguais aos atuais para esse módulo específico.

Parâmetros de caminho

Parâmetro Descrição
productId A ID da Central de Parceiros do produto

Cabeçalhos necessários

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

Parâmetros de solicitação

Nome Tipo Descrição
availability Objeto Objeto para armazenar os metadados do Módulo de Disponibilidade
mercados Matriz das cadeias de caracteres Obrigatório Confira a lista de mercados abaixo
detectabilidade String Obrigatório [DETECTÁVEL, DEEPLINK_ONLY]
enableInFutureMarkets Booliano Obrigatório
preços String Obrigatório [FREE, FREEMIUM, SUBSCRIPTION, PAID]
freeTrial String Obrigatório se o preço for PAGO ou ASSINATURA [NO_FREE_TRIAL, FREE_TRIAL]
properties Objeto Objeto para armazenar os metadados do módulo de propriedades
isPrivacyPolicyRequired Booliano Obrigatório
privacyPolicyUrl String Obrigatório se isPrivacyPolicyRequired = true Deve ser uma URL válida
website String Deve ser um URL válido
supportContactInfo String Deve ser um URL ou end. email válido
certificationNotes String Limite recomendado de caracteres = 2.000
category String Obrigatório Confira a lista de categorias abaixo
subcategory String Obrigatório Confira a lista de subcategorias abaixo
productDeclarations Objeto Obrigatório
isSystemFeatureRequired Matriz de objetos [Toque, Teclado, Mouse, Câmera, NFC_HCE, NFC_Proximity, Bluetooth_LE, Telefonia, Microfone]
IsRequired Booliano Obrigatório
isRecommended Booliano Obrigatório
hardwareItemType String Obrigatório
systemRequirementDetails Matriz de objetos [Processador, Gráficos, Memória, DirectX Video_Memory]
minimumRequirement String Obrigatório para systemRequirementsText, MaxLength = 200

Valores permitidos em hardwareItemType = Memória: [300MB, 750MB, 1GB, 2GB, 4GB, 6GB, 8GB, 12GB, 16GB, 20GB]

Valores permitidos em hardwareItemType = DirectX: [DX9, DX10, DX11, DX12-FEATURELEVEL11, DX12-FEATURELEVEL12]

Valores permitidos em hardwareItemType = Video_Memory: [1GB, 2GB, 4GB, 6GB]
recommendedRequirement String Obrigatório para systemRequirementsText, MaxLength = 200

Valores permitidos em hardwareItemType = Memória: [300MB, 750MB, 1GB, 2GB, 4GB, 6GB, 8GB, 12GB, 16GB, 20GB]

Valores permitidos em hardwareItemType = DirectX: [DX9, DX10, DX11, DX12-FEATURELEVEL11, DX12-FEATURELEVEL12]

Valores permitidos em hardwareItemType = Video_Memory: [1GB, 2GB, 4GB, 6GB]
dependsOnDriversOrNT Booliano Obrigatório
accessibilitySupport Booliano Obrigatório
penAndInkSupport Booliano Obrigatório
listagens Objeto Objeto para listar os dados de módulo de um único idioma
linguagem String Obrigatório Confira a lista de idiomas abaixo
descrição String Limite obrigatório de caracteres = 10.000
novidades String Limite de caracteres = 1.500
productFeatures Matriz de sequência 200 caracteres por recurso; até 20 recursos
shortDescription String Limite de caracteres = 1.000
searchTerms Matriz de sequência 30 caracteres por termo de pesquisa; até 7 termos de pesquisa

TOTAL de 21 palavras únicas em todos os termos de pesquisa
additionalLicenseTerms String Limite obrigatório de caracteres = 10.000
copyright String Limite de caracteres = 200
desenvolvido por String Limite de caracteres = 255
requisitos Matriz de objetos 200 caracteres por item; TOTAL de até 11 itens entre o mínimo e o recomendado]
minimumHardware String Limite de caracteres = 200
recommendedHardware String Limite de caracteres = 200
contactInfo String Limite de caracteres = 200
listagensToAdd Matriz das cadeias de caracteres Confira a lista de idiomas abaixo
listagensToRemove Matriz das cadeias de caracteres Confira a lista de idiomas abaixo

Mercados

Mercado Abreviação
Afeganistão AF
Albânia AL
Argélia DZ
Samoa Americana AS
Andorra AD
Angola AO
Anguila IA
Antártica AQ
Antígua e Barbuda AG
Argentina AR
Armênia AM
Aruba AW
Austrália AU
Áustria AT
Azerbaijão AZ
Bahamas BS
Bahrein BH
Bangladesh BD
Barbados BB
Bielorrússia BY
Bélgica BE
Belize BZ
Benin BJ
Bermudas BM
Butão BT
República Bolivariana da Venezuela VE
Bolívia BO
Bonaire BQ
Bósnia e Herzegovina BA
Botsuana BW
Ilha Bouvet BV
Brasil BR
Território Britânico do Oceano Índico IO
Ilhas Virgens Britânicas VG
Brunei BN
Bulgária BG
Burquina Faso BF
Burundi BI
Camboja KH
Camarões CM
Canadá CA
Cabo Verde CV
Ilhas Cayman KY
República Centro-Africana CF
Chade TD
Chile CL
China CN
Ilha Christmas CX
Ilhas Cocos (Keeling) CC
Colômbia CO
Comores KM
Congo CG
Congo (RDC) CD
Ilhas Cook CK
Costa Rica CR
Croácia RH
Curaçao CW
Chipre CY
República Tcheca CZ
Côte d’Ivoire CI
Dinamarca DK
Djibuti DJ
Dominica DM
República Dominicana O QUE FAZER
Equador EC
Egito EG
El Salvador SV
Guiné Equatorial GQ
Eritreia ER
Estônia EE
Etiópia ET
Ilhas Malvinas FK
Ilhas Faroé FO
Fiji FJ
Finlândia FI
França FR
Guiana Francesa GF
Polinésia Francesa PF
Terras Austrais e Antárticas Francesas TF
Gabão GA
Gâmbia GM
Geórgia GE
Alemanha DE
Gana GH
Gibraltar GI
Grécia GR
Groenlândia GL
Granada GD
Guadalupe GP
Guam GU
Guatemala GT
Guernsey GG
Guiné GN
Guiné-Bissau GW
Guiana GY
Haiti HT
Ilhas Heard e McDonald HM
Cidade do Vaticano VA
Honduras HN
RAE de Hong Kong HK
Hungria HU
Islândia IS
Índia IN
Indonésia ID
Iraque IQ
Irlanda IE
Israel IL
Itália IT
Jamaica JM
Japão JP
Jersey JE
Jordan JO
Cazaquistão KZ
Quênia KE
Quiribati KI
Coreia do Sul KR
Kuwait KW
Quirguistão KG
Laos LA
Letônia LV
Líbano LB
Lesoto LS
Libéria LR
Líbia LY
Liechtenstein LI
Lituânia LT
Luxemburgo LU
RAE de Macau MO
Macedônia do Norte MK
Madagascar MG
Malaui MW
Malásia MY
Maldivas MV
Mali ML
Malta MT
Ilha de Man IM
Ilhas Marshall MH
Martinica MQ
Mauritânia MR
Maurício MU
Mayotte YT
México MX
Micronésia FM
Moldova MD
Mônaco MC
Mongólia MN
Montenegr - ME
Montserrat MS
Marrocos MA
Moçambique MZ
Myanmar MM
Namíbia NA
Nauru NR
Nepal NP
Países Baixos NL
Nova Caledônia NC
Nova Zelândia NZ
Nicarágua NI
Níger NE
Nigéria NG
Niue NU
Ilha Norfolk NF
Ilhas Marianas do Norte MP
Noruega NO
Omã OM
Paquistão PK
Palau PW
Autoridade Palestina PS
Panamá PA
Papua-Nova Guiné PG
Paraguai PY
Peru PE
Filipinas PH
Ilhas Pitcairn PN
Polônia PL
Portugal PT
Qatar QA
Reunião RE
Romênia RO
Rússia RU
Ruanda RW
São Bartolomeu BL
Santa Helena, Ascensão e Tristão da Cunha SH
São Cristóvão e Nevis KN
Santa Lúcia LC
Saint Martin (parte francesa) MF
São Pedro e Miquelon PM
São Vicente e Granadinas VC
Samoa WS
San Marino SM
Arábia Saudita SA
Senegal SN
Sérvia RS
Seicheles SC
Serra Leoa SL
Singapura SG
Sint Maarten (parte holandesa) SX
Eslováquia SK
Eslovênia SI
Ilhas Salomão SB
Somália SO
África do Sul ZA
Ilhas Geórgia do Sul e Sandwich do Sul GS
Espanha ES
Sri Lanka LK
Suriname SR
Svalbard e Jan Mayen SJ
Suazilândia SZ
Suécia SE
Suíça CH
São Tomé e Príncipe ST
Taiwan TW
Tadjiquistão TJ
Tanzânia TZ
Tailândia TH
Timor-Leste TL
Tog - TG
Tokelau TK
Tonga TO
Trinidad e Tobago - TT
Tunísia TN
Turquia TR
Turcomenistão TM
Ilhas Turcas e Caicos TC
Tuvalu TV
EUA Ilhas Menores Distantes UM
Ilhas Virgens Americanas VI
Uganda UG
Ucrânia UA
Emirados Árabes Unidos AE
Reino Unido GB
Estados Unidos EUA
Uruguai UY
Uzbequistão UZ
Vanuatu VU
Vietnã VN
Wallis e Futuna WF
Iêmen YE
Zâmbia ZM
Zimbábue ZW
Ilhas Aland AX

Categorias e subcategorias

Categoria Subcategorias
Livros e Referência EReader, Ficção, Não-ficção, Referência
Negócios Contabilidade e finanças, colaboração, CRM, dados e análises, gerenciamento de arquivos, inventário e logística, jurídico e RH, gerenciamento de projetos, desktop remoto, vendas e marketing, tempo e despesas
DeveloperTools Banco de Dados, ferramentas de design, Kits de Desenvolvimento, Redes, Referência e Treinamento, Servidores, Utilitários, WebHosting
Education Educação, livros e referências, aprendizagem precoce, ferramentas instrucionais, idiomas, materiais de estudo
Entretenimento (Nenhuma)
FoodAndDining (Nenhuma)
Governo e política (Nenhuma)
Saúde e fitness (Nenhuma)
Crianças e família Crianças e Família, Livros e Referência, Crianças, Família e Entretenimento, Hobbies e brinquedos, Esportes e atividades, Crianças, Família e Viagem
Estilo de vida Automotivo, DYI, Casa e jardim, Relacionamentos, Interesse especial, Moda e estilo
Médicos (Nenhuma)
Design multimídia Ilustração e design gráfico, Produção musical, Produção de foto e vídeo
Música (Nenhuma)
Navegação e mapas (Nenhuma)
Notícias e meteorologia Notícias e Meteorologia
Finanças Pessoais Bancos e investimentos, Orçamento e impostos
Personalização Toques e sons, temas, papéis de parede e telas de bloqueio
Foto e vídeo (Nenhuma)
Produtividade (Nenhuma)
Segurança Proteção de PC, Segurança pessoal
Compras (Nenhuma)
Social (Nenhuma)
Esportes (Nenhuma)
Viagem Guias da cidades, Hotéis
Utilitários e ferramentas Backup e gerenciamento, Gerenciador de arquivos

Idiomas

Nome do idioma Códigos de idioma com suporte
Africâner af, af-za
Albanês sq, sq-al
Amárico am, am-et
Armênia hy, hy-am
Assamês as, as-in
Azerbaidjano az-arab, az-arab-az, az-cyrl, az-cyrl-az, az-latn, az-latn-az
Basco (País Basco) eu, eu-es
Bielorrusso be, be-by
Bangla bn, bn-bd, bn-in
Bósnio bs, bs-cyrl, bs-cyrl-ba, bs-latn, bs-latn-ba
Búlgaro bg, bg-bg
Catalão ca, ca-es, ca-es-valencia
Cherokee chr-cher, chr-cher-us, chr-latn
Chinês (simplificado) zh-Hans, zh-cn, zh-hans-cn, zh-sg, zh-hans-sg
Chinês (tradicional) zh-Hant, zh-hk, zh-mo, zh-tw, zh-hant-hk, zh-hant-mo, zh-hant-tw, zh-mo, zh-tw, zh-hant-hk, zh-hant-mo, zh-hant-tw
Croata hr, hr-hr, hr-ba
Tcheco cs, cs-cz
Dinamarquês da, da-dk
Dari prs, prs-af, prs-arab
Holandês nl, nl-nl, nl-be
Inglês en, en-au, en-ca, en-gb, en-ie, en-in, en-nz, en-sg, en-us, en-za, en-bz, en-hk, en-id, en-jm, en-kz, en-mt, en-my, en-ph, en-pk, en-tt, en-vn, en-zw
Estoniano et, et-ee
Filipino - fil, fil-latn, fil-ph
Finlandês fi, fi-fi
Francês fr, fr-be , fr-ca , fr-ch , fr-fr , fr-lu, fr-cd, fr-ci, fr-cm, fr-ht, fr-ma, fr-mc, fr-ml, fr-re, frc-latn, frp-latn
Galego gl, gl-es
Georgiano ka, ka-ge
Alemão de, de-at, de-ch, de-de, de-lu, de-li
Grego el, el-gr
Guzerate gu, gu-in
Hausa ha, ha-latn, ha-latn-ng
Hebraico he, he-il
Híndi hi, hi-in
Húngaro hu, hu-hu
Islandês is, is-is
Igb - ig-latn, ig-ng
Indonésio id, id-id
Inuktitut (Latino) iu-cans, iu-latn, iu-latn-ca
Irlandês ga, ga-ie
isiXhosa xh, xh-za
isiZulu zu, zu-za
Italiano it, it-it, it-ch
Japonês ja , ja-jp
canarim kn, kn-in
Cazaque kk, kk-kz
Khmer km, km-kh
Quiché quc-latn, qut-gt, qut-latn
Quiniaruanda rw, rw-rw
KiSwahili sw, sw-ke
Concani kok, kok-in
Coreano ko, ko-kr
Curdo ku-arab, ku-arab-iq
Kyrgyz ky-kg, ky-cyrl
Lao lo, lo-la
Letão lv, lv-lv
Lituano lt, lt-lt
Luxemburguês lb, lb-lu
Macedônio mk, mk-mk
Malaio ms, ms-bn, ms-my
Malaiala ml, ml-in
Maltês mt, mt-mt
Maori mi, mi-latn, mi-nz
Marati mr, mr-in
Mongol (Cirílico) mn-cyrl, mn-mong, mn-mn, mn-phag
Nepali ne, ne-np
Norueguês nb, nb-no, nn, nn-no, no, no-no
Oriá or, or-in
Persa fa, fa-ir
Polonês pl, pl-pl
Português (Brasil) pt-br
Português (Portugal) pt, pt-pt
Panjabi pa, pa-arab, pa-arab-pk, pa-deva, pa-in
Quíchua quz, quz-bo, quz-ec, quz-pe
Romeno ro, ro-ro
Russo ru , ru-ru
Gaélico escocês gd-gb, gd-latn
Sérvio (latino) sr-Latn, sr-latn-cs, sr, sr-latn-ba, sr-latn-me, sr-latn-rs
Sérvio (cirílico) sr-cyrl, sr-cyrl-ba, sr-cyrl-cs, sr-cyrl-me, sr-cyrl-rs
Soto setentrional nso, nso-za
Setsuana tn, tn-bw, tn-za
Sindhi sd-arab, sd-arab-pk, sd-deva
Sinhala si, si-lk
Eslovaco sk, sk-sk
Esloveno sl, sl-si
Espanhol es, es-cl, es-co, es-es, es-mx, es-ar, es-bo, es-cr, es-do, es-ec, es-gt, es-hn, es-ni, es-pa, es-pe, es-pr, es-py, es-sv, es-us, es-uy, es-ve
Sueco sv, sv-se, sv-fi
Tadjique (Cirílico) tg-arab, tg-cyrl, tg-cyrl-tj, tg-latn
Tâmil ta, ta-in
Tártaro tt-arab, tt-cyrl, tt-latn, tt-ru
Télugo te, te-in
Tailandês th, th-th
Tigrinya ti, ti-et
Turco tr, tr-tr
Turcomeno tk-cyrl, tk-latn, tk-tm, tk-latn-tr, tk-cyrl-tr
Ucraniano uk, uk-ua
Urdu ur, ur-pk
Uyghur ug-arab, ug-cn, ug-cyrl, ug-latn
Uzbeque (latino) uz, uz-cyrl, uz-latn, uz-latn-uz
Vietnamita vi, vi-vn
Galês cy, cy-gb
Wolof wo, wo-sn
Ioruba yo-latn, yo-ng

Solicitação de Exemplo

{
    "availability":{
        "markets": ["US"],
        "discoverability": "DISCOVERABLE",
        "enableInFutureMarkets": true,
        "pricing": "PAID",
        "freeTrial": "NO_FREE_TRIAL"
    },
    "properties":{
        "isPrivacyPolicyRequired": true,
        "privacyPolicyUrl": "http://contoso.com",
        "website": "http://contoso.com",
        "supportContactInfo": "http://contoso.com",
        "certificationNotes": "Certification Notes",
        "category": "DeveloperTools",
        "subcategory": "Database",
        "productDeclarations": {
            "dependsOnDriversOrNT": false,
            "accessibilitySupport": false,
            "penAndInkSupport": false
        },
        "isSystemFeatureRequired": [
        {
            "isRequired": true,
                "isRecommended": false,
                "hardwareItemType": "Touch"
            },
            {
                "isRequired": true,
                "isRecommended": false,
                "hardwareItemType": "Keyboard"
            },
            {
                "isRequired": false,
                "isRecommended": false,
                "hardwareItemType": "Mouse"
            },
            {
                "isRequired": false,
                "isRecommended": false,
                "hardwareItemType": "Camera"
            },
            {
                "isRequired": false,
                "isRecommended": false,
                "hardwareItemType": "NFC_HCE"
            },
            {
                "isRequired": false,
                "isRecommended": false,
                "hardwareItemType": "NFC_Proximity"
            },
            {
                "isRequired": false,
                "isRecommended": false,
                "hardwareItemType": "Bluetooth_LE"
            },
            {
                "isRequired": false,
                "isRecommended": false,
                "hardwareItemType": "Telephony"
            },
            {
                "isRequired": false,
                "isRecommended": false,
                "hardwareItemType": "Microphone"
            }
        ],
        "systemRequirementDetails": [
            {
                "minimumRequirement": "1GB",
                "recommendedRequirement": "4GB",
                "hardwareItemType": "Memory"
            },
            {
                "minimumRequirement": "",
                "recommendedRequirement": "",
                "hardwareItemType": "DirectX"
            },
            {
                "minimumRequirement": "",
                "recommendedRequirement": "",
                "hardwareItemType": "Video_Memory"
            },
            {
                "minimumRequirement": "",
                "recommendedRequirement": "",
                "hardwareItemType": "Processor"
            },
            {
                "minimumRequirement": "",
                "recommendedRequirement": "",
                "hardwareItemType": "Graphics"
            }
        ]
    },
    "listings":{
        "language": "en-us",
        "description": "Description",
        "whatsNew": "What's New",
        "productFeatures": ["Feature 1"],
        "shortDescription": "Short Description",
        "searchTerms": ["Search Ter 1"],
        "additionalLicenseTerms": "License Terms",
        "copyright": "Copyright Information",
        "developedBy": "Developer Details",
        "sortTitle": "Product 101",
        "requirements": [
            {
                "minimumHardware": "Pentium4",
                "recommendedHardware": "Corei9"
            }
        ],
        "contactInfo": "contactus@contoso.com"               
    },      
    "listingsToAdd": ["en-au"],
    "listingsToRemove": ["en-gb"]
}

Cabeçalhos de resposta

Cabeçalho Valor
X-Correlation-ID O GUID tipo ID exclusivo para cada solicitação. Pode ser compartilhado com a equipe de suporte para analisar qualquer issue.
Retry-After O tempo, em segundos, que o cliente precisa esperar antes de chamar as APIs novamente devido ao limite de taxa

Parâmetros de resposta

Nome Tipo Descrição
isSuccess Booliano
erros Matriz de objetos A lista de mensagens de aviso ou de erro, se houver
código String O código de erro da mensagem
message String A descrição do erro
destino String A entidade que originou o erro
responseData Objeto Contém payload de resposta real para a solicitação
pollingUrl String URL de pesquisa para obter o status de qualquer envio em andamento
ongoingSubmissionId String ID de envio de qualquer envio já em andamento

Resposta de exemplo

{
    "isSuccess": true,
    "errors": [{
        "code": "badrequest",
        "message": "Error Message 1",
        "target": "listings"
        }, {
        "code": "warning",
        "message": "Warning Message 1",
        "target": "properties"
    }],
    "responseData": {
        "pollingUrl": "/submission/v1/product/{productId}/submission/{submissionId}/status",
        "ongoingSubmissionId": ""
    } 
}

Obter a API de pacotes de rascunho atual

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

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

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

Parâmetros de caminho

Nome Descrição
productId A ID da Central de Parceiros do produto
packageId A ID exclusiva do pacote a ser buscado

Cabeçalhos necessários

Cabeçalho Valor
Authorization: Bearer <Token> Usar a ID do aplicativo Azure AD registrada com a conta da Central de Parceiros
X-Seller-Account-Id A ID do vendedor da conta da Central de Parceiros

Cabeçalhos de resposta

Cabeçalho Valor
X-Correlation-ID O GUID tipo ID exclusivo para cada solicitação. Pode ser compartilhado com a equipe de suporte para analisar qualquer issue.
Retry-After O tempo, em segundos, que o cliente precisa esperar antes de chamar as APIs novamente devido à limitação de fluxo.

Parâmetros de resposta

Nome Tipo Descrição
isSuccess Booliano
erros Matriz de objetos A lista de erros ou mensagens de aviso, se houver
código String O código de erro da mensagem
message String A descrição do erro
destino String A entidade que originou o erro
responseData Objeto
pacotes Matriz de objetos Objeto para armazenar dados do módulo de pacote
packageId String
packageUrl String
idiomas Matriz das cadeias de caracteres
arquiteturas Matriz das cadeias de caracteres [Neutro, X86, X64, Arm, Arm64]
isSilentInstall Booliano Deve ser marcado como verdadeiro se o instalador for executado no modo sem confirmação sem exigir opções, ou então como falso
installerParameters String
genericDocUrl String
errorDetails Matriz de objetos
errorScenario String
errorScenarioDetails Matriz de objetos
errorValue String
errorUrl String
packageType String

Resposta de exemplo

{   
    "isSuccess": true,
    "errors": [{
        "code": "badrequest",
        "message": "Error Message 1",
        "target": "listings"
    }, {
        "code": "warning",
        "message": "Warning Message 1",
        "target": "properties"
    }],
    "responseData":{
        "packages":[{
            "packageId": "pack0832",
            "packageUrl": "https://www.contoso.com/downloads/1.1/setup.exe",
            "languages": ["en-us"],
            "architectures": ["X86"],
            "isSilentInstall": true,
            "installerParameters": "/s",
            "genericDocUrl": "https://docs.contoso.com/doclink",
            "errorDetails": [{
                "errorScenario": "rebootRequired",
                "errorScenarioDetails": [{
                    "errorValue": "ERR001001",
                    "errorUrl": "https://errors.contoso.com/errors/ERR001001"
                }]
            }],
            "packageType": "exe",
        }]
    }
}

Atualizar a API de pacotes de rascunho atual

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

Caminho [Atualização completa do módulo]: /submission/v1/product/{productId}/packages
Método: PUT

Caminho [Atualização de patch de pacote único]: /submission/v1/product/{productId}/packages/{packageId}
Método: PATCH

Comportamento da API

No caso da API de Atualização Completa de Módulo – todos os dados de pacotes precisam estar presentes na solicitação de atualização completa de cada campo. Qualquer campo que não esteja presente na solicitação, seu valor padrão é usado para substituir o valor atual desse módulo específico. O resultado é a substituição de todos os pacotes existentes por um novo conjunto de pacotes da solicitação. O que causará a regeneração das IDs de Pacote e fará com que o usuário precise chamar a API de Pacotes GET para obter as IDs de Pacote mais recentes.

No caso da API de Atualização de Patch de Pacote Único – somente os campos de um determinado pacote a serem atualizados precisam estar presentes na solicitação. Esses valores de campo da solicitação substituirão os valores existentes, mantendo todos os outros campos que não estão presentes na solicitação iguais aos atuais desse pacote específico. Outros pacotes no conjunto permanecem como estão.

Parâmetros de caminho

Nome Descrição
productId A ID da Central de Parceiros do produto
packageId A ID exclusiva do pacote

Cabeçalhos necessários

Cabeçalho Valor
Authorization: Bearer <Token> Usar a ID do aplicativo Azure AD registrada com a conta da Central de Parceiros
X-Seller-Account-Id A ID do vendedor da conta da Central de Parceiros

Parâmetros de solicitação

Nome Tipo Descrição
pacotes Matriz de objetos Objeto para armazenar os dados do módulo de pacote [Obrigatório somente para a atualização completa do módulo]
packageUrl String Obrigatório
idiomas Matriz das cadeias de caracteres Obrigatório
arquiteturas Matriz das cadeias de caracteres Obrigatório Deve conter uma única arquitetura - Neutro, X86, X64, Arm, Arm64
isSilentInstall Booliano Obrigatório Deve ser marcado como verdadeiro se o instalador for executado no modo sem confirmação sem exigir opções, ou então como falso
installerParameters String Obrigatório se isSilentInstall for falso
genericDocUrl String Obrigatório se packageType for exe Link para documento que contém detalhes de códigos de erro personalizados para o instalador do tipo EXE
errorDetails Matriz de objetos Metadados para armazenar códigos de erro personalizados e detalhes para instaladores do tipo EXE.
errorScenario String Identificar o cenário de erro específico. [installationCancelledByUser, applicationAlreadyExists, installationAlreadyInProgress, diskSpaceIsFull, rebootRequired, networkFailure, packageRejectedDuringInstallation, installationSuccessful, miscellaneous]
errorScenarioDetails Matriz de objetos
errorValue String Código de erro que pode estar presente durante a instalação
errorUrl String URL para obter detalhes sobre o erro
packageType String Obrigatório [exe, msi]

Solicitação de exemplo [Atualização completa do módulo]

{
    "packages":[{
        "packageUrl": "https://www.contoso.com/downloads/1.1/setup.exe",
        "languages": ["en-us"],
        "architectures": ["X86"],
        "isSilentInstall": true,
        "installerParameters": "/s",
        "genericDocUrl": "https://docs.contoso.com/doclink",
        "errorDetails": [{
            "errorScenario": "rebootRequired",
            "errorScenarioDetails": [{
                "errorValue": "ERR001001",
                "errorUrl": "https://errors.contoso.com/errors/ERR001001"
            }]
        }],
        "packageType": "exe",
    }]
}

Solicitação de exemplo [Atualização de patch de pacote único]

{
    "packageUrl": "https://www.contoso.com/downloads/1.1/setup.exe",
    "languages": ["en-us"],
    "architectures": ["X86"],
    "isSilentInstall": true,
    "installerParameters": "/s",
    "genericDocUrl": "https://docs.contoso.com/doclink",
    "errorDetails": [{
        "errorScenario": "rebootRequired",
        "errorScenarioDetails": [{
            "errorValue": "ERR001001",
            "errorUrl": "https://errors.contoso.com/errors/ERR001001"
        }]
    }],
    "packageType": "exe",
}

Cabeçalhos de resposta

Cabeçalho Valor
X-Correlation-ID O GUID tipo ID exclusivo para cada solicitação. Pode ser compartilhado com a equipe de suporte para analisar qualquer issue.
Retry-After O tempo, em segundos, que o cliente precisa esperar antes de chamar as APIs novamente devido à limitação de fluxo.

Parâmetros de resposta

Nome Tipo Descrição
isSuccess Booliano
erros Matriz de objetos [A lista de mensagens de aviso ou de erro, se houver]
código String O código de erro da mensagem
message String A descrição do erro
destino String A entidade que originou o erro
responseData Objeto
pollingUrl String [URL de pesquisa para obter o status de envio no caso de haver qualquer envio já em andamento]
ongoingSubmissionId String [ID de envio de qualquer envio já em andamento]

Resposta de exemplo

{
    "isSuccess": true,
    "errors": [{
        "code": "badrequest",
        "message": "Error Message 1",
        "target": "listings"
        }, {
        "code": "warning",
        "message": "Warning Message 1",
        "target": "properties"
    }],
    "responseData": {
        "pollingUrl": "/submission/v1/product/{productId}/submission/{submissionId}/status",
        "ongoingSubmissionId": ""
    } 
}

Fazer commit de API de Pacotes

Confirma o novo conjunto de Pacotes atualizados usando APIs de Atualização do Pacote no envio de escalação atual. Essa API retorna uma URL de pesquisa para rastrear o Upload do Pacote.

Caminho: /submission/v1/product/{productId}/packages/commit
Método: LANÇAR

Parâmetros de caminho

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

Cabeçalhos necessários

Cabeçalho Valor
Authorization: Bearer <Token> Usar a ID do aplicativo Azure AD registrada com a conta da Central de Parceiros
X-Seller-Account-Id A ID do vendedor da conta da Central de Parceiros

Cabeçalhos de resposta

Cabeçalho Valor
X-Correlation-ID O GUID tipo ID exclusivo para cada solicitação. Pode ser compartilhado com a equipe de suporte para analisar qualquer issue.
Retry-After O tempo, em segundos, que o cliente precisa esperar antes de chamar as APIs novamente devido à limitação de fluxo.

Parâmetros de resposta

Nome Tipo Descrição
isSuccess Booliano
erros Matriz de objetos [A lista de mensagens de aviso ou de erro, se houver]
código String O código de erro da mensagem
message String A descrição do erro
destino String A entidade que originou o erro
responseData Objeto
pollingUrl String [URL de pesquisa para obter o status de upload de pacote ou status de envio no caso de haver qualquer envio Já em andamento]
ongoingSubmissionId String [ID de envio de qualquer envio já em andamento]

Resposta de exemplo

{
    "isSuccess": true,
    "errors": [{
        "code": "badrequest",
        "message": "Error Message 1",
        "target": "listings"
        }, {
        "code": "warning",
        "message": "Warning Message 1",
        "target": "properties"
    }],
    "responseData": {
        "pollingUrl": "/submission/v1/product/{productId}/status",
        "ongoingSubmissionId": ""
    } 
}

Obter a API de ativos da listagem de rascunho atual

Busca detalhes de ativos de listagem no envio de escalação atual.

Caminho: /submission/v1/product/{productId}/listings/assets?languages={languages}
Método: OBTER

Parâmetros de caminho

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

Parâmetros de consulta

Nome Descrição
idiomas [Opcional] Os idiomas de listagem são filtrados como sequência separada por vírgulas [limite de até 200 idiomas]. Se ausentes, os primeiros 200 dados de ativos de idiomas de listagem disponíveis serão recuperados. (por exemplo, "en-US, en-GB")

Cabeçalhos necessários

Cabeçalho Valor
Authorization: Bearer <Token> Usar a ID do aplicativo Azure AD registrada com a conta da Central de Parceiros
X-Seller-Account-Id A ID do vendedor da conta da Central de Parceiros

Cabeçalhos de resposta

Cabeçalho Valor
X-Correlation-ID O GUID tipo ID exclusivo para cada solicitação. Pode ser compartilhado com a equipe de suporte para analisar qualquer issue.
Retry-After O tempo, em segundos, que o cliente precisa esperar antes de chamar as APIs novamente devido à limitação de fluxo.

Parâmetros de resposta

Nome Tipo Descrição
isSuccess Booliano
erros Matriz de objetos A lista de mensagens de aviso ou de erro, se houver
código String O código de erro da mensagem
message String A descrição do erro
destino String A entidade que originou o erro
responseData Objeto
listagem de ativos Matriz de objetos Listagem dos detalhes de ativos de cada idioma
linguagem String
storeLogos Matriz de objetos
capturas de tela Matriz de objetos
ID String
assetUrl String Deve ser um URL válido
imageSize Objeto
width Inteiro
altura Inteiro

Resposta de exemplo

{   
"isSuccess": true,
    "errors": [{
        "code": "badrequest",
        "message": "Error Message 1",
        "target": "listings"
        }, {
        "code": "warning",
        "message": "Warning Message 1",
        "target": "properties"
    }],
    "responseData":{
        "listingAssets": [{
            "language": "en-us",
            "storeLogos": [
                {
                    "id": "1234567890abcdefgh",
                    "assetUrl": "https://contoso.com/blob=1234567890abcdefgh",
                    "imageSize": {
                        "width": 2160,
                        "height": 2160
                    }
                }
            ],
            "screenshots": [
                {
                    "id": "1234567891abcdefgh",
                    "assetUrl": "https://contoso.com/blob=1234567891abcdefgh",
                    "imageSize": {
                        "width": 2160,
                        "height": 2160
                    }
                }
            ]
        }]
    }
}

Criar API de ativos de listagem

Cria o Upload de ativos de listagem no envio de escalação atual.

Atualização da listagem de ativos

A API de Envio da Microsoft Store para aplicativos EXE ou MSI usa as URLs SAS geradas em runtime para Repositórios de Blobs para cada upload de ativo de imagem individual, juntamente com uma chamada de API de commit após o upload ser bem-sucedido. Para ter a capacidade de atualizar ativos de listagem e, por sua vez, para poder adicionar/remover localidades no módulo de listagem, a seguinte abordagem pode ser usada:

  1. Use a API Criar Ativo de Listagem para enviar solicitações sobre o upload de ativos junto com idioma, tipo e contagem 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 essa URL para fazer upload de ativos de imagem do tipo específico usando Clientes HTTP [Colocar BLOB (API REST) - Armazenamento do Azure | Microsoft Docs].
  3. Após o upload, você pode usar a API Fazer Commit de Ativos de Listagem para também enviar as novas informações de ID de Ativo recebidas anteriormente de uma chamada de API anterior. A API única fará commit internamente dos dados dos ativos de listagem após a validação.
  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: LANÇAR

Parâmetros de caminho

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

Cabeçalhos necessários

parâmetro Descrição
Authorization: Bearer <Token> Usar a ID do aplicativo Azure AD registrada com a conta da Central de Parceiros
X-Seller-Account-Id A ID do vendedor da conta da Central de Parceiros

Parâmetros de solicitação

Nome Tipo Descrição
Linguagem String Obrigatório
createAssetRequest Objeto Obrigatório
Captura de tela Inteiro Obrigatório se o ISV precisar atualizar capturas de tela ou adicionar novo idioma de listagem [1 - 10]
Logotipo Inteiro Obrigatório se o ISV precisar atualizar logotipos ou adicionar novo idioma de listagem [1 ou 2]

Cabeçalhos de resposta

parâmetro Descrição
X-Correlation-ID O GUID tipo ID exclusivo para cada solicitação. Pode ser compartilhado com a equipe de suporte para analisar qualquer issue.
Retry-After O tempo, em segundos, que o cliente precisa esperar antes de chamar as APIs novamente devido à limitação de fluxo.

Parâmetros de resposta

Nome Tipo Descrição
isSuccess Booliano
erros Matriz de objetos A lista de mensagens de aviso ou de erro, se houver
código String O código de erro da mensagem
message String A descrição do erro
destino String A entidade que originou o erro
responseData Objeto
listagem de ativos Objeto Objeto contendo detalhes de StoreLogos e Screenshots a serem carregados
linguagem String
storeLogos Matriz de objetos
capturas de tela Matriz de objetos
ID String
primaryAssetUploadUrl String URL primária para fazer upload do ativo de listagem usando a API REST de BLOB do Azure
secondaryAssetUploadUrl String URL secundária para fazer upload do ativo de listagem usando a API REST de BLOB do Azure
httpMethod Método HTTP O método HTTP precisava ser usado para fazer upload de ativos por meio das URLs de upload de ativos – primária ou secundária
httpHeaders Objeto Um objeto com chaves como cabeçalhos Obrigatórios para estar presente na chamada de API de upload para URLs de upload de ativos. Se o valor não estiver vazio, os cabeçalhos precisarão ter valores específicos. Caso contrário, os valores são calculados durante a chamada de API.

Resposta de exemplo

{
    "isSuccess": true,
    "errors": [{
        "code": "badrequest",
        "message": "Error Message 1",
        "target": "listings"
        }, {
        "code": "warning",
        "message": "Warning Message 1",
        "target": "properties"
    }],
    "responseData": {
        "listingAssets": {
            "language": "en-us",
            "storeLogos":[{
                "id": "1234567890abcdefgh",
                "primaryAssetUploadUrl": "https://contoso.com/upload?blob=1234567890abcdefgh&sig=12345",
                "secondaryAssetUploadUrl": "https://contoso.com/upload?blob=0987654321abcdfger&sig=54326",
                "httpMethod": "PUT",
                "httpHeaders": {"Required Header Name": "Header Value"}
            }],
            "screenshots":[{
                "id": "0987654321abcdfger",
                "primaryAssetUploadUrl": "https://contoso.com/upload?blob=0987654321abcdfger&sig=54321",
                "secondaryAssetUploadUrl": "https://contoso.com/upload?blob=0987654321abcdfger&sig=54322",
                "httpMethod": "PUT",
                "httpHeaders": {"Required Header Name": "Header Value"}

            }]
        }
    } 
}

Fazer commit da API de Ativos de Listagem

Faz commit do novo ativo de listagem carregado usando os detalhes da API Criar Ativos no envio de escalação atual.

Caminho: /submission/v1/product/{productId}/listings/assets/commit
Método: PUT

Parâmetros de caminho

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

Cabeçalhos necessários

parâmetro Descrição
Authorization: Bearer <Token> Usar a ID do aplicativo Azure AD registrada com a conta da Central de Parceiros
X-Seller-Account-Id A ID do vendedor da conta da Central de Parceiros

Parâmetros de solicitação

Nome Tipo Descrição
listagem de ativos Objeto
linguagem String
storeLogos Matriz de objetos
capturas de tela Matriz de objetos
ID String Deve ser uma ID existente que o usuário deseja manter a partir da API Obter Ativos de Listagem Atuais ou uma nova ID sob a qual um novo Ativo foi carregado na API Criar Ativos de Listagem.
assetUrl String Deve ser a URL do ativo existente que o usuário deseja manter a partir da API Obter Ativos de Listagem Atuais ou a URL de Upload – primária ou secundária, usando um novo ativo que foi carregado na API Criar Ativos de Listagem. Deve ser um URL válido

Solicitação de Exemplo

{
    "listingAssets": { 
        "language": "en-us",    
        "storeLogos": [
            {
                "id": "1234567890abcdefgh",
                "assetUrl": "https://contoso.com/blob=1234567890abcdefgh",
            }
        ],
        "screenshots": [
            {
                "id": "1234567891abcdefgh",
                "assetUrl": "https://contoso.com/blob=1234567891abcdefgh",
            }
        ]
    }
}

Cabeçalhos de resposta

parâmetro Descrição
X-Correlation-ID O GUID tipo ID exclusivo para cada solicitação. Pode ser compartilhado com a equipe de suporte para analisar qualquer issue.
Retry-After O tempo, em segundos, que o cliente precisa esperar antes de chamar as APIs novamente devido à limitação de fluxo.

Parâmetros de resposta

Nome Tipo Descrição
isSuccess Booliano
erros Matriz de objetos A lista de mensagens de aviso ou de erro, se houver
código String O código de erro da mensagem
message String A descrição do erro
destino String A entidade que originou o erro
responseData Objeto
pollingUrl String URL de pesquisa para obter o status de qualquer envio em andamento
ongoingSubmissionId String ID de envio de qualquer envio já em andamento

Resposta de exemplo

{
    "isSuccess": true,
    "errors": [{
        "code": "badrequest",
        "message": "Error Message 1",
        "target": "listings"
        }, {
        "code": "warning",
        "message": "Warning Message 1",
        "target": "properties"
    }],
    "responseData": {
        "pollingUrl": "/submission/v1/product/{productId}/submission/{submissionId}/status",
        "ongoingSubmissionId": ""
    } 
}

API de pesquisa de status do módulo

API para verificar a prontidão do módulo antes que o envio possa ser criado. Também valida o status de upload do pacote.

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

Parâmetros de caminho

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

Cabeçalhos necessários

parâmetro Descrição
Authorization: Bearer <Token> Usar a ID do aplicativo Azure AD registrada com a conta da Central de Parceiros
X-Seller-Account-Id A ID do vendedor da conta da Central de Parceiros

Cabeçalhos de resposta

parâmetro Descrição
X-Correlation-ID O GUID tipo ID exclusivo para cada solicitação. Pode ser compartilhado com a equipe de suporte para analisar qualquer issue.
Retry-After O tempo, em segundos, que o cliente precisa esperar antes de chamar as APIs novamente devido à limitação de fluxo.

Parâmetros de resposta

Nome Tipo Descrição
isSuccess Booliano
erros Matriz de objetos A lista de mensagens de aviso ou de erro, se houver
código String O código de erro da mensagem
message String A descrição do erro
destino String A entidade que originou o erro
responseData Objeto
isReady Booliano Indica se todos os módulos estão no estado pronto, incluindo o upload do pacote
ongoingSubmissionId String ID de envio de qualquer envio já em andamento

Resposta de exemplo

{
    "isSuccess": true,
    "errors": [{
        "code": "badrequest",
        "message": "Error Message 1",
        "target": "listings"
        }, {
        "code": "warning",
        "message": "Warning Message 1",
        "target": "properties"
    }],
    "responseData": {
        "isReady": true,
        "ongoingSubmissionId": ""
    }
}

Criar API de envio

Cria um envio de escalação atual para aplicativos MSI ou EXE. A API verifica:

  • para envio ativo e falha com mensagem de erro se existir um envio ativo.
  • se todos os módulos estiverem no status pronto para criar o envio.
  • cada campo no envio é validado de acordo com os requisitos da Store

Caminho:/submission/v1/product/{productId}/submit
Método: LANÇAR

Parâmetros de caminho

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

Cabeçalhos necessários

parâmetro Descrição
Authorization: Bearer <Token> Usar a ID do aplicativo Azure AD registrada com a conta da Central de Parceiros
X-Seller-Account-Id A ID do vendedor da conta da Central de Parceiros

Cabeçalhos de resposta

parâmetro Descrição
X-Correlation-ID O GUID tipo ID exclusivo para cada solicitação. Pode ser compartilhado com a equipe de suporte para analisar qualquer issue.
Retry-After O tempo, em segundos, que o cliente precisa esperar antes de chamar as APIs novamente devido à limitação de fluxo.

Parâmetros de resposta

Nome Tipo Descrição
isSuccess Booliano
erros Matriz de objetos A lista de mensagens de aviso ou de erro, se houver
código String O código de erro da mensagem
message String A descrição do erro
destino String A entidade que originou o erro
responseData Objeto
pollingUrl String URL de pesquisa para obter o status de preparação do módulo, incluindo o upload de pacotes para envio
submissionId String A ID do envio recém-criada
ongoingSubmissionId String ID de envio de qualquer envio já em andamento

Resposta de exemplo

{
    "isSuccess": true,
    "errors": [{
        "code": "badrequest",
        "message": "Error Message 1",
        "target": "listings"
        }, {
        "code": "warning",
        "message": "Warning Message 1",
        "target": "properties"
    }],
    "responseData": {
        "submissionId": "1234567890", 
        "pollingUrl": "/submission/v1/product/{productId}/submission/{submissionId}/status",
        "ongoingSubmissionId": ""
    }
}

API de pesquisa de status de envio

API para verificar o status de envio.

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

Parâmetros de caminho

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

Cabeçalhos necessários

parâmetro Descrição
Authorization: Bearer <Token> Usar a ID do aplicativo Azure AD registrada com a conta da Central de Parceiros
X-Seller-Account-Id A ID do vendedor da conta da Central de Parceiros

Cabeçalhos de resposta

parâmetro Descrição
X-Correlation-ID O GUID tipo ID exclusivo para cada solicitação. Pode ser compartilhado com a equipe de suporte para analisar qualquer issue.
Retry-After O tempo, em segundos, que o cliente precisa esperar antes de chamar as APIs novamente devido à limitação de fluxo.

Parâmetros de resposta

Nome Tipo Descrição
isSuccess Booliano
erros Matriz de objetos A lista de mensagens de aviso ou de erro, se houver
código String O código de erro da mensagem
message String A descrição do erro
destino String A entidade que originou o erro
responseData Objeto
publicandoStatus String Status de publicação da envio - [INPROGRESS, PUBLISHED, FAILED, UNKNOWN]
hasFailed Booliano Indica se a publicação falhou e não será tentada novamente

Resposta de exemplo

{
    "isSuccess": true,
    "errors": [{
        "code": "badrequest",
        "message": "Error Message 1",
        "target": "listings"
        }, {
        "code": "warning",
        "message": "Warning Message 1",
        "target": "properties"
    }],
    "responseData": {
        "publishingStatus": "INPROGRESS",
        "hasFailed": false
    }
}

Exemplos de código

Os artigos a seguir fornecem exemplos de código detalhados que demonstram como usar a API de envio da Microsoft Store em diferentes linguagens de programação:

Exemplo C#: API de Envio da Microsoft Store para aplicativos MSI ou EXE

Este artigo fornece exemplos de código C# que demonstram como usar a API de envio da Microsoft Store para aplicativos MSI ou EXE. Você pode revisar cada exemplo para saber mais sobre a tarefa que ele demonstra ou pode criar todos os exemplos de código neste artigo em um aplicativo de console.

Pré-requisitos Esses exemplos usam a seguinte biblioteca:

  • Pacote Newtonsoft.Json NuGet da Newtonsoft.

Programa Main O exemplo a seguir implementa um programa de linha de comando que chama os outros métodos de exemplo neste artigo para demonstrar maneiras diferentes de usar a API de envio da Microsoft Store. Para adaptar este programa para seu próprio uso:

  • Atribua a propriedade SellerId à ID do Vendedor da sua conta da Central de Parceiros.
  • Atribua a propriedade ApplicationId à ID do aplicativo que deseja gerenciar.
  • Atribua as propriedades ClientId e ClientSecret à ID do cliente e à chave do seu aplicativo e substitua a sequência tenantid na URL do TokenEndpoint pela ID do locatário do seu aplicativo. Para obter mais informações, confira Como associar um aplicativo do Azure AD à sua conta da Central de Parceiros
using System;
using System.Threading.Tasks;

namespace Win32SubmissionApiCSharpSample
{
    public class Program
    {
        static async Task Main(string[] args)
        {
            var config = new ClientConfiguration()
            {
                ApplicationId = "...",
                ClientId = "...",
                ClientSecret = "...",
                Scope = "https://api.store.microsoft.com/.default",
                ServiceUrl = "https://api.store.microsoft.com",
                TokenEndpoint = "...",
                SellerId = 0
            };

            await new AppSubmissionUpdateSample(config).RunAppSubmissionUpdateSample();

        }
    }
}

Classe auxiliar ClientConfiguration usando C#

O aplicativo de exemplo usa a classe auxiliar ClientConfiguration para passar os dados do Azure Active Directory e os dados do aplicativo para cada um dos métodos de exemplo que usam a API de envio da Microsoft Store.

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

namespace Win32SubmissionApiCSharpSample
{
    public class ClientConfiguration
    {
        /// <summary>
        /// Client Id of your Azure Active Directory app.
        /// Example" ba3c223b-03ab-4a44-aa32-38aa10c27e32
        /// </summary>
        public string ClientId { get; set; }

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

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

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

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

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


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

Criar um envio de aplicativo usando C#

O exemplo a seguir implementa uma classe que usa diversos métodos na API de envio da Microsoft Store para atualizar um envio de aplicativo.

using Newtonsoft.Json.Linq;
using System;
using System.Collections.Generic;
using System.IO;
using System.Net.Http;
using System.Text;
using System.Threading.Tasks;

namespace Win32SubmissionApiCSharpSample
{
    public class AppSubmissionUpdateSample
    {
        private ClientConfiguration ClientConfig;

        /// <summary>
        /// Constructor
        /// </summary>
        /// <param name="configuration">An instance of ClientConfiguration that contains all parameters populated</param>
        public AppSubmissionUpdateSample(ClientConfiguration configuration)
        {
            this.ClientConfig = configuration;
        }

        /// <summary>
        /// Main method to Run the Sample Application
        /// </summary>
        /// <returns></returns>
        /// <exception cref="InvalidOperationException"></exception>
        public async Task RunAppSubmissionUpdateSample()
        {
            // **********************
            //       SETTINGS
            // **********************
            var appId = this.ClientConfig.ApplicationId;
            var clientId = this.ClientConfig.ClientId;
            var clientSecret = this.ClientConfig.ClientSecret;
            var serviceEndpoint = this.ClientConfig.ServiceUrl;
            var tokenEndpoint = this.ClientConfig.TokenEndpoint;
            var scope = this.ClientConfig.Scope;

            // Get authorization token.
            Console.WriteLine("Getting authorization token");
            var accessToken = await SubmissionClient.GetClientCredentialAccessToken(
                tokenEndpoint,
                clientId,
                clientSecret,
                scope);

            var client = new SubmissionClient(accessToken, serviceEndpoint);

            client.DefaultHeaders = new Dictionary<string, string>()
            {
                {"X-Seller-Account-Id", this.ClientConfig.SellerId.ToString() }
            };

            Console.WriteLine("Getting Current Application Draft Status");
            
            dynamic AppDraftStatus = await client.Invoke<dynamic>(HttpMethod.Get, string.Format(SubmissionClient.ProductDraftStatusPollingUrlTemplate,
                SubmissionClient.Version, appId), null);
            
            Console.WriteLine(AppDraftStatus.ToString());

            Console.WriteLine("Getting Application Packages ");

            dynamic PackagesResponse = await client.Invoke<dynamic>(HttpMethod.Get, string.Format(SubmissionClient.PackagesUrlTemplate,
                SubmissionClient.Version, appId), null);

            Console.WriteLine(PackagesResponse.ToString());

            Console.WriteLine("Getting Single Package");

            dynamic SinglePackageResponse = await client.Invoke<dynamic>(HttpMethod.Get, string.Format(SubmissionClient.PackageByIdUrlTemplate,
                SubmissionClient.Version, appId, (string)PackagesResponse.responseData.packages[0].packageId), null);

            Console.WriteLine(SinglePackageResponse.ToString());

            Console.WriteLine("Updating Entire Package Set");

            // Update data in Packages list to have final set of updated Packages

            // Example - Updating Installer Parameters
            PackagesResponse.responseData.packages[0].installerParameters = "/s /r new-args";

            dynamic PackagesUpdateRequest = new
            {
                packages = PackagesResponse.responseData.packages
            };

            dynamic PackagesUpdateResponse = await client.Invoke<dynamic>(HttpMethod.Put, string.Format(SubmissionClient.PackagesUrlTemplate,
                SubmissionClient.Version, appId), PackagesUpdateRequest);

            Console.WriteLine(PackagesUpdateResponse.ToString());

            Console.WriteLine("Updating Single Package's Download Url");

            // Update data in the SinglePackage object

            var SinglePackageUpdateRequest = SinglePackageResponse.responseData.packages[0];

            // Example - Updating Installer Parameters
            SinglePackageUpdateRequest.installerParameters = "/s /r /t new-args";

            dynamic PackageUpdateResponse = await client.Invoke<dynamic>(HttpMethod.Patch, string.Format(SubmissionClient.PackageByIdUrlTemplate,
                SubmissionClient.Version, appId, SinglePackageUpdateRequest.packageId), SinglePackageUpdateRequest);

            Console.WriteLine("Committing Packages");

            dynamic PackageCommitResponse = await client.Invoke<dynamic>(HttpMethod.Post, string.Format(SubmissionClient.PackagesCommitUrlTemplate,
                SubmissionClient.Version, appId), null);

            Console.WriteLine(PackageCommitResponse.ToString());

            Console.WriteLine("Polling Package Upload Status");

            AppDraftStatus = await client.Invoke<dynamic>(HttpMethod.Get, string.Format(SubmissionClient.ProductDraftStatusPollingUrlTemplate,
                SubmissionClient.Version, appId), null);

            while (!((bool)AppDraftStatus.responseData.isReady))
            {
                AppDraftStatus = await client.Invoke<dynamic>(HttpMethod.Get, string.Format(SubmissionClient.ProductDraftStatusPollingUrlTemplate,
                    SubmissionClient.Version, appId), null);

                Console.WriteLine("Waiting for Upload to finish");

                await Task.Delay(TimeSpan.FromSeconds(2));

                if(AppDraftStatus.errors != null && AppDraftStatus.errors.Count > 0)
                {
                    for(var index = 0; index < AppDraftStatus.errors.Count; index++)
                    {
                        if(AppDraftStatus.errors[index].code == "packageuploaderror")
                        {
                            throw new InvalidOperationException("Package Upload Failed. Please try committing packages again.");
                        }
                    }
                }
            }

            Console.WriteLine("Getting Application Metadata - All Modules");

            dynamic AppMetadata = await client.Invoke<dynamic>(HttpMethod.Get, string.Format(SubmissionClient.AppMetadataUrlTemplate,
                SubmissionClient.Version, appId), null);

            Console.WriteLine(AppMetadata.ToString());

            Console.WriteLine("Getting Application Metadata - Listings");

            dynamic AppListingsMetadata = await client.Invoke<dynamic>(HttpMethod.Get, string.Format(SubmissionClient.AppListingsFetchMetadataUrlTemplate,
                SubmissionClient.Version, appId), null);

            Console.WriteLine(AppListingsMetadata.ToString());

            Console.WriteLine("Updating Listings Metadata - Description");

            // Update Required Fields in Listings Metadata Object - Per Language. For eg. AppListingsMetadata.responseData.listings[0]

            // Example - Updating Description
            AppListingsMetadata.responseData.listings[0].description = "New Description Updated By C# Sample Code";

            dynamic ListingsUpdateRequest = new
            {
                listings = AppListingsMetadata.responseData.listings[0]
            };

            dynamic UpdateListingsMetadataResponse = await client.Invoke<dynamic>(HttpMethod.Put, string.Format(SubmissionClient.AppMetadataUrlTemplate,
                SubmissionClient.Version, appId), ListingsUpdateRequest);

            Console.WriteLine(UpdateListingsMetadataResponse.ToString());

            Console.WriteLine("Getting All Listings Assets");

            dynamic ListingAssets = await client.Invoke<dynamic>(HttpMethod.Get, string.Format(SubmissionClient.ListingAssetsUrlTemplate,
                SubmissionClient.Version, appId), null);

            Console.WriteLine(ListingAssets.ToString());

            Console.WriteLine("Creating Listing Assets for 1 Screenshot");

            
            dynamic AssetCreateRequest = new
            {
                language = ListingAssets.responseData.listingAssets[0].language,
                createAssetRequest = new Dictionary<string, int>()
                {
                    {"Screenshot", 1 },
                    {"Logo", 0 }
                }
            };

            dynamic AssetCreateResponse = await client.Invoke<dynamic>(HttpMethod.Post, string.Format(SubmissionClient.ListingAssetsCreateUrlTemplate,
               SubmissionClient.Version, appId), AssetCreateRequest);

            Console.WriteLine(AssetCreateResponse.ToString());

            Console.WriteLine("Uploading Listing Assets");

            // Path to PNG File to be Uploaded as Screenshot / Logo
            var PathToFile = "./Image.png";
            var AssetToUpload = File.OpenRead(PathToFile);

            await client.UploadAsset(AssetCreateResponse.responseData.listingAssets.screenshots[0].primaryAssetUploadUrl.Value as string, AssetToUpload);

            Console.WriteLine("Committing Listing Assets");

            dynamic AssetCommitRequest = new
            {
                listingAssets = new
                {
                    language = ListingAssets.responseData.listingAssets[0].language,
                    storeLogos = ListingAssets.responseData.listingAssets[0].storeLogos,
                    screenshots = JToken.FromObject(new List<dynamic>() { new
                {
                    id = AssetCreateResponse.responseData.listingAssets.screenshots[0].id.Value as string,
                    assetUrl = AssetCreateResponse.responseData.listingAssets.screenshots[0].primaryAssetUploadUrl.Value as string
                }
                }.ToArray())
                }
            };

            dynamic AssetCommitResponse = await client.Invoke<dynamic>(HttpMethod.Put, string.Format(SubmissionClient.ListingAssetsCommitUrlTemplate,
               SubmissionClient.Version, appId), AssetCommitRequest);

            Console.WriteLine(AssetCommitResponse.ToString());

            Console.WriteLine("Getting Current Application Draft Status before Submission");

            AppDraftStatus = await client.Invoke<dynamic>(HttpMethod.Get, string.Format(SubmissionClient.ProductDraftStatusPollingUrlTemplate,
                SubmissionClient.Version, appId), null);

            Console.WriteLine(AppDraftStatus.ToString());

            if (AppDraftStatus == null || !((bool)AppDraftStatus.responseData.isReady))
            {
                throw new InvalidOperationException("Application Current Status is not in Ready Status for All Modules");
            }

            Console.WriteLine("Creating Submission");

            dynamic SubmissionCreationResponse = await client.Invoke<dynamic>(HttpMethod.Post, string.Format(SubmissionClient.CreateSubmissionUrlTemplate,
                SubmissionClient.Version, appId), null);

            Console.WriteLine(SubmissionCreationResponse.ToString());

            Console.WriteLine("Current Submission Status");

            dynamic SubmissionStatus = await client.Invoke<dynamic>(HttpMethod.Get, string.Format(SubmissionClient.SubmissionStatusPollingUrlTemplate,
                SubmissionClient.Version, appId, SubmissionCreationResponse.responseData.submissionId.Value as string), null);

            Console.Write(SubmissionStatus.ToString());

            // User can Poll on this API to know if Submission Status is INPROGRESS, PUBLISHED or FAILED.
            // This Process involves File Scanning, App Certification and Publishing and can take more than a day.
        }
    }
}

Classe auxiliar IngestionClient usando C#

A classe IngestionClient fornece métodos auxiliares que são usados por outros métodos no aplicativo de exemplo para executar as seguintes tarefas:

  • Obter um token de acesso do Azure AD que pode ser usado para chamar métodos na API de envio da Microsoft Store. Depois de obter um token, você tem 60 minutos para usá-lo em chamadas para a API de envio da Microsoft Store antes que ele expire. Depois que o token expirar, será possível gerar um novo.
  • Processar as solicitações HTTP para a API de envio da Microsoft Store.
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using System;
using System.Collections.Generic;
using System.IO;
using System.Net.Http;
using System.Net.Http.Headers;
using System.Text;
using System.Threading.Tasks;

namespace Win32SubmissionApiCSharpSample
{
    /// <summary>
    /// This class is a proxy that abstracts the functionality of the API service
    /// </summary>
    public class SubmissionClient : IDisposable
    {
        public static readonly string Version = "1";
        private HttpClient httpClient;
        private HttpClient imageUploadClient;

        private readonly string accessToken;

        public static readonly string PackagesUrlTemplate = "/submission/v{0}/product/{1}/packages";
        public static readonly string PackageByIdUrlTemplate = "/submission/v{0}/product/{1}/packages/{2}";
        public static readonly string PackagesCommitUrlTemplate = "/submission/v{0}/product/{1}/packages/commit";
        public static readonly string AppMetadataUrlTemplate = "/submission/v{0}/product/{1}/metadata";
        public static readonly string AppListingsFetchMetadataUrlTemplate = "/submission/v{0}/product/{1}/metadata/listings";
        public static readonly string ListingAssetsUrlTemplate = "/submission/v{0}/product/{1}/listings/assets";
        public static readonly string ListingAssetsCreateUrlTemplate = "/submission/v{0}/product/{1}/listings/assets/create";
        public static readonly string ListingAssetsCommitUrlTemplate = "/submission/v{0}/product/{1}/listings/assets/commit";
        public static readonly string ProductDraftStatusPollingUrlTemplate = "/submission/v{0}/product/{1}/status";
        public static readonly string CreateSubmissionUrlTemplate = "/submission/v{0}/product/{1}/submit";
        public static readonly string SubmissionStatusPollingUrlTemplate = "/submission/v{0}/product/{1}/submission/{2}/status";

        public const string JsonContentType = "application/json";
        public const string PngContentType = "image/png";
        public const string BinaryStreamContentType = "application/octet-stream";

        /// <summary>
        /// Initializes a new instance of the <see cref="SubmissionClient" /> class.
        /// </summary>
        /// <param name="accessToken">
        /// The access token. This is JWT a token obtained from Azure Active Directory allowing the caller to invoke the API
        /// on behalf of a user
        /// </param>
        /// <param name="serviceUrl">The service URL.</param>
        public SubmissionClient(string accessToken, string serviceUrl)
        {
            if (string.IsNullOrEmpty(accessToken))
            {
                throw new ArgumentNullException("accessToken");
            }

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

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

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

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

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

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

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

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

            return result.access_token;
        }


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

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

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

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

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

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

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

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


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

Exemplo de Node.js: API de Envio da Microsoft Store para aplicativos MSI ou EXE

Este artigo fornece exemplos de código Node.js que demonstram como usar a API de envio da Microsoft Store para aplicativos MSI ou EXE. Você pode revisar cada exemplo para saber mais sobre a tarefa que ele demonstra ou pode criar todos os exemplos de código neste artigo em um aplicativo de console.

Pré-requisitos Esses exemplos usam a seguinte biblioteca:

  • node-fetch v2 [npm install node-fetch@2]

Crie um envio de aplicativo usando o Node.js

O exemplo a seguir chama os outros métodos de exemplo neste artigo para demonstrar maneiras diferentes de usar a API de envio da Microsoft Store. Para adaptar este programa para seu próprio uso:

  • Atribua a propriedade SellerId à ID do Vendedor da sua conta da Central de Parceiros.
  • Atribua a propriedade ApplicationId à ID do aplicativo que deseja gerenciar.
  • Atribua as propriedades ClientId e ClientSecret à ID do cliente e à chave do seu aplicativo e substitua a sequência tenantid na URL do TokenEndpoint pela ID do locatário do seu aplicativo. Para obter mais informações, confira Como associar um aplicativo do Azure AD à sua conta da Central de Parceiros

O exemplo a seguir implementa uma classe que usa diversos métodos na API de envio da Microsoft Store para atualizar um envio de aplicativo.

const config = require('./Configuration');
const submissionClient = require('./SubmissionClient');
const fs = require('fs');

var client = new submissionClient(config);

/**
 * Main entry method to Run the Store Submission API Node.js Sample
 */
async function RunNodeJsSample(){
    print('Getting Access Token');
    await client.getAccessToken();
    
    print('Getting Current Application Draft Status');
    var currentDraftStatus = await client.callStoreAPI(client.productDraftStatusPollingUrlTemplate, 'get');
    print(currentDraftStatus);

    print('Getting Application Packages');
    var currentPackages = await client.callStoreAPI(client.packagesUrlTemplate, 'get');
    print(currentPackages);

    print('Getting Single Package');
    var packageId = currentPackages.responseData.packages[0].packageId;
    var packageIdUrl = `${client.packageByIdUrlTemplate}`.replace('{packageId}', packageId);
    var singlePackage = await client.callStoreAPI(packageIdUrl, 'get');
    print(singlePackage);

    print('Updating Entire Package Set');
    // Update data in Packages list to have final set of updated Packages
    currentPackages.responseData.packages[0].installerParameters = "/s /r new-args";
    var packagesUpdateRequest = {
        'packages': currentPackages.responseData.packages
    };
    print(packagesUpdateRequest);
    var packagesUpdateResponse = await client.callStoreAPI(client.packagesUrlTemplate, 'put', packagesUpdateRequest);
    print(packagesUpdateResponse);

    print('Updating Single Package\'s Download Url');
    // Update data in the SinglePackage object
    singlePackage.responseData.packages[0].installerParameters = "/s /r /t new-args";
    var singlePackageUpdateResponse = await client.callStoreAPI(packageIdUrl, 'patch', singlePackage.responseData.packages[0]);
    print(singlePackageUpdateResponse);

    print('Committing Packages');
    var commitPackagesResponse = await client.callStoreAPI(client.packagesCommitUrlTemplate, 'post');
    print(commitPackagesResponse);

    await poll(async ()=>{
        print('Waiting for Upload to finish');
        return await client.callStoreAPI(client.productDraftStatusPollingUrlTemplate, 'get');
    }, 2);

    print('Getting Application Metadata - All Modules');
    var appMetadata = await client.callStoreAPI(client.appMetadataUrlTemplate, 'get');
    print(appMetadata);

    print('Getting Application Metadata - Listings');
    var appListingMetadata = await client.callStoreAPI(client.appListingsFetchMetadataUrlTemplate, 'get');
    print(appListingMetadata);

    print('Updating Listings Metadata - Description');   
    // Update Required Fields in Listings Metadata Object - Per Language. For eg. AppListingsMetadata.responseData.listings[0]
    // Example - Updating Description
    appListingMetadata.responseData.listings[0].description = 'New Description Updated By Node.js Sample Code';
    var listingsUpdateRequest = {
        'listings': appListingMetadata.responseData.listings[0]
    };
    var listingsMetadataUpdateResponse = await client.callStoreAPI(client.appMetadataUrlTemplate, 'put', listingsUpdateRequest);
    print(listingsMetadataUpdateResponse);

    print('Getting All Listings Assets');
    var listingAssets = await client.callStoreAPI(client.listingAssetsUrlTemplate, 'get');
    print(listingAssets);

    print('Creating Listing Assets for 1 Screenshot');
    var listingAssetCreateRequest = {
        'language': listingAssets.responseData.listingAssets[0].language,
        'createAssetRequest': {
            'Screenshot': 1,
            'Logo': 0
        }
    };
    var listingAssetCreateResponse = await client.callStoreAPI(client.listingAssetsCreateUrlTemplate, 'post', listingAssetCreateRequest);
    print(listingAssetCreateResponse);

    print('Uploading Listing Assets');
    const pathToFile = './Image.png';
    const stats = fs.statSync(pathToFile);
    const fileSize = stats.size;
    const fileStream = fs.createReadStream(pathToFile);
    await client.uploadAssets(listingAssetCreateResponse.responseData.listingAssets.screenshots[0].primaryAssetUploadUrl, fileStream, fileSize);

    print('Committing Listing Assets');
    var assetCommitRequest = {
        'listingAssets': {
            'language': listingAssets.responseData.listingAssets[0].language,
            'storeLogos': listingAssets.responseData.listingAssets[0].storeLogos,
            'screenshots': [{
                'id': listingAssetCreateResponse.responseData.listingAssets.screenshots[0].id,
                'assetUrl': listingAssetCreateResponse.responseData.listingAssets.screenshots[0].primaryAssetUploadUrl
            }]
        }
    };
    var assetCommitResponse = await client.callStoreAPI(client.listingAssetsCommitUrlTemplate, 'put', assetCommitRequest);
    print(assetCommitResponse);

    print('Getting Current Application Draft Status before Submission');
    currentDraftStatus = await client.callStoreAPI(client.productDraftStatusPollingUrlTemplate, 'get');
    print(currentDraftStatus);
    if(!currentDraftStatus.responseData.isReady){
        throw new Error('Application Current Status is not in Ready Status for All Modules');
    }

    print('Creating Submission');
    var submissionCreationResponse = await client.callStoreAPI(client.createSubmissionUrlTemplate, 'post');
    print(submissionCreationResponse);

    print('Current Submission Status');
    var submissionStatusUrl = `${client.submissionStatusPollingUrlTemplate}`.replace('{submissionId}', submissionCreationResponse.responseData.submissionId);
    var submissionStatusResponse = await client.callStoreAPI(submissionStatusUrl, 'get');
    print(submissionStatusResponse);

    // User can Poll on this API to know if Submission Status is INPROGRESS, PUBLISHED or FAILED.
    // This Process involves File Scanning, App Certification and Publishing and can take more than a day.
}

/**
 * Utility Method to Poll using a given function and time interval in seconds
 * @param {*} func 
 * @param {*} intervalInSeconds 
 * @returns 
 */
async function poll(func, intervalInSeconds){
var result = await func();
if(result.responseData.isReady){
    Promise.resolve(true);
}
else if(result.errors && result.errors.length > 0 && result.errors.find(element => element.code == 'packageuploaderror') != undefined){
throw new Error('Package Upload Failed');
}
else{
    await new Promise(resolve => setTimeout(resolve, intervalInSeconds*1000));
    return await poll(func, intervalInSeconds); 
}
}

/**
 * Utility function to Print a Json or normal string
 * @param {*} json 
 */
function print(json){
    if(typeof(json) == 'string'){
        console.log(json);
    }
    else{
        console.log(JSON.stringify(json));
    }
    console.log("\n");
}

/** Run the Node.js Sample Application */
RunNodeJsSample();

Auxiliar ClientConfiguration

O aplicativo de exemplo usa a classe auxiliar ClientConfiguration para passar os dados do Azure Active Directory e os dados do aplicativo para cada um dos métodos de exemplo que usam a API de envio da Microsoft Store.

/** Configuration Object for Store Submission API */
var config = {
    version : "1",
    applicationId : "...",
    clientId : "...",
    clientSecret : "...",
    serviceEndpoint : "https://api.store.microsoft.com",
    tokenEndpoint : "...",
    scope : "https://api.store.microsoft.com/.default",
    sellerId : "...",
    jsonContentType : "application/json",
    pngContentType : "image/png",
    binaryStreamContentType : "application/octet-stream"
};

module.exports = config;

Auxiliar IngestionClient usando o Node.js

A classe IngestionClient fornece métodos auxiliares que são usados por outros métodos no aplicativo de exemplo para executar as seguintes tarefas:

  • Obter um token de acesso do Azure AD que pode ser usado para chamar métodos na API de envio da Microsoft Store. Depois de obter um token, você tem 60 minutos para usá-lo em chamadas para a API de envio da Microsoft Store antes que ele expire. Depois que o token expirar, será possível gerar um novo.
  • Processar as solicitações HTTP para a API de envio da Microsoft Store.
const fetch = require('node-fetch');
/**
 * Submission Client to invoke all available Store Submission API and Asset Upload to Blob Store
 */
class SubmissionClient{

    constructor(config){
        this.configuration = config;
        this.accessToken = "";
        this.packagesUrlTemplate = `/submission/v${this.configuration.version}/product/${this.configuration.applicationId}/packages`;
        this.packageByIdUrlTemplate = `/submission/v${this.configuration.version}/product/${this.configuration.applicationId}/packages/{packageId}`;
        this.packagesCommitUrlTemplate = `/submission/v${this.configuration.version}/product/${this.configuration.applicationId}/packages/commit`;
        this.appMetadataUrlTemplate = `/submission/v${this.configuration.version}/product/${this.configuration.applicationId}/metadata`;
        this.appListingsFetchMetadataUrlTemplate = `/submission/v${this.configuration.version}/product/${this.configuration.applicationId}/metadata/listings`;
        this.listingAssetsUrlTemplate = `/submission/v${this.configuration.version}/product/${this.configuration.applicationId}/listings/assets`;
        this.listingAssetsCreateUrlTemplate = `/submission/v${this.configuration.version}/product/${this.configuration.applicationId}/listings/assets/create`;
        this.listingAssetsCommitUrlTemplate = `/submission/v${this.configuration.version}/product/${this.configuration.applicationId}/listings/assets/commit`;
        this.productDraftStatusPollingUrlTemplate = `/submission/v${this.configuration.version}/product/${this.configuration.applicationId}/status`;
        this.createSubmissionUrlTemplate = `/submission/v${this.configuration.version}/product/${this.configuration.applicationId}/submit`;
        this.submissionStatusPollingUrlTemplate = `/submission/v${this.configuration.version}/product/${this.configuration.applicationId}/submission/{submissionId}/status`;
    }
    
    async getAccessToken(){
        var params = new URLSearchParams();
        params.append('grant_type','client_credentials');
        params.append('client_id',this.configuration.clientId);
        params.append('client_secret',this.configuration.clientSecret);
        params.append('scope',this.configuration.scope);
        var response = await fetch(this.configuration.tokenEndpoint,{
            method: "POST",
            body: params
        });    
        var data = await response.json();
        this.accessToken = data.access_token;
    }

    async callStoreAPI(url, method, data){
        var request = {
            method: method,
            headers:{
                'Authorization': `Bearer ${this.accessToken}`,
                'Content-Type': this.configuration.jsonContentType,
                'X-Seller-Account-Id': this.configuration.sellerId
            },            
        };
        if(data){
            request.body = JSON.stringify(data);
        }
        var response = await fetch(`${this.configuration.serviceEndpoint}${url}`,request);
        var jsonResponse = await response.json();
        return jsonResponse;
    }

    async uploadAssets(url, stream, size){
        var request = {
            method: 'put',
            headers:{
                'Content-Type': this.configuration.pngContentType,
                'x-ms-blob-type': 'BlockBlob',
                "Content-length": size
            },            
            body: stream
        };
        var response = await fetch(`${url}`,request);
        if(response.ok){
            return response;
        }
        else{
            throw new Error('Uploading of assets failed');
        }
    }
}
module.exports = SubmissionClient;

Ajuda adicional

Se você tiver dúvidas sobre a API de envio da Microsoft Store ou precisar de assistência para gerenciar seus envios com essa API, use os seguintes recursos:

  • Faça perguntas em nossos fóruns.
  • Visite nossa página de suporte e solicite uma das opções de suporte assistido para a Central de Parceiros. Se você for solicitado a escolher um tipo e uma categoria de problema, escolha Envio de aplicativo, certificação e Enviar um aplicativo, respectivamente.