Nota
El acceso a esta página requiere autorización. Puede intentar iniciar sesión o cambiar directorios.
El acceso a esta página requiere autorización. Puede intentar cambiar los directorios.
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 usa microsoft Entra ID 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 de la API de envío de Microsoft Store, obtén un token de acceso de Microsoft Entra ID. 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 presentación de Microsoft Store para una aplicación MSI o EXE, asegúrate de haber cumplido los siguientes requisitos previos.
- Usted (o su organización) debe tener un directorio de id. de Microsoft Entra y debe tener permiso de administrador global para el directorio. Si ya usa Microsoft 365 u otros servicios empresariales de Microsoft, ya tiene el directorio Microsoft Entra ID. De lo contrario, puede crear un nuevo identificador de Microsoft Entra en el Centro de partners sin ningún cargo adicional.
- Debe asociar una aplicación de Microsoft Entra ID a su cuenta de Partner Center y obtener el identificador del inquilino, el identificador de cliente y la clave. Necesitas estos valores para obtener un token de acceso de Microsoft Entra ID, que utilizarás 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 tu aplicación aún no existe en Partner Center, debes crear tu aplicación reservando su nombre en Partner Center. 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 debes crear un envío para la aplicación en Partner Center, incluida la respuesta al cuestionario de clasificación 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 Microsoft Entra ID con su cuenta del Centro de partners
Antes de poder usar la API de envío de Microsoft Store para una aplicación MSI o EXE, debes asociar una aplicación de Microsoft Entra ID a tu cuenta de Partner Center, obtener el id. del inquilino y el id. de cliente de la aplicación, y generar una clave. La aplicación Microsoft Entra ID representa la aplicación o servicio desde la que quieres llamar a la API de envío de Microsoft Store. Necesitas el ID de inquilino, el ID de cliente y la clave para obtener un token de acceso de Microsoft Entra ID que pasarás a la API.
Nota:
Solo tiene que realizar esta tarea una vez. Después de tener el identificador de inquilino, el identificador de cliente y la clave, puede reutilizarlos cada vez que necesite crear un nuevo token de acceso de Id. de Microsoft Entra.
- En Partner Center, asocie la cuenta de Partner Center de su organización al directorio de Microsoft Entra ID de su organización.
- A continuación, en la página Usuarios de la sección Configuración de la cuenta de Partner Center, agregue la aplicación de Microsoft Entra ID que representa la aplicación o el servicio que usará para acceder a las presentaciones de su cuenta de Partner Center. Asegúrese de asignar a esta aplicación el rol Administrador. Si la aplicación todavía no existe en su directorio de Microsoft Entra ID, puede crear una nueva aplicación de Microsoft Entra ID en Partner Center.
- Vuelva a la página Usuarios, haga clic en el nombre de la aplicación Microsoft Entra ID para ir a la configuración de la aplicación y copie los valores id. de inquilino e Id. 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 el directorio de Microsoft Entra ID.
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 Microsoft Entra ID
Antes de llamar a cualquiera de los métodos de la API de envío a Microsoft Store para aplicaciones MSI o EXE, debes obtener primero un token de acceso de Microsoft Entra ID que deberás pasar al encabezado Authorization 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 Service to Service Calls Using Client Credentials para enviar una solicitud 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 POST y los parámetros client_id y client_secret, especifique el identificador del arrendatario, el identificador de cliente y la clave de su aplicación que recuperó de Partner Center 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 dispongas de un token de acceso de Microsoft Entra ID, podrás llamar a los métodos de la API de envío a 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 invocan 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
Obtiene los metadatos de cada módulo (listados, propiedades o disponibilidad) de la presentación actual en borrador.
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 |
|---|---|
| ID de producto | El ID de Partner Center del producto |
| nombreDelMódulo | Módulo del Centro de partners: descripciones, propiedades o disponibilidad |
Parámetros de consulta
| Parámetro | Descripción |
|---|---|
| Idiomas |
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 ID de aplicación de Microsoft Entra ID registrado en la cuenta de Centro de socios |
X-Seller-Account-Id |
ID de vendedor de la cuenta de Partner Center |
Encabezados de respuesta
| Encabezado | Valor |
|---|---|
X-Correlation-ID |
El identificador único de tipo GUID para cada solicitud. Se puede compartir con el equipo de soporte técnico para analizar cualquier problema. |
Retry-After |
El tiempo en segundos que el cliente debe esperar antes de volver a llamar a las API debido a la limitación de tasa. |
Parámetros de respuesta
| Nombre | Tipo | Descripción |
|---|---|---|
| soporte de accesibilidad | Booleano | |
| términos adicionales de la licencia | Cadena | |
| disponibilidad | Objeto | Datos del módulo de disponibilidad |
| categoría | Cadena | Consulte la lista de categorías más adelante |
| notas de certificación | Cadena | |
| código | Cadena | El código de error del mensaje. |
| información de contacto | Cadena | |
| derechos de autor | Cadena | |
| dependsOnDriversOrNT | Booleano | |
| descripción | Cadena | |
| developedBy | Cadena | |
| detectabilidad | Cadena | [DISCOVERABLE, DEEPLINK_ONLY] |
| enableInFutureMarkets | Booleano | |
| Errores | Matriz de objetos | Lista de mensajes de error o advertencia, si los hay |
| freeTrial | Cadena | [NO_FREE_TRIAL, FREE_TRIAL] |
| hardwareItemType | Cadena | |
| ¿Se requiere política de privacidad? | Booleano | |
| isRecommended | Booleano | |
| isRequired | Booleano | |
| isSuccess | Booleano | |
| isSystemFeatureRequired | Matriz de objetos | |
| lenguaje | Cadena | Consulte la lista de idiomas más adelante |
| Listados | Matriz de objetos | Datos del módulo de descripciones para cada idioma |
| mercados | Matriz de cadenas | Consulte la lista de mercados más adelante |
| Mensaje | Cadena | Descripción del error |
| minimumHardware | Cadena | |
| requisito mínimo | Cadena | |
| compatibilidad con lápiz y tinta | Booleano | |
| Precios | Cadena | [FREE, FREEMIUM, SUBSCRIPTION, PAID] |
| privacyPolicyUrl | Cadena | |
| productDeclarations | Objeto | |
| características del producto | Matriz de cadenas | |
| Propiedades | Objeto | Datos del módulo de propiedades |
| recommendedHardware | Cadena | |
| requisito recomendado | Cadena | |
| responseData | Objeto | Contiene la carga de respuesta real para la solicitud |
| requisitos | Matriz de objetos | |
| términos de búsqueda | Matriz de cadenas | |
| descripción breve | Cadena | |
| subcategoría | 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 | |
| Novedades | Cadena |
API Update Current Draft Submission Metadata
Actualiza los metadatos en cada módulo bajo el borrador de envío. La API verifica
- 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 de la solicitud se valida de acuerdo con los requisitos de la Tienda.
- 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 del parche 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 del módulo Patch, solo es necesario incluir en la solicitud los campos que se vayan a actualizar. 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 |
|---|---|
| ID de producto | ID de Partner Center del producto |
Encabezados obligatorios
| Encabezado | Valor |
|---|---|
Authorization: Bearer <Token> |
El ID de aplicación de Microsoft Entra ID registrado en la cuenta de Centro de socios |
X-Seller-Account-Id |
ID de vendedor de la cuenta de Partner Center |
Parámetros de la solicitud
| Nombre | Tipo | Descripción |
|---|---|---|
| disponibilidad | Objeto | Objeto para contener los metadatos del módulo de disponibilidad |
| mercados | Matriz de cadenas | Obligatorio Consulte la lista de mercados más adelante |
| detectabilidad | Cadena | Obligatorio [DISCOVERABLE, DEEPLINK_ONLY] |
| enableInFutureMarkets | Booleano | Obligatorio |
| Precios | Cadena | Obligatorio [FREE, FREEMIUM, SUBSCRIPTION, PAID] |
| freeTrial | Cadena | Obligatorio si el precio es DE PAGO o SUSCRIPCIÓN [NO_FREE_TRIAL, FREE_TRIAL] |
| Propiedades | Objeto | Objeto para contener los metadatos del módulo de propiedades |
| ¿Se requiere política de privacidad? | 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 |
| notas de certificación | Cadena | Recomendado Límite de caracteres = 2000 |
| categoría | Cadena | Obligatorio Consulte la lista de categorías más adelante |
| subcategoría | Cadena | Obligatorio Consulte la lista de subcategorías más adelante |
| productDeclarations | Objeto | Obligatorio |
| isSystemFeatureRequired | Matriz de objetos | [Táctil, Teclado, Ratón, Cámara, NFC_HCE, NFC_Proximity, Bluetooth_LE, Telefonía, Micrófono] |
| isRequired | Booleano | Obligatorio |
| isRecommended | Booleano | Obligatorio |
| hardwareItemType | Cadena | Obligatorio |
| systemRequirementDetails | Matriz de objetos | [Procesador, gráficos, memoria, DirectX, Video_Memory] |
| requisito mínimo | 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] |
| requisito recomendado | 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 |
| soporte de accesibilidad | Booleano | Obligatorio |
| compatibilidad con lápiz y tinta | Booleano | Obligatorio |
| Listados | Objeto | Objeto para los datos del módulo de descripciones para un único idioma |
| lenguaje | Cadena | Obligatorio Consulte la lista de idiomas más adelante |
| descripción | Cadena | Obligatorio Límite de caracteres = 10000 |
| Novedades | Cadena | Límite de caracteres = 1500 |
| características del producto | Matriz de cadena | 200 caracteres por característica; hasta 20 características |
| descripción breve | Cadena | Límite de caracteres = 1000 |
| términos de búsqueda | 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 |
| términos adicionales de la licencia | Cadena | Obligatorio Límite de caracteres = 10000 |
| derechos de autor | 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 |
| información de contacto | Cadena | Límite de caracteres = 200 |
| listingsToAdd | Matriz de cadenas | Consulte la lista de idiomas más adelante |
| listadosParaEliminar | Matriz de cadenas | Consulte la lista de idiomas más adelante |
Mercados
Ver tabla
| Mercado | Abreviatura | |--------|------------- -| | Afganistán | AF | | Albania | AL | | Argelia | DZ | | Samoa Americana | AS | | Andorra | AD | | Angola | AO | | Anguila | AI | | Antártida | AQ | | Antigua y Barbuda | AG | | Argentina | AR | | Armenia | AM | | Aruba | AW | | Australia | AU | | Austria | AT | | Azerbaiyán | AZ | | Bahamas | BS | | Baréin | BH | | Bangladés | BD | | Barbados | BB | | República de Belarús | 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 | | Brunei | 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 (Keeling) | 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 | | República de Côte d'Ivore | 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 | | Fiyi | FJ | | Finlandia | FI | | Francia | FR | | Guayana Francesa | GF | | Polinesia Francesa | PF | | Territorios Franceses del Sur y Antárticos | 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 -Bissau | GW | | Guyana | GY | | Haití | HT | | Isla Heard y las Islas McDonald | HM | | Ciudad del Vaticano | VA | | Honduras | HN | | RAE de Hong Kong | HK | | Hungría | HU | | Islandia | IS | | India | IN | | Indonesia | ID | | Irak | 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 | LA | | 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 | | Malí | 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 | NA | | 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 | | Palau | PW | | Autoridad Palestina | PS | | Panamá | PA | | Papúa Nueva Guinea | PG | | Paraguay | PY | | Perú | PE | | Filipinas | PH | | Islas Pitcairn | PN | | Polonia | PL | | Portugal | PT | | Catar | 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 (parte 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 (parte neerlandesa) | SX | | Eslovaquia | SK | | Eslovenia | SI | | Islas Salomón | SB | | Somalia | SO | | Sudáfrica | ZA | | Georgia del Sur y las 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 | | República Democrática de 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 | | Islas Menores Alejadas de EE. UU. | UM | | 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
Ver tabla
| Categoría | Subcategorías | |-----------------------|---------------| | BooksAndReference | EReader, Fiction, Nonfiction, Reference | | Business | 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 | | Entertainment | (None) | | FoodAndDining | (None) | | GovernmentAndPolitics | (None) | | HealthAndFitness | (None) | | KidsAndFamily | KidsAndFamilyBooksAndReference, KidsAndFamilyEntertainment, HobbiesAndToys, SportsAndActivities, KidsAndFamilyTravel | | Lifestyle | Automotive, DYI, HomeAndGarden, Relationships, SpecialInterest, StyleAndFashion | | Medical | (None) | | MultimediaDesign | IllustrationAndGraphicDesign, MusicProduction, PhotoAndVideoProduction | | Music | (None) | | NavigationAndMaps | (None) | | NewsAndWeather | News, Weather | | PersonalFinance | BankingAndInvestments, BudgetingAndTaxes | | Personalization | RingtonesAndSounds, themes, WallpaperAndLockScreens | | PhotoAndVideo | (None) | | Productivity | (None) | | Security | PCProtection, PersonalSecurity | | Shopping | (None) | | Social | (None) | | Sports | (None) | | Travel | CityGuides, Hotels | | UtilitiesAndTools | BackupAndManage, FileManager |Idiomas
Ver tabla
| 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 | | euskera (euskera) | 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 | | Cherokee | 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 | | Inglés | en, en-au, en-ca, en-gb, en-ie, en-in, en-nz, en-sg, en-us, en-za, en-bz, en-hk, en-id, en-jm, en-kz, en-mt, en-my, en-ph, en-pk, en-tt, en-vn, en-zw | | Estonio | et, et-ee | | Filipino | fil, fil-latn, fil-ph | | Finlandés | fi, fi-fi | | Francés | fr, fr-be, fr-ca, fr-ch, fr-fr, fr-lu, fr-cd, fr-ci, fr-cm, fr-ht, fr-ma, fr-mc, fr-ml, fr-re, frc-latn, frp-latn | | 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 | | Igb - ig-latn, ig-ng | | Indonesio | id, id-id | | Inuktitut (latín) | 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 | | kannada | kn, kn-in | | kazajo | kk, kk-kz | | Jemer | km, km-kh | | K'iche' | quc-latn, qut-gt, qut-latn | | Kinyarwanda | rw, rw-rw | | KiSwahili | sw, sw-ke | | Konkani | kok, kok-in | | Coreano | ko, ko-kr | | 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 | | Maorí | mi, mi-latn, mi-nz | | Marathi | 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 | | Sesotho sa Leboa | nso, nso-za | | Setswana | 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 | | Tártaro | tt-arab, tt-cyrl, tt-latn, tt-ru | | Telugu | te, te-in | | Tailandés | th, th-th | | Tigrino | ti, ti-et | | Turco | tr, tr-tr | | Turkmeno | 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 (latín) | 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 |
El identificador único de tipo GUID para cada solicitud. Se puede compartir con el equipo de soporte técnico para analizar cualquier problema. |
Retry-After |
El tiempo en segundos que el cliente debe esperar antes de volver a llamar a las API debido a la limitación de velocidad |
Parámetros de respuesta
| Nombre | Tipo | Descripción |
|---|---|---|
| isSuccess | Booleano | |
| Errores | Matriz de objetos | Lista de mensajes de error o advertencia, si los hay |
| código | Cadena | El código de error del mensaje. |
| Mensaje | Cadena | Descripción del error |
| Destino | Cadena | Entidad desde la que se originó el error |
| responseData | Objeto | Contiene la carga de respuesta real para la solicitud |
| URL de sondeo | 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 para obtener los paquetes de borrador actuales
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 [paquete único]: /submission/v1/product/{productId}/packages/{packageId}
Método: GET
Parámetros de la ruta de acceso
| Nombre | Descripción |
|---|---|
| ID de producto | ID de Partner Center del producto |
| packageId | El ID único del paquete que se va a obtener |
Encabezados obligatorios
| Encabezado | Valor |
|---|---|
Authorization: Bearer <Token> |
Utilizando el ID de aplicación de Microsoft Entra ID registrado en la cuenta de Centro de socios |
X-Seller-Account-Id |
ID de vendedor de la cuenta de Partner Center |
Encabezados de respuesta
| Encabezado | Valor |
|---|---|
X-Correlation-ID |
El identificador único 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 | Tipo | Descripción |
|---|---|---|
| isSuccess | Booleano | |
| Errores | Matriz de objetos | Lista de mensajes de error o advertencia, si los hay |
| código | Cadena | El código de error del mensaje. |
| Mensaje | Cadena | Descripción del error |
| Destino | Cadena | Entidad desde la que se originó el error |
| responseData | Objeto | |
| Paquetes | Matriz de objetos | Objeto que contiene los datos del módulo de paquetes |
| packageId | Cadena | |
| URL del paquete | Cadena | |
| Idiomas | 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 |
| parámetros del instalador | Cadena | |
| genericDocUrl | Cadena | |
| errorDetails | Matriz de objetos | |
| errorScenario | Cadena | |
| errorScenarioDetails | Matriz de objetos | |
| errorValue | Cadena | |
| errorUrl | Cadena | |
| tipo de paquete | 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 para actualizar los paquetes de borrador actuales
Actualiza los detalles de los paquetes en el borrador del envío actual.
Ruta [Actualización completa del módulo]: /submission/v1/product/{productId}/packages
Método: PUT
Ruta [Actualización de parche de un solo paquete]: /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 parcial de un único paquete, solo deben incluirse en la solicitud los campos que se vayan a actualizar para un paquete concreto. 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 |
|---|---|
| ID de producto | ID de Partner Center del producto |
| packageId | El identificador único del paquete |
Encabezados obligatorios
| Encabezado | Valor |
|---|---|
Authorization: Bearer <Token> |
Utilizando el ID de aplicación de Microsoft Entra ID registrado en la cuenta de Centro de socios |
X-Seller-Account-Id |
ID de vendedor de la cuenta de Partner Center |
Parámetros de la solicitud
| Nombre | Tipo | Descripción |
|---|---|---|
| Paquetes | Matriz de objetos | Objeto que contiene los datos del módulo de paquetes [solo es necesario para la actualización completa del módulo] |
| URL del paquete | Cadena | Obligatorio |
| Idiomas | 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 |
| parámetros del instalador | Cadena | Obligatorio si isSilentInstall es falso |
| 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. [instalaciónCanceladaPorElUsuario, aplicaciónYaExiste, instalaciónYaEnProgreso, espacioEnDiscoLleno, seRequiereReinicio, fallaDeRed, paqueteRechazadoDuranteLaInstalación, instalaciónExitosa, varios] |
| 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 |
| tipo de paquete | 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 parche de un solo paquete]
{
"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 |
El identificador único 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 | Tipo | Descripción |
|---|---|---|
| isSuccess | Booleano | |
| Errores | Matriz de objetos | [Lista de mensajes de error o advertencia, si los hay] |
| código | Cadena | El código de error del mensaje |
| Mensaje | Cadena | Descripción del error |
| Destino | Cadena | Entidad desde la que se originó el error |
| responseData | Objeto | |
| URL de sondeo | Cadena | URL de consulta para obtener el estado de la presentación en caso de que ya haya alguna presentación en curso |
| ongoingSubmissionId | Cadena | [ID 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 de confirmación de paquetes
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: /submission/v1/product/{productId}/packages/commit
Método: POST
Parámetros de la ruta de acceso
| Nombre | Descripción |
|---|---|
| ID de producto | ID de Partner Center del producto |
Encabezados obligatorios
| Encabezado | Valor |
|---|---|
Authorization: Bearer <Token> |
Uso del identificador de aplicación de Microsoft Entra ID registrado con la cuenta de Partner Center |
X-Seller-Account-Id |
ID de vendedor de la cuenta de Partner Center |
Encabezados de respuesta
| Encabezado | Valor |
|---|---|
X-Correlation-ID |
El identificador único 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 | Tipo | Descripción |
|---|---|---|
| isSuccess | Booleano | |
| Errores | Matriz de objetos | [Lista de mensajes de error o advertencia, si los hay] |
| código | Cadena | El código de error del mensaje. |
| Mensaje | Cadena | Descripción del error |
| Destino | Cadena | Entidad desde la que se originó el error |
| responseData | Objeto | |
| URL de sondeo | Cadena | URL de consulta para obtener el estado de la carga del paquete o el estado de la presentación en caso de que ya haya una presentación en curso |
| ongoingSubmissionId | Cadena | [ID 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 |
|---|---|
| ID de producto | ID de Partner Center del producto |
Parámetros de consulta
| Nombre | Descripción |
|---|---|
| Idiomas | [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> |
Uso del identificador de aplicación de Microsoft Entra ID registrado con la cuenta de Partner Center |
X-Seller-Account-Id |
ID de vendedor de la cuenta de Partner Center |
Encabezados de respuesta
| Encabezado | Valor |
|---|---|
X-Correlation-ID |
El identificador único 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 | Tipo | Descripción |
|---|---|---|
| isSuccess | Booleano | |
| Errores | Matriz de objetos | Lista de mensajes de error o advertencia, si los hay |
| código | Cadena | El código de error del mensaje. |
| Mensaje | Cadena | Descripción del error |
| Destino | Cadena | Entidad desde la que se originó el error |
| responseData | Objeto | |
| listado de activos | Matriz de objetos | Mostrando los detalles del recurso para cada idioma |
| lenguaje | Cadena | |
| storeLogos | Matriz de objetos | |
| capturas de pantalla | Matriz de objetos | |
| id | Cadena | |
| assetUrl | Cadena | Debe ser una dirección URL válida |
| tamaño de imagen | Objeto | |
| width | Entero | |
| altura | 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 para crear recursos de anuncio
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 eliminarán los recursos cargados previamente.
Ruta: /submission/v1/product/{productId}/listings/assets/create
Método: POST
Parámetros de la ruta de acceso
| Nombre | Descripción |
|---|---|
| ID de producto | ID de Partner Center del producto |
Encabezados obligatorios
| Encabezado | Descripción |
|---|---|
Authorization: Bearer <Token> |
Uso del identificador de aplicación de Microsoft Entra ID registrado con la cuenta de Partner Center |
X-Seller-Account-Id |
ID de vendedor de la cuenta de Partner Center |
Parámetros de la solicitud
| Nombre | Tipo | Descripción |
|---|---|---|
| lenguaje | Cadena | Obligatorio |
| createAssetRequest | Objeto | Obligatorio |
| Captura de pantalla | 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 |
El identificador único 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 | Tipo | Descripción |
|---|---|---|
| isSuccess | Booleano | |
| Errores | Matriz de objetos | Lista de mensajes de error o advertencia, si los hay |
| código | Cadena | El código de error del mensaje. |
| Mensaje | Cadena | Descripción del error |
| Destino | Cadena | Entidad desde la que se originó el error |
| responseData | Objeto | |
| listado de activos | Objeto | Objeto que contiene información de StoreLogos y Screenshots que se cargarán |
| lenguaje | Cadena | |
| storeLogos | Matriz de objetos | |
| capturas de pantalla | 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 | URL secundaria para subir el recurso del anuncio 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 | Objeto | 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 |
|---|---|
| ID de producto | ID de Partner Center del producto |
Encabezados obligatorios
| Encabezado | Descripción |
|---|---|
Authorization: Bearer <Token> |
Uso del identificador de aplicación de Microsoft Entra ID registrado con la cuenta de Partner Center |
X-Seller-Account-Id |
ID de vendedor de la cuenta de Partner Center |
Parámetros de la solicitud
| Nombre | Tipo | Descripción |
|---|---|---|
| listingAssets | Objeto | |
| lenguaje | Cadena | |
| storeLogos | Matriz de objetos | |
| capturas de pantalla | 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 |
El identificador único 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 | Tipo | Descripción |
|---|---|---|
| isSuccess | Booleano | |
| Errores | Matriz de objetos | Lista de mensajes de error o advertencia, si los hay |
| código | Cadena | El código de error del mensaje. |
| Mensaje | Cadena | Descripción del error |
| Destino | Cadena | Entidad desde la que se originó el error |
| responseData | Objeto | |
| URL de sondeo | 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 de sondeo del estado del módulo
Se puede crear una API para comprobar la preparación del módulo antes del 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 |
|---|---|
| ID de producto | ID de Partner Center del producto |
Encabezados obligatorios
| Encabezado | Descripción |
|---|---|
Authorization: Bearer <Token> |
Uso del identificador de aplicación de Microsoft Entra ID registrado con la cuenta de Partner Center |
X-Seller-Account-Id |
ID de vendedor de la cuenta de Partner Center |
Encabezados de respuesta
| Encabezado | Descripción |
|---|---|
X-Correlation-ID |
El identificador único 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 | Tipo | Descripción |
|---|---|---|
| isSuccess | Booleano | |
| Errores | Matriz de objetos | Lista de mensajes de error o advertencia, si los hay |
| código | Cadena | El código de error del mensaje. |
| Mensaje | Cadena | Descripción del error |
| Destino | Cadena | Entidad desde la que se originó el error |
| responseData | Objeto | |
| estáListo | 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": ""
}
}
Crear API de envío
Crea una presentación a partir del borrador actual para una 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 listos para crear la presentación.
- Cada campo del envío se valida según los requisitos de Store
Ruta: /submission/v1/product/{productId}/submit
Método: POST
Parámetros de la ruta de acceso
| Nombre | Descripción |
|---|---|
| ID de producto | El ID de Partner Center del producto |
Encabezados obligatorios
| Encabezado | Descripción |
|---|---|
Authorization: Bearer <Token> |
Uso del identificador de aplicación de Microsoft Entra ID registrado en la cuenta de Partner Center |
X-Seller-Account-Id |
Identificador de vendedor de la cuenta de Partner Center |
Encabezados de respuesta
| Encabezado | Descripción |
|---|---|
X-Correlation-ID |
El identificador único de tipo GUID para cada solicitud. Se puede compartir con el equipo de soporte técnico para analizar cualquier problema. |
Retry-After |
El tiempo en segundos que el cliente debe esperar antes de volver a llamar a las API debido a la limitación de tasa. |
Parámetros de respuesta
| Nombre | Tipo | Descripción |
|---|---|---|
| isSuccess | Booleano | |
| Errores | Matriz de objetos | Lista de mensajes de error o advertencia, si los hay |
| código | Cadena | El código de error del mensaje. |
| Mensaje | Cadena | Descripción del error |
| Objetivo | Cadena | Entidad desde la que se originó el error |
| responseData | Objeto | |
| URL de sondeo | 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 |
| Id de envío | 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 de consulta periódica del estado de envío
API para comprobar el estado del envío.
Ruta: /submission/v1/product/{productId}/submission/{submissionId}/status
Método: GET
Parámetros de la ruta de acceso
| Nombre | Descripción |
|---|---|
| ID de producto | El ID de Partner Center del producto |
Encabezados obligatorios
| Encabezado | Descripción |
|---|---|
Authorization: Bearer <Token> |
Uso del identificador de aplicación de Microsoft Entra ID registrado con la cuenta de Partner Center |
X-Seller-Account-Id |
ID de vendedor de la cuenta de Partner Center |
Encabezados de respuesta
| Encabezado | Descripción |
|---|---|
X-Correlation-ID |
El identificador único 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 | Tipo | Descripción |
|---|---|---|
| isSuccess | Booleano | |
| Errores | Matriz de objetos | Lista de mensajes de error o advertencia, si los hay |
| código | Cadena | El código de error del mensaje. |
| Mensaje | Cadena | Descripción del error |
| Destino | Cadena | Entidad desde la que se originó el error |
| responseData | Objeto | |
| 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 Cómo asociar una aplicación de Microsoft Entra ID a su cuenta de Partner Center.
using System;
using System.Threading.Tasks;
namespace Win32SubmissionApiCSharpSample
{
public class Program
{
static async Task Main(string[] args)
{
var config = new ClientConfiguration()
{
ApplicationId = "...",
ClientId = "...",
ClientSecret = "...",
Scope = "https://api.store.microsoft.com/.default",
ServiceUrl = "https://api.store.microsoft.com",
TokenEndpoint = "...",
SellerId = 0
};
await new AppSubmissionUpdateSample(config).RunAppSubmissionUpdateSample();
}
}
}
Clase auxiliar ClientConfiguration mediante C#
La aplicación de ejemplo usa la clase auxiliar ClientConfiguration para pasar los datos del directorio de Microsoft Entra ID y los datos de la aplicación a cada uno de los métodos de ejemplo que utilizan la API de envíos de Microsoft Store.
using System;
using System.Collections.Generic;
using System.Text;
namespace Win32SubmissionApiCSharpSample
{
public class ClientConfiguration
{
/// <summary>
/// Client Id of your Microsoft Entra ID Directory app.
/// Example" 00001111-aaaa-2222-bbbb-3333cccc4444
/// </summary>
public string ClientId { get; set; }
/// <summary>
/// Client secret of your Microsoft Entra ID Directory app
/// </summary>
public string ClientSecret { get; set; }
/// <summary>
/// Service root endpoint.
/// Example: "https://api.store.microsoft.com"
/// </summary>
public string ServiceUrl { get; set; }
/// <summary>
/// Token endpoint to which the request is to be made. Specific to your Microsoft Entra ID Directory app
/// Example: https://login.microsoftonline.com/d454d300-128e-2d81-334a-27d9b2baf002/oauth2/v2.0/token
/// </summary>
public string TokenEndpoint { get; set; }
/// <summary>
/// Resource scope. If not provided (set to null), default one is used for the production API
/// endpoint ("https://api.store.microsoft.com/.default")
/// </summary>
public string Scope { get; set; }
/// <summary>
/// Partner Center Application ID.
/// Example: 3e31a9f9-84e8-4d2d-9eba-487878d02ebf
/// </summary>
public string ApplicationId { get; set; }
/// <summary>
/// The Partner Center Seller Id
/// Example: 123456892
/// </summary>
public int SellerId { get; set; }
}
}
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:
- Obtén un token de acceso de Microsoft Entra ID que se pueda utilizar para llamar a métodos de 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 Microsoft Entra ID Directory allowing the caller to invoke the API
/// on behalf of a user
/// </param>
/// <param name="serviceUrl">The service URL.</param>
public SubmissionClient(string accessToken, string serviceUrl)
{
if (string.IsNullOrEmpty(accessToken))
{
throw new ArgumentNullException("accessToken");
}
if (string.IsNullOrEmpty(serviceUrl))
{
throw new ArgumentNullException("serviceUrl");
}
this.accessToken = accessToken;
this.httpClient = new HttpClient
{
BaseAddress = new Uri(serviceUrl)
};
this.imageUploadClient = new HttpClient();
this.DefaultHeaders = new Dictionary<string, string>();
}
/// <summary>
/// Gets or Sets the default headers.
/// </summary>
public Dictionary<string, string> DefaultHeaders { get; set; }
/// <summary>
/// Performs application-defined tasks associated with freeing, releasing, or resetting
/// unmanaged resources.
/// </summary>
public void Dispose()
{
if (this.httpClient != null)
{
this.httpClient.Dispose();
this.httpClient = null;
GC.SuppressFinalize(this);
}
}
/// <summary>
/// Gets the authorization token for the provided client id, client secret, and the scope.
/// This token is usually valid for 1 hour, so if your submission takes longer than that to complete,
/// make sure to get a new one periodically.
/// </summary>
/// <param name="tokenEndpoint">Token endpoint to which the request is to be made. Specific to your
/// Microsoft Entra ID Directory app. Example: https://login.microsoftonline.com/d454d300-128e-2d81-334a-27d9b2baf002/oauth2/v2.0/token </param>
/// <param name="clientId">Client Id of your Microsoft Entra ID Directory app. Example" 00001111-aaaa-2222-bbbb-3333cccc4444</param>
/// <param name="clientSecret">Client secret of your Microsoft Entra ID Directory app</param>
/// <param name="scope">Scope. If not provided, default one is used for the production API endpoint.</param>
/// <returns>Autorization token. Prepend it with "Bearer: " and pass it in the request header as the
/// value for "Authorization: " header.</returns>
public static async Task<string> GetClientCredentialAccessToken(
string tokenEndpoint,
string clientId,
string clientSecret,
string scope = null)
{
if (scope == null)
{
scope = "https://api.store.microsoft.com/.default";
}
dynamic result;
using (HttpClient client = new HttpClient())
{
string tokenUrl = tokenEndpoint;
using (
HttpRequestMessage request = new HttpRequestMessage(
HttpMethod.Post,
tokenUrl))
{
string strContent =
string.Format(
"grant_type=client_credentials&client_id={0}&client_secret={1}&scope={2}",
clientId,
clientSecret,
scope);
request.Content = new StringContent(strContent, Encoding.UTF8,
"application/x-www-form-urlencoded");
using (HttpResponseMessage response = await client.SendAsync(request))
{
string responseContent = await response.Content.ReadAsStringAsync();
result = JsonConvert.DeserializeObject(responseContent);
}
}
}
return result.access_token;
}
/// <summary>
/// Invokes the specified HTTP method.
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="httpMethod">The HTTP method.</param>
/// <param name="relativeUrl">The relative URL.</param>
/// <param name="requestContent">Content of the request.</param>
/// <returns>instance of the type T</returns>
/// <exception cref="ServiceException"></exception>
public async Task<T> Invoke<T>(HttpMethod httpMethod,
string relativeUrl,
object requestContent)
{
using (var request = new HttpRequestMessage(httpMethod, relativeUrl))
{
this.SetRequest(request, requestContent);
using (HttpResponseMessage response = await this.httpClient.SendAsync(request))
{
T result;
if (this.TryHandleResponse(response, out result))
{
return result;
}
if (response.IsSuccessStatusCode)
{
var resource = JsonConvert.DeserializeObject<T>(await response.Content.ReadAsStringAsync());
return resource;
}
throw new Exception(await response.Content.ReadAsStringAsync());
}
}
}
/// <summary>
/// Uploads a given Image Asset file to Asset Storage
/// </summary>
/// <param name="assetUploadUrl">Asset Storage Url</param>
/// <param name="fileStream">The Stream instance of file to be uploaded</param>
/// <returns></returns>
/// <exception cref="Exception"></exception>
public async Task UploadAsset(string assetUploadUrl, Stream fileStream)
{
using (var request = new HttpRequestMessage(HttpMethod.Put, assetUploadUrl))
{
request.Headers.Add("x-ms-blob-type", "BlockBlob");
request.Content = new StreamContent(fileStream);
request.Content.Headers.ContentType = new MediaTypeHeaderValue(PngContentType);
using (HttpResponseMessage response = await this.imageUploadClient.SendAsync(request))
{
if (response.IsSuccessStatusCode)
{
return;
}
throw new Exception(await response.Content.ReadAsStringAsync());
}
}
}
/// <summary>
/// Sets the request.
/// </summary>
/// <param name="request">The request.</param>
/// <param name="requestContent">Content of the request.</param>
protected virtual void SetRequest(HttpRequestMessage request, object requestContent)
{
request.Headers.Authorization = new AuthenticationHeaderValue("Bearer", this.accessToken);
foreach (var header in this.DefaultHeaders)
{
request.Headers.Add(header.Key, header.Value);
}
if (requestContent != null)
{
request.Content = new StringContent(JsonConvert.SerializeObject(requestContent),
Encoding.UTF8,
JsonContentType);
}
}
/// <summary>
/// Tries the handle response.
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="response">The response.</param>
/// <param name="result">The result.</param>
/// <returns>true if the response was handled</returns>
protected virtual bool TryHandleResponse<T>(HttpResponseMessage response, out T result)
{
result = default(T);
return false;
}
}
}
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 Cómo asociar una aplicación de Microsoft Entra ID a su cuenta de Partner Center.
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 de ClientConfiguration
La aplicación de ejemplo usa la clase auxiliar ClientConfiguration para pasar los datos del directorio de Microsoft Entra ID y los datos de la aplicación a cada uno de los métodos de ejemplo que utilizan la API de envíos 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:
- Obtén un token de acceso de Microsoft Entra ID que se pueda utilizar para llamar a métodos de 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.
Preguntas más frecuentes
¿Qué puedo hacer a través de la API de envío de Microsoft Store?
La API de envío de Microsoft Store permite a los desarrolladores automatizar las tareas de administración de aplicaciones, entre las que se incluyen:
- Creación y envío de nuevas actualizaciones de aplicaciones.
- Carga y administración de paquetes de aplicaciones.
- Actualización de metadatos y listados de la tienda.
Puede integrar esta API en los flujos de trabajo de integración continua o de compilación, automatizando tareas rutinarias para simplificar el proceso de publicación.
Windows developer