API de envío de Microsoft Store para aplicaciones MSI o EXE
Utilice la API de envío de Microsoft Store para aplicaciones MSI o EXE para consultar y crear envíos mediante programación para aplicaciones MSI o EXE para la cuenta del Centro de partners de su organización. Esta API es útil si su cuenta administra muchas aplicaciones y desea automatizar y optimizar el proceso de envío de estos recursos. Esta API utiliza Azure Active Directory (Azure AD) para autenticar las llamadas desde la aplicación o el servicio.
En los pasos siguientes se describe el proceso completo para utilizar la API de envío de Microsoft Store:
- Asegúrese de haber completado todos los requisitos previos.
- Antes de llamar a un método en la API de envío de Microsoft Store, obtenga un token de acceso de Azure AD. Después de obtener un token, tiene 60 minutos para utilizar este token en llamadas a la API de envío de Microsoft Store antes de que el token expire. Después de que el token expire, puede generar uno nuevo.
- Llame a la API de envío de Microsoft Store para la aplicación MSI o EXE.
Paso 1: Completar los requisitos previos para utilizar la API de envío de Microsoft Store
Antes de empezar a escribir código para llamar a la API de envío de Microsoft Store para la aplicación MSI o EXE, asegúrese de haber completado los requisitos previos a continuación.
- Usted (o su organización) tiene que tener un directorio de Azure AD y el permiso de Administrador global para el directorio. Si usa Microsoft 365 u otros servicios empresariales de Microsoft, ya tiene el directorio de Azure AD. De lo contrario, puede crear una nueva instancia de Azure AD en el Centro de partners sin cargo adicional.
- Tiene que asociar una aplicación Azure AD a su cuenta del Centro de partners y obtener el identificador de inquilino, el identificador de cliente y la clave. Necesitará estos valores para obtener un token de acceso de Azure AD, que usará en las llamadas a la API de envío de Microsoft Store.
- Prepare la aplicación para utilizarla con la API de envío de Microsoft Store:
- Si la aplicación aún no existe en el Centro de partners, para crearla, debe reservar el nombre en el Centro de partners. No puede utilizar la API de envío de Microsoft Store para crear una aplicación en el Centro de partners; debe trabajar en el Centro de partners para crearla y, después, puede utilizar la API para acceder a la aplicación y crear envíos mediante programación para ella.
- Para poder crear un envío para una aplicación determinada mediante esta API, primero debe crear un envío para la aplicación en el Centro de partners, incluida la respuesta al cuestionario de clasificaciones por edades . Después de esto, podrá crear mediante programación nuevos envíos para esta aplicación a través de la API.
- Si va a crear o actualizar un envío de aplicación y tiene que incluir un nuevo paquete, prepare los detalles del paquete.
- Si va a crear o actualizar un envío de aplicación y tiene que incluir capturas de pantalla o imágenes para la descripción de Store, prepare las capturas de pantalla e imágenes de la aplicación.
Cómo asociar una aplicación de Azure AD con la cuenta del Centro de partners
Antes de poder utilizar la API de envío de Microsoft Store para aplicaciones MSI o EXE, tiene que asociar una aplicación de Azure AD a su cuenta del Centro de partners, recuperar el identificador de inquilino y el identificador de cliente para la aplicación y generar una clave. La aplicación de Azure AD representa la aplicación o el servicio desde donde desea llamar a la API de envío de Microsoft Store. Necesita el identificador de inquilino, el identificador de cliente y la clave para obtener un token de acceso de Azure AD para pasar a la API.
Nota:
Solo tiene que realizar esta tarea una vez. Una vez que tenga el identificador de inquilino, el identificador de cliente y la clave, puede volver a usarlos cada vez que tenga que crear un nuevo token de acceso de Azure AD.
- En el Centro de partners, asocie la cuenta del Centro de partners de la organización con el directorio de Azure AD de la organización.
- A continuación, en la página Usuarios en la sección Configuración de la cuenta del Centro de partners, agregue la aplicación de Azure AD que representa la aplicación o el servicio que utilizará para acceder a los envíos de la cuenta del Centro de partners. Asegúrese de asignar a esta aplicación el rol Administrador. Si la aplicación aún no existe en el directorio de Azure AD, puede crear una nueva aplicación de Azure AD en el Centro de partners.
- Vuelva a la página Usuarios, haga clic en el nombre de la aplicación de Azure AD para ir a la configuración de la aplicación y, a continuación, copie los valores de Identificador de inquilino e Identificador de cliente.
- Para agregar una nueva clave o un secreto de cliente, consulte las instrucciones siguientes o consulte las instrucciones para registrar la aplicación a través de Azure Portal:
Para registrar la aplicación:
Inicie sesión en Azure Portal.
Si tiene acceso a varios inquilinos, use el filtro Directorios y suscripciones del menú superior para ir al inquilino en el que quiere registrar la aplicación.
Busque y seleccione Azure Active Directory.
En Administrar, seleccione Registros de aplicaciones > Seleccionar la aplicación.
Seleccione Certificados y secretos > Secretos de cliente > Nuevo secreto de cliente.
Agregue una descripción para el secreto de cliente.
Seleccione una expiración para el secreto o especifique una duración personalizada.
La duración del secreto de cliente se limita a dos años (24 meses) o menos. No se puede especificar una duración personalizada superior a 24 meses.
Nota:
Microsoft recomienda establecer un valor de expiración de menos de 12 meses.
Seleccione Agregar.
Registre el valor del secreto para su uso en el código de la aplicación cliente. Este valor secreto no se volverá a mostrar una vez que abandone esta página.
Paso 2: Obtener un token de acceso de Azure AD
Antes de llamar a cualquiera de los métodos de la API de envío de Microsoft Store para aplicaciones MSI o EXE, primero tiene que obtener un token de acceso de Azure AD que pase al encabezado de autorización de cada método de la API. Una vez que haya obtenido un token de acceso, tiene 60 minutos para usarlo antes de que expire. Una vez que expire el token, puede actualizarlo para poder seguir utilizándolo en llamadas adicionales a la API.
Para obtener el token de acceso, siga las instrucciones de Llamadas de servicio a servicio mediante credenciales de cilente/azure/active-directory/azuread-dev/v1-oauth2-client-creds-grant-flow) para enviar un HTTP POST al punto de conexión https://login.microsoftonline.com/<tenant_id>/oauth2/token. Esta es una solicitud de ejemplo.
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 el valor tenant_id
en el URI de POST y los parámetros client_id
y client_secret
, especifique el identificador de inquilino, el identificador de cliente y la clave de la aplicación que recuperó del Centro de partners en la sección anterior. Para el parámetro scope, tiene que especificar https://api.store.microsoft.com/.default
.
Una vez que expire el token de acceso, puede seguir las instrucciones que se indican aquí para actualizarlo.
Para obtener ejemplos que muestran cómo obtener un token de acceso mediante C# o Node.js, consulte los ejemplos de código para la API de envío de Microsoft Store para aplicaciones MSI o EXE.
Paso 3: Utilizar la API de envío de Microsoft Store
Una vez que tenga un token de acceso de Azure AD, puede llamar a los métodos en la API de envío de Microsoft Store para aplicaciones MSI o EXE. La API incluye muchos métodos que se agrupan en escenarios para las aplicaciones. Para crear o actualizar envíos, normalmente se llama a varios métodos en un orden específico. Para obtener información acerca de cada escenario y la sintaxis de cada método, consulte las secciones siguientes:
Nota:
Después de obtener un token de acceso, tiene 60 minutos para llamar a los métodos en la API de envío de Microsoft Store para aplicaciones MSI o EXE antes de que el token expire.
URL base
La URL base de la API de envío de Microsoft Store para aplicaciones MSI o EXE es https://api.store.microsoft.com
Contratos de API
API Get Current Draft Submission Metadata
Captura los metadatos de cada módulo (descripciones, propiedades o disponibilidad) en el envío del borrador actual.
Ruta de acceso [todos los módulos]: /submission/v1/product/{productId}/metadata?languages={languages}&includelanguagelist={true/false}
Ruta de acceso [módulo único]: /submission/v1/product/{productId}/metadata/{moduleName}?languages={languages}&includelanguagelist={true/false}
Método: GET
Parámetros de la ruta de acceso
Parámetro | Descripción |
---|---|
productId | Identificador del producto en el Centro de partners |
moduleName | Módulo del Centro de partners: descripciones, propiedades o disponibilidad |
Parámetros de consulta
Parámetro | Descripción |
---|---|
languages | Opcional Los idiomas de descripción se filtran como cadena separada por comas [límite de hasta 200 idiomas]. Si no está presente, se recuperan los metadatos de los primeros 200 idiomas de descripción disponibles. [Por ejemplo, "en-us, en-gb"]. |
includelanguagelist | Opcional Booleano: si es verdadero, devuelve la lista de idiomas de descripción agregados y su estado de integridad. |
Encabezados obligatorios
Encabezado | Valor |
---|---|
Authorization: Bearer <Token> |
El identificador de la aplicación de Azure AD registrado en la cuenta del Centro de partners |
X-Seller-Account-Id |
Id. de vendedor de la cuenta del Centro de partners |
Encabezados de respuesta
Encabezado | Valor |
---|---|
X-Correlation-ID |
Id. exclusivo de tipo GUID para cada solicitud. Se puede compartir con el equipo de soporte técnico para analizar cualquier problema. |
Retry-After |
Tiempo en segundos que el cliente debe esperar antes de llamar a las API de nuevo debido a la limitación de volumen. |
Parámetros de respuesta
Nombre | Escribir | Descripción |
---|---|---|
accessibilitySupport | Booleano | |
additionalLicenseTerms | Cadena | |
disponibilidad | Object | Datos del módulo de disponibilidad |
category | Cadena | Consulte la lista de categorías más adelante |
certificationNotes | Cadena | |
code | Cadena | El código de error del mensaje. |
contactInfo | Cadena | |
copyright | Cadena | |
dependsOnDriversOrNT | Booleano | |
descripción | Cadena | |
developedBy | Cadena | |
discoverability | Cadena | [DISCOVERABLE, DEEPLINK_ONLY] |
enableInFutureMarkets | Booleano | |
errors | Matriz de objetos | Lista de mensajes de error o advertencia, si los hay |
freeTrial | Cadena | [NO_FREE_TRIAL, FREE_TRIAL] |
hardwareItemType | Cadena | |
isPrivacyPolicyRequired | Booleano | |
isRecommended | Booleano | |
isRequired | Booleano | |
isSuccess | Booleano | |
isSystemFeatureRequired | Matriz de objetos | |
language | Cadena | Consulte la lista de idiomas más adelante |
listings | Matriz de objetos | Datos del módulo de descripciones para cada idioma |
markets | Matriz de cadenas | Consulte la lista de mercados más adelante |
message | String | Descripción del error |
minimumHardware | Cadena | |
minimumRequirement | Cadena | |
penAndInkSupport | Booleano | |
Precios | Cadena | [FREE, FREEMIUM, SUBSCRIPTION, PAID] |
privacyPolicyUrl | Cadena | |
productDeclarations | Object | |
productFeatures | Matriz de cadenas | |
properties | Object | Datos del módulo de propiedades |
recommendedHardware | Cadena | |
recommendedRequirement | Cadena | |
responseData | Object | Contiene la carga de respuesta real para la solicitud. |
requisitos | Matriz de objetos | |
searchTerms | Matriz de cadenas | |
shortDescription | Cadena | |
subcategory | Cadena | Consulte la lista de subcategorías más adelante |
supportContactInfo | Cadena | |
systemRequirementDetails | Matriz de objetos | |
Destino | Cadena | Entidad desde la que se originó el error |
sitio web | Cadena | |
whatsNew | Cadena |
Respuesta de ejemplo
{
"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}]
}
}
API Update Current Draft Submission Metadata
Actualiza los metadatos en cada módulo bajo el borrador de envío. La API comprueba:
- Para el envío activo. Si existe, error con el mensaje de error.
- Si todos los módulos están en estado listo para permitir la operación Guardar borrador.
- Cada campo del envío se valida según los requisitos de Store.
- Reglas de validación de detalles de los requisitos del sistema:
- Valores permitidos en hardwareItemType = Memory: 300 MB, 750 MB, 1 GB, 2 GB, 4 GB, 6 GB, 8 GB, 12 GB, 16 GB, 20 GB
- Valores permitidos en hardwareItemType = DirectX: DX9, DX10, DX11, DX12-FEATURELEVEL11, DX12-FEATURELEVEL12
- Valores permitidos en hardwareItemType = Video_Memory: 1 GB, 2 GB, 4 GB, 6 GB
Ruta de acceso [actualización del módulo completo]: /submission/v1/product/{productId}/metadata
Método: PUT
Ruta de acceso [actualización de revisión del módulo]: /submission/v1/product/{productId}/metadata
Método: PATCH
Comportamiento de la API
En el caso de la API de actualización completa del módulo, es necesario que todos los datos del módulo estén presentes en la solicitud para la actualización completa de cada campo. Cuando un campo no esté presente en la solicitud, su valor predeterminado se usará para sobrescribir el valor actual de ese módulo específico.
En el caso de la API de actualización de la revisión del módulo, solo los campos que se van a actualizar deben estar presentes en la solicitud. Estos valores de campos de la solicitud sobrescribirán sus valores existentes y mantendrán todos los demás campos que no están presentes en la solicitud igual que los actuales para ese módulo específico.
Parámetros de la ruta de acceso
Parámetro | Descripción |
---|---|
productId | Identificador del producto en el Centro de partners |
Encabezados obligatorios
Encabezado | Valor |
---|---|
Authorization: Bearer <Token> |
El identificador de la aplicación de Azure AD registrado en la cuenta del Centro de partners |
X-Seller-Account-Id |
Id. de vendedor de la cuenta del Centro de partners |
Parámetros de la solicitud
Nombre | Escribir | Descripción |
---|---|---|
disponibilidad | Object | Objeto para contener los metadatos del módulo de disponibilidad |
markets | Matriz de cadenas | Obligatorio Consulte la lista de mercados más adelante |
discoverability | Cadena | Obligatorio [DISCOVERABLE, DEEPLINK_ONLY] |
enableInFutureMarkets | Booleano | Obligatorio |
Precios | Cadena | Obligatorio [FREE, FREEMIUM, SUBSCRIPTION, PAID] |
freeTrial | Cadena | Obligatorio si Pricing es PAID o SUBSCRIPTION [NO_FREE_TRIAL, FREE_TRIAL] |
properties | Object | Objeto para contener los metadatos del módulo de propiedades |
isPrivacyPolicyRequired | Booleano | Obligatorio |
privacyPolicyUrl | Cadena | Obligatorio si isPrivacyPolicyRequired = true Debe ser una dirección URL válida |
sitio web | Cadena | Debe ser una dirección URL válida |
supportContactInfo | Cadena | Debe ser una dirección URL o dirección de correo electrónico válida |
certificationNotes | Cadena | Recomendado Límite de caracteres = 2000 |
category | Cadena | Obligatorio Consulte la lista de categorías más adelante |
subcategory | Cadena | Obligatorio Consulte la lista de subcategorías más adelante |
productDeclarations | Object | Obligatorio |
isSystemFeatureRequired | Matriz de objetos | [Touch, Keyboard, Mouse, Camera, NFC_HCE, NFC_Proximity, Bluetooth_LE, Telephony, Microphone] |
isRequired | Booleano | Obligatorio |
isRecommended | Booleano | Obligatorio |
hardwareItemType | Cadena | Obligatorio |
systemRequirementDetails | Matriz de objetos | [Processor, Graphics, Memory, DirectX, Video_Memory] |
minimumRequirement | Cadena | Obligatorio Para systemRequirementsText, MaxLength = 200 Valores permitidos en hardwareItemType = Memory: [300 MB, 750 MB, 1 GB, 2 GB, 4 GB, 6 GB, 8 GB, 12 GB, 16 GB, 20 GB] Valores permitidos en hardwareItemType = DirectX: [DX9, DX10, DX11, DX12-FEATURELEVEL11, DX12-FEATURELEVEL12] Valores permitidos en hardwareItemType = Video_Memory: [1 GB, 2 GB, 4 GB, 6 GB] |
recommendedRequirement | Cadena | Obligatorio Para systemRequirementsText, MaxLength = 200 Valores permitidos en hardwareItemType = Memory: [300 MB, 750 MB, 1 GB, 2 GB, 4 GB, 6 GB, 8 GB, 12 GB, 16 GB, 20 GB] Valores permitidos en hardwareItemType = DirectX: [DX9, DX10, DX11, DX12-FEATURELEVEL11, DX12-FEATURELEVEL12] Valores permitidos en hardwareItemType = Video_Memory: [1 GB, 2 GB, 4 GB, 6 GB] |
dependsOnDriversOrNT | Booleano | Obligatorio |
accessibilitySupport | Booleano | Obligatorio |
penAndInkSupport | Booleano | Obligatorio |
listings | Object | Objeto para los datos del módulo de descripciones para un único idioma |
language | Cadena | Obligatorio Consulte la lista de idiomas más adelante |
descripción | Cadena | Obligatorio Límite de caracteres = 10000 |
whatsNew | Cadena | Límite de caracteres = 1500 |
productFeatures | Matriz de cadena | 200 caracteres por característica; hasta 20 características |
shortDescription | Cadena | Límite de caracteres = 1000 |
searchTerms | Matriz de cadena | 30 caracteres por término de búsqueda; hasta 7 términos de búsqueda 21 palabras únicas en total entre todos los términos de búsqueda |
additionalLicenseTerms | Cadena | Obligatorio Límite de caracteres = 10000 |
copyright | Cadena | Límite de caracteres = 200 |
developedBy | Cadena | Límite de caracteres = 255 |
requisitos | Matriz de objetos | 200 caracteres por elemento; hasta 11 elementos en total entre el mínimo y el recomendado] |
minimumHardware | Cadena | Límite de caracteres = 200 |
recommendedHardware | Cadena | Límite de caracteres = 200 |
contactInfo | Cadena | Límite de caracteres = 200 |
listingsToAdd | Matriz de cadenas | Consulte la lista de idiomas más adelante |
listingsToRemove | Matriz de cadenas | Consulte la lista de idiomas más adelante |
Mercados
Mercado | Abreviatura |
---|---|
Afganistán | AF |
Albania | AL |
Argelia | DZ |
Samoa Americana | AS |
Andorra | AD |
Angola | AO |
Anguila | INTELIGENCIA ARTIFICIAL |
Antártida | AQ |
Antigua y Barbuda | AG |
Argentina | AR |
Armenia | AM |
Aruba | AW |
Australia | AU |
Austria | AT |
Azerbaiyán | AZ |
Bahamas | BS |
Bahréin | BH |
Bangladés | BD |
Barbados | BB |
Bielorrusia | BY |
Bélgica | BE |
Belice | BZ |
Benín | BJ |
Bermudas | BM |
Bután | BT |
República Bolivariana de Venezuela | VE |
Bolivia | BO |
Bonaire | BQ |
Bosnia y Herzegovina | BA |
Botsuana | BW |
Isla Bouvet | BV |
Brasil | BR |
Territorio Británico del Océano Índico | IO |
Islas Vírgenes Británicas | VG |
Brunéi | BN |
Bulgaria | BG |
Burkina Faso | BF |
Burundi | BI |
Camboya | KH |
Camerún | CM |
Canadá | CA |
Cabo Verde | CV |
Islas Caimán | KY |
República Centroafricana | CF |
Chad | TD |
Chile | CL |
China | CN |
Isla de Navidad | CX |
Islas Cocos | CC |
Colombia | CO |
Comoras | KM |
Congo | CG |
Congo (RDC) | CD |
Islas Cook | CK |
Costa Rica | CR |
Croacia | HR |
Curazao | CW |
Chipre | CY |
República Checa | CZ |
Costa de Marfil | CI |
Dinamarca | DK |
Yibuti | DJ |
Dominica | DM |
República Dominicana | DO |
Ecuador | EC |
Egipto | EG |
El Salvador | SV |
Guinea Ecuatorial | GQ |
Eritrea | ER |
Estonia | EE |
Etiopía | ET |
Islas Malvinas | FK |
Islas Feroe | FO |
Islas Fiji | FJ |
Finlandia | FI |
Francia | VF |
Guayana Francesa | GF |
Polinesia Francesa | PF |
Territorios Australes Franceses | TF |
Gabón | GA |
Gambia | GM |
Georgia | GE |
Alemania | DE |
Ghana | GH |
Gibraltar | GI |
Grecia | GR |
Groenlandia | GL |
Granada | GD |
Guadalupe | GP |
Guam | GU |
Guatemala | GT |
Guernsey | GG |
Guinea | GN |
Guinea-Bisáu | GW |
Guyana | GY |
Haití | HT |
Islas Heard y McDonald | HM |
Ciudad del Vaticano | VA |
Honduras | HN |
RAE de Hong Kong | HK |
Hungría | HU |
Islandia | IS |
India | IN |
Indonesia | ID |
Iraq | IQ |
Irlanda | IE |
Israel | IL |
Italia | IT |
Jamaica | JM |
Japón | JP |
Jersey | JE |
Jordania | JO |
Kazajistán | KZ |
Kenia | KE |
Kiribati | KI |
Corea | KR |
Kuwait | KW |
Kirguistán | KG |
Laos | Los Ángeles |
Letonia | LV |
Líbano | LB |
Lesoto | LS |
Liberia | LR |
Libia | LY |
Liechtenstein | LI |
Lituania | LT |
Luxemburgo | LU |
RAE de Macao | MO |
Macedonia del Norte | MK |
Madagascar | MG |
Malaui | MW |
Malasia | MY |
Maldivas | MV |
Mali | ML |
Malta | MT |
Isla de Man | IM |
Islas Marshall | MH |
Martinica | MQ |
Mauritania | MR |
Mauricio | MU |
Mayotte | YT |
México | MX |
Micronesia | FM |
Moldavia | MD |
Mónaco | MC |
Mongolia | MN |
Montenegro - ME | |
Montserrat | MS |
Marruecos | MA |
Mozambique | MZ |
Myanmar | MM |
Namibia | N/D |
Nauru | NR |
Nepal | NP |
Países Bajos | NL |
Nueva Caledonia | NC |
Nueva Zelanda | NZ |
Nicaragua | NI |
Níger | NE |
Nigeria | NG |
Niue | NU |
Isla Norfolk | NF |
Islas Marianas del Norte | MP |
Noruega | NO |
Omán | OM |
Pakistán | PK |
Palaos | PW |
Autoridad palestina | PS |
Panamá | PA |
Papúa Nueva Guinea | PG |
Paraguay | PY |
Perú | PE |
Filipinas | PH |
Islas Pitcairn | PN |
Polonia | PL |
Portugal | PT |
Qatar | QA |
Reunión | RE |
Rumanía | RO |
Rusia | RU |
Ruanda | RW |
San Bartolomé | BL |
Santa Elena, Ascensión y Tristán da Cunha | SH |
San Cristóbal y Nieves | KN |
Santa Lucía | LC |
San Martín (zona francesa) | MF |
San Pedro y Miquelón | PM |
San Vicente y las Granadinas | VC |
Samoa | WS |
San Marino | SM |
Arabia Saudí | SA |
Senegal | SN |
Serbia | RS |
Seychelles | SC |
Sierra Leona | SL |
Singapur | SG |
Sint Maarten (zona neerlandesa) | SX |
Eslovaquia | SK |
Eslovenia | SI |
Islas Salomón | SB |
Somalia | SO |
Sudáfrica | ZA |
Georgia del Sur e Islas Sandwich del Sur | GS |
España | ES |
Sri Lanka | LK |
Surinam | SR |
Svalbard y Jan Mayen | SJ |
Suazilandia | SZ |
Suecia | SE |
Suiza | CH |
Santo Tomé y Príncipe | ST |
Taiwán | TW |
Tayikistán | TJ |
Tanzania | TZ |
Tailandia | TH |
Timor-Leste | TL |
Togo - TG | |
Tokelau | TK |
Tonga | TO |
Trinidad y Tobago - TT | |
Túnez | TN |
Turquía | TR |
Turkmenistán | TM |
Islas Turcas y Caicos | TC |
Tuvalu | TV |
EE. UU. Islas Ultramarinas Menores de Estados Unidos | UM |
EE. UU. Vírgenes de EE. UU. | VI |
Uganda | UG |
Ucrania | UA |
Emiratos Árabes Unidos | AE |
Reino Unido | GB |
Estados Unidos | US |
Uruguay | UY |
Uzbekistán | UZ |
Vanuatu | VU |
Vietnam | VN |
Wallis y Futuna | WF |
Yemen | YE |
Zambia | ZM |
Zimbabue | ZW |
Islas Åland | AX |
Categorías y subcategorías
Category | Subcategorías |
---|---|
BooksAndReference | EReader, Fiction, Nonfiction, Reference |
Negocio | AccountingAndfinance, Collaboration, CRM, DataAndAnalytics, FileManagement, InventoryAndlogistics, LegalAndHR, ProjectManagement, RemoteDesktop, SalesAndMarketing, TimeAndExpenses |
DeveloperTools | Database, DesignTools, DevelopmentKits, Networking, ReferenceAndTraining, Servers, Utilities, WebHosting |
Education | EducationBooksAndReference, EarlyLearning, InstructionalTools, Language, StudyAids |
Entretenimiento | (Ninguna) |
FoodAndDining | (Ninguna) |
GovernmentAndPolitics | (Ninguna) |
HealthAndFitness | (Ninguna) |
KidsAndFamily | KidsAndFamilyBooksAndReference, KidsAndFamilyEntertainment, HobbiesAndToys, SportsAndActivities, KidsAndFamilyTravel |
Estilo de vida | Automotive, DYI, HomeAndGarden, Relationships, SpecialInterest, StyleAndFashion |
Medicina | (Ninguna) |
MultimediaDesign | IllustrationAndGraphicDesign, MusicProduction, PhotoAndVideoProduction |
Música | (Ninguna) |
NavigationAndMaps | (Ninguna) |
NewsAndWeather | News, Weather |
PersonalFinance | BankingAndInvestments, BudgetingAndTaxes |
Personalización | RingtonesAndSounds, themes, WallpaperAndLockScreens |
PhotoAndVideo | (Ninguna) |
Productividad | (Ninguna) |
Seguridad | PCProtection, PersonalSecurity |
Compras | (Ninguna) |
Redes sociales | (Ninguna) |
Deportes | (Ninguna) |
Viajes | CityGuides, Hotels |
UtilitiesAndTools | BackupAndManage, FileManager |
Idiomas
Nombre del idioma | Códigos de idioma admitidos |
---|---|
Afrikáans | af, af-za |
Albanés | sq, sq-al |
Amárico | am, am-et |
Armenio | hy, hy-am |
Asamés | as, as-in |
Azerbaiyano | az-arab, az-arab-az, az-cyrl, az-cyrl-az, az-latn, az-latn-az |
Vasco (España) | eu, eu-es |
Bielorruso | be, be-by |
Bengalí | bn, bn-bd, bn-in |
Bosnio | bs, bs-cyrl, bs-cyrl-ba, bs-latn, bs-latn-ba |
Búlgaro | bg, bg-bg |
Catalán | ca, ca-es, ca-es-valencia |
Cheroqui | chr-cher, chr-cher-us, chr-latn |
Chino (simplificado) | zh-Hans, zh-cn, zh-hans-cn, zh-sg, zh-hans-sg |
Chino (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 |
Checo | cs, cs-cz |
Danés | da, da-dk |
Dari | prs, prs-af, prs-arab |
Neerlandés | nl, nl-nl, nl-be |
English | 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 |
Estonio | et, et-ee |
Filipino - fil, fil-latn, fil-ph | |
Finé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 |
Gallego | gl, gl-es |
Georgiano | ka, ka-ge |
Alemán | de, de-at, de-ch, de-de, de-lu, de-li |
Griego | el, el-gr |
Gujarati | gu, gu-in |
Hausa | ha, ha-latn, ha-latn-ng |
Hebreo | he, he-il |
Hindi | hi, hi-in |
Húngaro | hu, hu-hu |
Islandés | is, is-is |
Igbo - ig-latn, ig-ng | |
Indonesio | id, id-id |
Inuktitut (latino) | iu-cans, iu-latn, iu-latn-ca |
Irlandés | ga, ga-ie |
isiXhosa | xh, xh-za |
isiZulu | zu, zu-za |
Italiano | it, it-it, it-ch |
Japonés | ja , ja-jp |
Canarés | kn, kn-in |
Kazajo | kk, kk-kz |
Jemer | km, km-kh |
Quiché | quc-latn, qut-gt, qut-latn |
Kinyarwanda | rw, rw-rw |
KiSwahili | sw, sw-ke |
Konkani | kok, kok-in |
Coreano | ko, ko-kr |
Kurdo | ku-arab, ku-arab-iq |
Kirguís | ky-kg, ky-cyrl |
Lao | lo, lo-la |
Letón | lv, lv-lv |
Lituano | lt, lt-lt |
Luxemburgués | lb, lb-lu |
Macedonio | mk, mk-mk |
Malayo | ms, ms-bn, ms-my |
Malayalam | ml, ml-in |
Maltés | mt, mt-mt |
Maori | mi, mi-latn, mi-nz |
Maratí | mr, mr-in |
Mongol (cirílico) | mn-cyrl, mn-mong, mn-mn, mn-phag |
Nepalí | ne, ne-np |
Noruego | nb, nb-no, nn, nn-no, no, no-no |
Odia | or, or-in |
Persa | fa, fa-ir |
Polaco | pl, pl-pl |
Portugués (Brasil) | pt-br |
Portugués (Portugal) | pt, pt-pt |
Punjabi | pa, pa-arab, pa-arab-pk, pa-deva, pa-in |
Quechua | quz, quz-bo, quz-ec, quz-pe |
Rumano | ro, ro-ro |
Ruso | ru , ru-ru |
Gaélico escocés | gd-gb, gd-latn |
Serbio (latino) | sr-Latn, sr-latn-cs, sr, sr-latn-ba, sr-latn-me, sr-latn-rs |
Serbio (cirílico) | sr-cyrl, sr-cyrl-ba, sr-cyrl-cs, sr-cyrl-me, sr-cyrl-rs |
Sotho septentrional | nso, nso-za |
Setsuana | tn, tn-bw, tn-za |
Sindhi | sd-arab, sd-arab-pk, sd-deva |
Cingalés | si, si-lk |
Eslovaco | sk, sk-sk |
Esloveno | sl, sl-si |
Español | 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 |
Tayiko (cirílico) | tg-arab, tg-cyrl, tg-cyrl-tj, tg-latn |
Tamil | ta, ta-in |
Tatar | tt-arab, tt-cyrl, tt-latn, tt-ru |
Telugu | te, te-in |
Tailandés | th, th-th |
Tigriña | ti, ti-et |
Turco | tr, tr-tr |
Turcomano | tk-cyrl, tk-latn, tk-tm, tk-latn-tr, tk-cyrl-tr |
Ucraniano | uk, uk-ua |
Urdu | ur, ur-pk |
Uigur | ug-arab, ug-cn, ug-cyrl, ug-latn |
Uzbeko (latino) | uz, uz-cyrl, uz-latn, uz-latn-uz |
Vietnamita | vi, vi-vn |
Galés | cy, cy-gb |
Wolof | wo, wo-sn |
Yoruba | yo-latn, yo-ng |
Solicitud de ejemplo
{
"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"]
}
Encabezados de respuesta
Encabezado | Valor |
---|---|
X-Correlation-ID |
Id. exclusivo de tipo GUID para cada solicitud. Se puede compartir con el equipo de soporte técnico para analizar cualquier problema. |
Retry-After |
Tiempo en segundos que el cliente debe esperar antes de llamar a las API de nuevo debido a la limitación de volumen |
Parámetros de respuesta
Nombre | Escribir | Descripción |
---|---|---|
isSuccess | Booleano | |
errors | Matriz de objetos | Lista de mensajes de error o advertencia, si los hay |
code | Cadena | El código de error del mensaje. |
message | String | Descripción del error |
Destino | Cadena | Entidad desde la que se originó el error |
responseData | Object | Contiene la carga de respuesta real para la solicitud. |
pollingUrl | Cadena | Dirección URL de sondeo para obtener el estado de cualquier envío en curso |
ongoingSubmissionId | Cadena | Id. de envío de cualquier envío ya en curso |
Respuesta de ejemplo
{
"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 Get Current Draft Packages
Captura los detalles de los paquetes en el borrador del envío actual.
Ruta de acceso [todos los paquetes]: /submission/v1/product/{productId}/packages
Método: GET
Ruta de acceso [paquete único]: /submission/v1/product/{productId}/packages/{packageId}
Método: GET
Parámetros de la ruta de acceso
Nombre | Descripción |
---|---|
productId | Identificador del producto en el Centro de partners |
packageId | Id. exclusivo del paquete que se va a capturar |
Encabezados obligatorios
Encabezado | Valor |
---|---|
Authorization: Bearer <Token> |
Con el identificador de la aplicación de Azure AD registrado en la cuenta del Centro de partners |
X-Seller-Account-Id |
Id. de vendedor de la cuenta del Centro de partners |
Encabezados de respuesta
Encabezado | Valor |
---|---|
X-Correlation-ID |
Id. exclusivo de tipo GUID para cada solicitud. Se puede compartir con el equipo de soporte técnico para analizar cualquier problema. |
Retry-After |
Tiempo en segundos que el cliente debe esperar antes de llamar a las API de nuevo debido a la limitación de volumen. |
Parámetros de respuesta
Nombre | Escribir | Descripción |
---|---|---|
isSuccess | Booleano | |
errors | Matriz de objetos | Lista de mensajes de error o advertencia, si los hay |
code | Cadena | El código de error del mensaje. |
message | String | Descripción del error |
Destino | Cadena | Entidad desde la que se originó el error |
responseData | Object | |
packages | Matriz de objetos | Objeto que contiene los datos del módulo de paquetes |
packageId | Cadena | |
packageUrl | Cadena | |
languages | Matriz de cadenas | |
arquitecturas | Matriz de cadenas | [Neutral, X86, X64, Arm, Arm64] |
isSilentInstall | Booleano | Debe marcarse como true si el instalador se ejecuta en modo silencioso sin necesidad de conmutadores o, de lo contrario, es false |
installerParameters | Cadena | |
genericDocUrl | Cadena | |
errorDetails | Matriz de objetos | |
errorScenario | Cadena | |
errorScenarioDetails | Matriz de objetos | |
errorValue | Cadena | |
errorUrl | Cadena | |
packageType | Cadena |
Respuesta de ejemplo
{
"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",
}]
}
}
API Update Current Draft Packages
Actualiza los detalles de los paquetes en el borrador del envío actual.
Ruta de acceso [actualización del módulo completo]: /submission/v1/product/{productId}/packages
Método: PUT
Ruta de acceso [actualización de la revisión del paquete único]: /submission/v1/product/{productId}/packages/{packageId}
Método: PATCH
Comportamiento de la API
En el caso de la API de actualización completa del módulo, es necesario que todos los datos de los paquetes estén presentes en la solicitud para la actualización completa de cada campo. Cuando un campo no esté presente en la solicitud, su valor predeterminado se usará para sobrescribir el valor actual de ese módulo específico. Esto hace que se sobrescriban todos los paquetes existentes con un nuevo conjunto de paquetes de la solicitud. Esto dará lugar a la regeneración de identificadores de paquete, y el usuario debe llamar a la API GET Packages para obtener los identificadores de paquete más recientes.
En el caso de la API de actualización de la revisión del paquete único, solo los campos que se van a actualizar para un paquete dado deben estar presentes en la solicitud. Estos valores de campos de la solicitud sobrescribirán sus valores existentes y mantendrán todos los demás campos que no están presentes en la solicitud igual que los actuales para ese paquete específico. Los demás paquetes del conjunto permanecen tal como están.
Parámetros de la ruta de acceso
Nombre | Descripción |
---|---|
productId | Identificador del producto en el Centro de partners |
packageId | El id. exclusivo del paquete |
Encabezados obligatorios
Encabezado | Valor |
---|---|
Authorization: Bearer <Token> |
Con el identificador de la aplicación de Azure AD registrado en la cuenta del Centro de partners |
X-Seller-Account-Id |
Id. de vendedor de la cuenta del Centro de partners |
Parámetros de la solicitud
Nombre | Escribir | Descripción |
---|---|---|
packages | Matriz de objetos | Objeto que contiene los datos del módulo de paquetes [solo es necesario para la actualización completa del módulo] |
packageUrl | Cadena | Obligatorio |
languages | Matriz de cadenas | Obligatorio |
arquitecturas | Matriz de cadenas | Obligatorio Debe contener una única arquitectura: Neutral, X86, X64, Arm, Arm64 |
isSilentInstall | Booleano | Obligatorio Debe marcarse como true si el instalador se ejecuta en modo silencioso sin necesidad de conmutadores o, de lo contrario, es false |
installerParameters | Cadena | Obligatorio si isSilentInstall es false |
genericDocUrl | Cadena | Obligatorio si packageType es exe Vínculo al documento que contiene detalles de los códigos de error personalizados para el instalador de tipo EXE |
errorDetails | Matriz de objetos | Metadatos para contener códigos de error personalizados y detalles para los instaladores de tipo EXE. |
errorScenario | Cadena | Identifique el escenario de error específico. [installationCancelledByUser, applicationAlreadyExists, installationAlreadyInProgress, diskSpaceIsFull, rebootRequired, networkFailure, packageRejectedDuringInstallation, installationSuccessful, miscellaneous] |
errorScenarioDetails | Matriz de objetos | |
errorValue | Cadena | Código de error que puede estar presente durante la instalación |
errorUrl | Cadena | Dirección URL con los detalles del error |
packageType | Cadena | Obligatorio [exe, msi] |
Solicitud de ejemplo [actualización completa del 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",
}]
}
Solicitud de ejemplo [actualización de la revisión de paquete ú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",
}
Encabezados de respuesta
Encabezado | Valor |
---|---|
X-Correlation-ID |
Id. exclusivo de tipo GUID para cada solicitud. Se puede compartir con el equipo de soporte técnico para analizar cualquier problema. |
Retry-After |
Tiempo en segundos que el cliente debe esperar antes de llamar a las API de nuevo debido a la limitación de volumen. |
Parámetros de respuesta
Nombre | Escribir | Descripción |
---|---|---|
isSuccess | Booleano | |
errors | Matriz de objetos | [Lista de mensajes de error o advertencia, si los hay] |
code | Cadena | El código de error del mensaje |
message | String | Descripción del error |
Destino | Cadena | Entidad desde la que se originó el error |
responseData | Object | |
pollingUrl | Cadena | [Dirección URL de sondeo para obtener el estado de envío en caso de cualquier envío ya en curso] |
ongoingSubmissionId | Cadena | [Id. de envío de cualquier envío ya en curso] |
Respuesta de ejemplo
{
"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 Commit Packages
Confirma el nuevo conjunto de paquetes actualizados mediante las API de actualización de paquetes en el borrador de envío actual. Esta API devuelve una dirección URL de sondeo para realizar un seguimiento de la carga de paquetes.
Ruta de acceso: /submission/v1/product/{productId}/packages/commit
Método: POST
Parámetros de la ruta de acceso
Nombre | Descripción |
---|---|
productId | Identificador del producto en el Centro de partners |
Encabezados obligatorios
Encabezado | Valor |
---|---|
Authorization: Bearer <Token> |
Con el identificador de la aplicación de Azure AD registrado en la cuenta del Centro de partners |
X-Seller-Account-Id |
Id. de vendedor de la cuenta del Centro de partners |
Encabezados de respuesta
Encabezado | Valor |
---|---|
X-Correlation-ID |
Id. exclusivo de tipo GUID para cada solicitud. Se puede compartir con el equipo de soporte técnico para analizar cualquier problema. |
Retry-After |
Tiempo en segundos que el cliente debe esperar antes de llamar a las API de nuevo debido a la limitación de volumen. |
Parámetros de respuesta
Nombre | Escribir | Descripción |
---|---|---|
isSuccess | Booleano | |
errors | Matriz de objetos | [Lista de mensajes de error o advertencia, si los hay] |
code | Cadena | El código de error del mensaje. |
message | String | Descripción del error |
Destino | Cadena | Entidad desde la que se originó el error |
responseData | Object | |
pollingUrl | Cadena | [Dirección URL de sondeo para obtener el estado de carga o envío de paquetes en caso de envío ya en curso] |
ongoingSubmissionId | Cadena | [Id. de envío de cualquier envío ya en curso] |
Respuesta de ejemplo
{
"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": ""
}
}
API Get Current Draft Listing Assets
Captura los detalles de los recursos de descripción en el borrador del envío actual.
Ruta de acceso: /submission/v1/product/{productId}/listings/assets?languages={languages}
Método: GET
Parámetros de la ruta de acceso
Nombre | Descripción |
---|---|
productId | Identificador del producto en el Centro de partners |
Parámetros de consulta
Nombre | Descripción |
---|---|
languages | [Opcional] Los idiomas de descripción se filtran como cadena separada por comas [límite de hasta 200 idiomas]. Si no está presente, se recuperan los datos de recursos de los primeros 200 idiomas de descripción disponibles. (Por ejemplo, "en-us, en-gb"). |
Encabezados obligatorios
Encabezado | Valor |
---|---|
Authorization: Bearer <Token> |
Con el identificador de la aplicación de Azure AD registrado en la cuenta del Centro de partners |
X-Seller-Account-Id |
Id. de vendedor de la cuenta del Centro de partners |
Encabezados de respuesta
Encabezado | Valor |
---|---|
X-Correlation-ID |
Id. exclusivo de tipo GUID para cada solicitud. Se puede compartir con el equipo de soporte técnico para analizar cualquier problema. |
Retry-After |
Tiempo en segundos que el cliente debe esperar antes de llamar a las API de nuevo debido a la limitación de volumen. |
Parámetros de respuesta
Nombre | Escribir | Descripción |
---|---|---|
isSuccess | Booleano | |
errors | Matriz de objetos | Lista de mensajes de error o advertencia, si los hay |
code | Cadena | El código de error del mensaje. |
message | String | Descripción del error |
Destino | Cadena | Entidad desde la que se originó el error |
responseData | Object | |
listingAssets | Matriz de objetos | Detalles de los recursos de descripción para cada idioma |
language | Cadena | |
storeLogos | Matriz de objetos | |
screenshots | Matriz de objetos | |
id | Cadena | |
assetUrl | Cadena | Debe ser una dirección URL válida |
imageSize | Object | |
width | Entero | |
height | Entero |
Respuesta de ejemplo
{
"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
}
}
]
}]
}
}
API Create Listing Assets
Crea una nueva carga de recursos de descripción en el borrador del envío actual.
Actualización de los recursos de descripción
La API de envío de Microsoft Store para aplicaciones EXE o MSI usa direcciones URL de SAS generadas en tiempo de ejecución en almacenes de blobs para cada carga de recursos de imagen individual, junto con una llamada a la API Commit después de que la carga se completa correctamente. Para tener la capacidad de actualizar los recursos de descripción y, a su vez, poder agregar o quitar configuraciones regionales en el módulo de descripciones, se puede usar el siguiente enfoque:
- Utilice la API Create Listing Asset para enviar una solicitud relacionada con la carga de recursos junto con el idioma, el tipo y el recuento de recursos.
- En función del número de recursos solicitados, los identificadores de recurso se crean a petición y crearían una dirección URL de SAS a corto plazo y la enviarían de vuelta en el cuerpo de la respuesta en el tipo de recursos. Puede utilizar esta dirección URL para cargar recursos de imagen de tipo específico mediante clientes HTTP [Put Blob (API REST) - Azure Storage | Microsoft Docs].
- Después de cargar, puede usar la API Commit Listing Assets para enviar también la nueva información del id. de recurso recibida anteriormente de la llamada API anterior. La API única confirmará internamente los datos de los recursos de descripción después de la validación.
- Este enfoque sobrescribirá de manera eficaz todo el conjunto de imágenes anteriores del tipo de recurso en el idioma específico que se envía en la solicitud. Por lo tanto, se quitarán los recursos cargados previamente.
Ruta de acceso: /submission/v1/product/{productId}/listings/assets/create
Método: POST
Parámetros de la ruta de acceso
Nombre | Descripción |
---|---|
productId | Identificador del producto en el Centro de partners |
Encabezados obligatorios
Encabezado | Descripción |
---|---|
Authorization: Bearer <Token> |
Con el identificador de la aplicación de Azure AD registrado en la cuenta del Centro de partners |
X-Seller-Account-Id |
Id. de vendedor de la cuenta del Centro de partners |
Parámetros de la solicitud
Nombre | Escribir | Descripción |
---|---|---|
language | Cadena | Obligatorio |
createAssetRequest | Object | Obligatorio |
Instantánea | Entero | Obligatorio si ISV tiene que actualizar capturas de pantalla o agregar un nuevo idioma de descripción [1 - 10] |
Logotipo | Entero | Obligatorio si ISV tiene que actualizar logotipos o agregar un nuevo idioma de descripción [1 o 2] |
Encabezados de respuesta
Encabezado | Descripción |
---|---|
X-Correlation-ID |
Id. exclusivo de tipo GUID para cada solicitud. Se puede compartir con el equipo de soporte técnico para analizar cualquier problema. |
Retry-After |
Tiempo en segundos que el cliente debe esperar antes de llamar a las API de nuevo debido a la limitación de volumen. |
Parámetros de respuesta
Nombre | Escribir | Descripción |
---|---|---|
isSuccess | Booleano | |
errors | Matriz de objetos | Lista de mensajes de error o advertencia, si los hay |
code | Cadena | El código de error del mensaje. |
message | String | Descripción del error |
Destino | Cadena | Entidad desde la que se originó el error |
responseData | Object | |
listingAssets | Object | Objeto que contiene detalles de StoreLogos y Screenshots que se van a cargar |
language | Cadena | |
storeLogos | Matriz de objetos | |
screenshots | Matriz de objetos | |
id | Cadena | |
primaryAssetUploadUrl | Cadena | Dirección URL principal para cargar el recurso de descripción mediante la API REST de Azure Blob |
secondaryAssetUploadUrl | Cadena | Dirección URL secundaria para cargar el recurso de descripción mediante la API REST de Azure Blob |
httpMethod | Método de HTTP | El método HTTP necesario para cargar recursos a través de las direcciones URL de carga de recursos: principal o secundaria |
httpHeaders | Object | Objeto con claves como encabezados obligatorios que van a estar presentes en la llamada a la API Upload a las direcciones URL de carga de recursos. Si el valor no está vacío, los encabezados deben tener valores específicos. De lo contrario, los valores se calculan durante la llamada API. |
Respuesta de ejemplo
{
"isSuccess": true,
"errors": [{
"code": "badrequest",
"message": "Error Message 1",
"target": "listings"
}, {
"code": "warning",
"message": "Warning Message 1",
"target": "properties"
}],
"responseData": {
"listingAssets": {
"language": "en-us",
"storeLogos":[{
"id": "1234567890abcdefgh",
"primaryAssetUploadUrl": "https://contoso.com/upload?blob=1234567890abcdefgh&sig=12345",
"secondaryAssetUploadUrl": "https://contoso.com/upload?blob=0987654321abcdfger&sig=54326",
"httpMethod": "PUT",
"httpHeaders": {"Required Header Name": "Header Value"}
}],
"screenshots":[{
"id": "0987654321abcdfger",
"primaryAssetUploadUrl": "https://contoso.com/upload?blob=0987654321abcdfger&sig=54321",
"secondaryAssetUploadUrl": "https://contoso.com/upload?blob=0987654321abcdfger&sig=54322",
"httpMethod": "PUT",
"httpHeaders": {"Required Header Name": "Header Value"}
}]
}
}
}
API Commit Listing Assets
Confirma el nuevo recurso de descripción cargado mediante los detalles de la API Create Assets en el borrador del envío actual.
Ruta de acceso: /submission/v1/product/{productId}/listings/assets/commit
Método: PUT
Parámetros de la ruta de acceso
Nombre | Descripción |
---|---|
productId | Identificador del producto en el Centro de partners |
Encabezados obligatorios
Encabezado | Descripción |
---|---|
Authorization: Bearer <Token> |
Con el identificador de la aplicación de Azure AD registrado en la cuenta del Centro de partners |
X-Seller-Account-Id |
Id. de vendedor de la cuenta del Centro de partners |
Parámetros de la solicitud
Nombre | Escribir | Descripción |
---|---|---|
listingAssets | Object | |
language | Cadena | |
storeLogos | Matriz de objetos | |
screenshots | Matriz de objetos | |
id | Cadena | Debe ser un identificador existente que el usuario quiera conservar desde la API Get Current Listing Assets o un nuevo identificador con el que se cargó un nuevo recurso en la API Create Listing Assets. |
assetUrl | Cadena | Debe ser la dirección URL del recurso existente que el usuario desea conservar desde la API Get Current Listing Assets o la dirección URL de carga principal o secundaria, con la que se cargó un nuevo recurso en la API Create Listing Assets. Debe ser una dirección URL válida |
Solicitud de ejemplo
{
"listingAssets": {
"language": "en-us",
"storeLogos": [
{
"id": "1234567890abcdefgh",
"assetUrl": "https://contoso.com/blob=1234567890abcdefgh",
}
],
"screenshots": [
{
"id": "1234567891abcdefgh",
"assetUrl": "https://contoso.com/blob=1234567891abcdefgh",
}
]
}
}
Encabezados de respuesta
Encabezado | Descripción |
---|---|
X-Correlation-ID |
Id. exclusivo de tipo GUID para cada solicitud. Se puede compartir con el equipo de soporte técnico para analizar cualquier problema. |
Retry-After |
Tiempo en segundos que el cliente debe esperar antes de llamar a las API de nuevo debido a la limitación de volumen. |
Parámetros de respuesta
Nombre | Escribir | Descripción |
---|---|---|
isSuccess | Booleano | |
errors | Matriz de objetos | Lista de mensajes de error o advertencia, si los hay |
code | Cadena | El código de error del mensaje. |
message | String | Descripción del error |
Destino | Cadena | Entidad desde la que se originó el error |
responseData | Object | |
pollingUrl | Cadena | Dirección URL de sondeo para obtener el estado de cualquier envío en curso |
ongoingSubmissionId | Cadena | Id. de envío de cualquier envío ya en curso |
Respuesta de ejemplo
{
"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 Module Status Polling
API para comprobar la preparación del módulo antes de que se pueda crear el envío. Además, valida el estado de carga de los paquetes.
Ruta de acceso: /submission/v1/product/{productId}/status
Método: GET
Parámetros de la ruta de acceso
Nombre | Descripción |
---|---|
productId | Identificador del producto en el Centro de partners |
Encabezados obligatorios
Encabezado | Descripción |
---|---|
Authorization: Bearer <Token> |
Con el identificador de la aplicación de Azure AD registrado en la cuenta del Centro de partners |
X-Seller-Account-Id |
Id. de vendedor de la cuenta del Centro de partners |
Encabezados de respuesta
Encabezado | Descripción |
---|---|
X-Correlation-ID |
Id. exclusivo de tipo GUID para cada solicitud. Se puede compartir con el equipo de soporte técnico para analizar cualquier problema. |
Retry-After |
Tiempo en segundos que el cliente debe esperar antes de llamar a las API de nuevo debido a la limitación de volumen. |
Parámetros de respuesta
Nombre | Escribir | Descripción |
---|---|---|
isSuccess | Booleano | |
errors | Matriz de objetos | Lista de mensajes de error o advertencia, si los hay |
code | Cadena | El código de error del mensaje. |
message | String | Descripción del error |
Destino | Cadena | Entidad desde la que se originó el error |
responseData | Object | |
isReady | Booleano | Indica si todos los módulos están en estado listo, incluida la carga de paquetes |
ongoingSubmissionId | Cadena | Id. de envío de cualquier envío ya en curso |
Respuesta de ejemplo
{
"isSuccess": true,
"errors": [{
"code": "badrequest",
"message": "Error Message 1",
"target": "listings"
}, {
"code": "warning",
"message": "Warning Message 1",
"target": "properties"
}],
"responseData": {
"isReady": true,
"ongoingSubmissionId": ""
}
}
API Create Submission
Crea un envío a partir del borrador actual de la aplicación MSI o EXE. La API comprueba:
- El envío activo y produce un mensaje de error si existe un envío activo.
- Si todos los módulos están en estado listo para crear el envío.
- Cada campo del envío se valida según los requisitos de Store.
Ruta de acceso:/submission/v1/product/{productId}/submit
Método: POST
Parámetros de la ruta de acceso
Nombre | Descripción |
---|---|
productId | Identificador del producto en el Centro de partners |
Encabezados obligatorios
Encabezado | Descripción |
---|---|
Authorization: Bearer <Token> |
Con el identificador de la aplicación de Azure AD registrado en la cuenta del Centro de partners |
X-Seller-Account-Id |
Id. de vendedor de la cuenta del Centro de partners |
Encabezados de respuesta
Encabezado | Descripción |
---|---|
X-Correlation-ID |
Id. exclusivo de tipo GUID para cada solicitud. Se puede compartir con el equipo de soporte técnico para analizar cualquier problema. |
Retry-After |
Tiempo en segundos que el cliente debe esperar antes de llamar a las API de nuevo debido a la limitación de volumen. |
Parámetros de respuesta
Nombre | Escribir | Descripción |
---|---|---|
isSuccess | Booleano | |
errors | Matriz de objetos | Lista de mensajes de error o advertencia, si los hay |
code | Cadena | El código de error del mensaje. |
message | String | Descripción del error |
Destino | Cadena | Entidad desde la que se originó el error |
responseData | Object | |
pollingUrl | Cadena | Dirección URL de sondeo para obtener el estado de preparación del módulo, incluida la carga de paquetes para el envío |
submissionId | Cadena | Id. del envío recién creado |
ongoingSubmissionId | Cadena | Id. de envío de cualquier envío ya en curso |
Respuesta de ejemplo
{
"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 Submission Status Polling
API para comprobar el estado del envío.
Ruta de acceso: /submission/v1/product/{productId}/submission/{submissionId}/status
Método: GET
Parámetros de la ruta de acceso
Nombre | Descripción |
---|---|
productId | Identificador del producto en el Centro de partners |
Encabezados obligatorios
Encabezado | Descripción |
---|---|
Authorization: Bearer <Token> |
Con el identificador de la aplicación de Azure AD registrado en la cuenta del Centro de partners |
X-Seller-Account-Id |
Id. de vendedor de la cuenta del Centro de partners |
Encabezados de respuesta
Encabezado | Descripción |
---|---|
X-Correlation-ID |
Id. exclusivo de tipo GUID para cada solicitud. Se puede compartir con el equipo de soporte técnico para analizar cualquier problema. |
Retry-After |
Tiempo en segundos que el cliente debe esperar antes de llamar a las API de nuevo debido a la limitación de volumen. |
Parámetros de respuesta
Nombre | Escribir | Descripción |
---|---|---|
isSuccess | Booleano | |
errors | Matriz de objetos | Lista de mensajes de error o advertencia, si los hay |
code | Cadena | El código de error del mensaje. |
message | String | Descripción del error |
Destino | Cadena | Entidad desde la que se originó el error |
responseData | Object | |
publishingStatus | Cadena | Estado de publicación del envío: [INPROGRESS, PUBLISHED, FAILED, UNKNOWN] |
hasFailed | Booleano | Indica si la publicación ha producido un error y no se reintentará. |
Respuesta de ejemplo
{
"isSuccess": true,
"errors": [{
"code": "badrequest",
"message": "Error Message 1",
"target": "listings"
}, {
"code": "warning",
"message": "Warning Message 1",
"target": "properties"
}],
"responseData": {
"publishingStatus": "INPROGRESS",
"hasFailed": false
}
}
Ejemplos de código
En los artículos siguientes se proporcionan ejemplos de código detallados que muestran cómo usar la API de envío de Microsoft Store en distintos lenguajes de programación:
Ejemplo de C#: API de envío de Microsoft Store para aplicaciones MSI o EXE
En este artículo se proporcionan ejemplos de código de C# que muestran cómo usar la API de envío de Microsoft Store para aplicaciones MSI o EXE. Puede revisar cada ejemplo para obtener más información sobre la tarea que muestra o puede compilar todos los ejemplos de código de este artículo en una aplicación de consola.
Requisitos previos Estos ejemplos utilizan la biblioteca siguiente:
- Paquete NuGet Newtonsoft.Json de Newtonsoft.
Programa principal El siguiente ejemplo implementa un programa de línea de comandos que llama a los otros métodos de ejemplo de este artículo para mostrar diferentes maneras de usar la API de envío de Microsoft Store. Para adaptar este programa para su propio uso:
- Asigne la propiedad SellerId al identificador de vendedor de la cuenta del Centro de partners.
- Asigne la propiedad ApplicationId al identificador de la aplicación que desea administrar.
- Asigne las propiedades ClientId y ClientSecret al identificador de cliente y la clave de la aplicación, y reemplace la cadena tenantid en la dirección URL de TokenEndpoint por el identificador de inquilino de la aplicación. Para obtener más información, consulte Asociación de una aplicación de Azure AD a la cuenta del Centro de partners
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();
}
}
}
Clase auxiliar ClientConfiguration mediante C#
La aplicación de ejemplo utiliza la clase auxiliar ClientConfiguration para pasar datos de Azure Active Directory y datos de aplicación a cada uno de los métodos de ejemplo que utilizan la API de envío de Microsoft Store.
using System;
using System.Collections.Generic;
using System.Text;
namespace Win32SubmissionApiCSharpSample
{
public class ClientConfiguration
{
/// <summary>
/// Client Id of your Azure Active Directory app.
/// Example" 00001111-aaaa-2222-bbbb-3333cccc4444
/// </summary>
public string ClientId { get; set; }
/// <summary>
/// Client secret of your Azure Active Directory app
/// </summary>
public string ClientSecret { get; set; }
/// <summary>
/// Service root endpoint.
/// Example: "https://api.store.microsoft.com"
/// </summary>
public string ServiceUrl { get; set; }
/// <summary>
/// Token endpoint to which the request is to be made. Specific to your Azure Active Directory app
/// Example: https://login.microsoftonline.com/d454d300-128e-2d81-334a-27d9b2baf002/oauth2/v2.0/token
/// </summary>
public string TokenEndpoint { get; set; }
/// <summary>
/// Resource scope. If not provided (set to null), default one is used for the production API
/// endpoint ("https://api.store.microsoft.com/.default")
/// </summary>
public string Scope { get; set; }
/// <summary>
/// Partner Center Application ID.
/// Example: 3e31a9f9-84e8-4d2d-9eba-487878d02ebf
/// </summary>
public string ApplicationId { get; set; }
/// <summary>
/// The Partner Center Seller Id
/// Example: 123456892
/// </summary>
public int SellerId { get; set; }
}
}
Crear un envío de aplicación con C#
En el siguiente ejemplo se implementa una clase que utiliza varios métodos en la API de envío de Microsoft Store para actualizar un envío de aplicación.
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.
}
}
}
Clase auxiliar IngestionClient mediante C#
La clase IngestionClient proporciona métodos auxiliares que otros métodos de la aplicación de ejemplo utilizan para realizar las tareas siguientes:
- Obtener un token de acceso de Azure AD para utilizarlo para llamar a los métodos en la API de envío de Microsoft Store. Después de obtener un token, tiene 60 minutos para utilizar este token en llamadas a la API de envío de Microsoft Store antes de que el token expire. Después de que el token expire, puede generar uno nuevo.
- Procesar las solicitudes HTTP para la API de envío de Microsoft Store.
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using System;
using System.Collections.Generic;
using System.IO;
using System.Net.Http;
using System.Net.Http.Headers;
using System.Text;
using System.Threading.Tasks;
namespace Win32SubmissionApiCSharpSample
{
/// <summary>
/// This class is a proxy that abstracts the functionality of the API service
/// </summary>
public class SubmissionClient : IDisposable
{
public static readonly string Version = "1";
private HttpClient httpClient;
private HttpClient imageUploadClient;
private readonly string accessToken;
public static readonly string PackagesUrlTemplate = "/submission/v{0}/product/{1}/packages";
public static readonly string PackageByIdUrlTemplate = "/submission/v{0}/product/{1}/packages/{2}";
public static readonly string PackagesCommitUrlTemplate = "/submission/v{0}/product/{1}/packages/commit";
public static readonly string AppMetadataUrlTemplate = "/submission/v{0}/product/{1}/metadata";
public static readonly string AppListingsFetchMetadataUrlTemplate = "/submission/v{0}/product/{1}/metadata/listings";
public static readonly string ListingAssetsUrlTemplate = "/submission/v{0}/product/{1}/listings/assets";
public static readonly string ListingAssetsCreateUrlTemplate = "/submission/v{0}/product/{1}/listings/assets/create";
public static readonly string ListingAssetsCommitUrlTemplate = "/submission/v{0}/product/{1}/listings/assets/commit";
public static readonly string ProductDraftStatusPollingUrlTemplate = "/submission/v{0}/product/{1}/status";
public static readonly string CreateSubmissionUrlTemplate = "/submission/v{0}/product/{1}/submit";
public static readonly string SubmissionStatusPollingUrlTemplate = "/submission/v{0}/product/{1}/submission/{2}/status";
public const string JsonContentType = "application/json";
public const string PngContentType = "image/png";
public const string BinaryStreamContentType = "application/octet-stream";
/// <summary>
/// Initializes a new instance of the <see cref="SubmissionClient" /> class.
/// </summary>
/// <param name="accessToken">
/// The access token. This is JWT a token obtained from Azure Active Directory allowing the caller to invoke the API
/// on behalf of a user
/// </param>
/// <param name="serviceUrl">The service URL.</param>
public SubmissionClient(string accessToken, string serviceUrl)
{
if (string.IsNullOrEmpty(accessToken))
{
throw new ArgumentNullException("accessToken");
}
if (string.IsNullOrEmpty(serviceUrl))
{
throw new ArgumentNullException("serviceUrl");
}
this.accessToken = accessToken;
this.httpClient = new HttpClient
{
BaseAddress = new Uri(serviceUrl)
};
this.imageUploadClient = new HttpClient();
this.DefaultHeaders = new Dictionary<string, string>();
}
/// <summary>
/// Gets or Sets the default headers.
/// </summary>
public Dictionary<string, string> DefaultHeaders { get; set; }
/// <summary>
/// Performs application-defined tasks associated with freeing, releasing, or resetting
/// unmanaged resources.
/// </summary>
public void Dispose()
{
if (this.httpClient != null)
{
this.httpClient.Dispose();
this.httpClient = null;
GC.SuppressFinalize(this);
}
}
/// <summary>
/// Gets the authorization token for the provided client id, client secret, and the scope.
/// This token is usually valid for 1 hour, so if your submission takes longer than that to complete,
/// make sure to get a new one periodically.
/// </summary>
/// <param name="tokenEndpoint">Token endpoint to which the request is to be made. Specific to your
/// Azure Active Directory app. Example: https://login.microsoftonline.com/d454d300-128e-2d81-334a-27d9b2baf002/oauth2/v2.0/token </param>
/// <param name="clientId">Client Id of your Azure Active Directory app. Example" 00001111-aaaa-2222-bbbb-3333cccc4444</param>
/// <param name="clientSecret">Client secret of your Azure Active Directory app</param>
/// <param name="scope">Scope. If not provided, default one is used for the production API endpoint.</param>
/// <returns>Autorization token. Prepend it with "Bearer: " and pass it in the request header as the
/// value for "Authorization: " header.</returns>
public static async Task<string> GetClientCredentialAccessToken(
string tokenEndpoint,
string clientId,
string clientSecret,
string scope = null)
{
if (scope == null)
{
scope = "https://api.store.microsoft.com/.default";
}
dynamic result;
using (HttpClient client = new HttpClient())
{
string tokenUrl = tokenEndpoint;
using (
HttpRequestMessage request = new HttpRequestMessage(
HttpMethod.Post,
tokenUrl))
{
string strContent =
string.Format(
"grant_type=client_credentials&client_id={0}&client_secret={1}&scope={2}",
clientId,
clientSecret,
scope);
request.Content = new StringContent(strContent, Encoding.UTF8,
"application/x-www-form-urlencoded");
using (HttpResponseMessage response = await client.SendAsync(request))
{
string responseContent = await response.Content.ReadAsStringAsync();
result = JsonConvert.DeserializeObject(responseContent);
}
}
}
return result.access_token;
}
/// <summary>
/// Invokes the specified HTTP method.
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="httpMethod">The HTTP method.</param>
/// <param name="relativeUrl">The relative URL.</param>
/// <param name="requestContent">Content of the request.</param>
/// <returns>instance of the type T</returns>
/// <exception cref="ServiceException"></exception>
public async Task<T> Invoke<T>(HttpMethod httpMethod,
string relativeUrl,
object requestContent)
{
using (var request = new HttpRequestMessage(httpMethod, relativeUrl))
{
this.SetRequest(request, requestContent);
using (HttpResponseMessage response = await this.httpClient.SendAsync(request))
{
T result;
if (this.TryHandleResponse(response, out result))
{
return result;
}
if (response.IsSuccessStatusCode)
{
var resource = JsonConvert.DeserializeObject<T>(await response.Content.ReadAsStringAsync());
return resource;
}
throw new Exception(await response.Content.ReadAsStringAsync());
}
}
}
/// <summary>
/// Uploads a given Image Asset file to Asset Storage
/// </summary>
/// <param name="assetUploadUrl">Asset Storage Url</param>
/// <param name="fileStream">The Stream instance of file to be uploaded</param>
/// <returns></returns>
/// <exception cref="Exception"></exception>
public async Task UploadAsset(string assetUploadUrl, Stream fileStream)
{
using (var request = new HttpRequestMessage(HttpMethod.Put, assetUploadUrl))
{
request.Headers.Add("x-ms-blob-type", "BlockBlob");
request.Content = new StreamContent(fileStream);
request.Content.Headers.ContentType = new MediaTypeHeaderValue(PngContentType);
using (HttpResponseMessage response = await this.imageUploadClient.SendAsync(request))
{
if (response.IsSuccessStatusCode)
{
return;
}
throw new Exception(await response.Content.ReadAsStringAsync());
}
}
}
/// <summary>
/// Sets the request.
/// </summary>
/// <param name="request">The request.</param>
/// <param name="requestContent">Content of the request.</param>
protected virtual void SetRequest(HttpRequestMessage request, object requestContent)
{
request.Headers.Authorization = new AuthenticationHeaderValue("Bearer", this.accessToken);
foreach (var header in this.DefaultHeaders)
{
request.Headers.Add(header.Key, header.Value);
}
if (requestContent != null)
{
request.Content = new StringContent(JsonConvert.SerializeObject(requestContent),
Encoding.UTF8,
JsonContentType);
}
}
/// <summary>
/// Tries the handle response.
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="response">The response.</param>
/// <param name="result">The result.</param>
/// <returns>true if the response was handled</returns>
protected virtual bool TryHandleResponse<T>(HttpResponseMessage response, out T result)
{
result = default(T);
return false;
}
}
}
Ejemplo de Node.js: API de envío de Microsoft Store para aplicaciones MSI o EXE
En este artículo se proporcionan ejemplos de código de Node.js que muestran cómo usar la API de envío de Microsoft Store para aplicaciones MSI o EXE. Puede revisar cada ejemplo para obtener más información sobre la tarea que muestra o puede compilar todos los ejemplos de código de este artículo en una aplicación de consola.
Requisitos previos Estos ejemplos utilizan la biblioteca siguiente:
- node-fetch v2 [npm install node-fetch@2]
Crear un envío de aplicación con node.js
El siguiente ejemplo llama a los otros métodos de ejemplo de este artículo para mostrar diferentes maneras de usar la API de envío de Microsoft Store. Para adaptar este programa para su propio uso:
- Asigne la propiedad SellerId al identificador de vendedor de la cuenta del Centro de partners.
- Asigne la propiedad ApplicationId al identificador de la aplicación que desea administrar.
- Asigne las propiedades ClientId y ClientSecret al identificador de cliente y la clave de la aplicación, y reemplace la cadena tenantid en la dirección URL de TokenEndpoint por el identificador de inquilino de la aplicación. Para obtener más información, consulte Asociación de una aplicación de Azure AD a la cuenta del Centro de partners
En el siguiente ejemplo se implementa una clase que utiliza varios métodos en la API de envío de Microsoft Store para actualizar un envío de aplicación.
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();
Asistente ClientConfiguration
La aplicación de ejemplo utiliza la clase auxiliar ClientConfiguration para pasar datos de Azure Active Directory y datos de aplicación a cada uno de los métodos de ejemplo que utilizan la API de envío de 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;
Asistente IngestionClient mediante node.js
La clase IngestionClient proporciona métodos auxiliares que otros métodos de la aplicación de ejemplo utilizan para realizar las tareas siguientes:
- Obtener un token de acceso de Azure AD para utilizarlo para llamar a los métodos en la API de envío de Microsoft Store. Después de obtener un token, tiene 60 minutos para utilizar este token en llamadas a la API de envío de Microsoft Store antes de que el token expire. Después de que el token expire, puede generar uno nuevo.
- Procesar las solicitudes HTTP para la API de envío de 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;
Ayuda adicional
Si tiene preguntas sobre la API de envío de Microsoft Store o necesita ayuda para administrar los envíos con esta API, utilice los siguientes recursos:
- Formule preguntas en nuestros foros.
- Visite nuestra página de soporte técnico y solicite una de las opciones de soporte técnico asistido para el Centro de partners. Si se le pide que elija un tipo de problema y una categoría, elija Envío y certificación de la aplicación y Envío de una aplicación, respectivamente.