API pengiriman Microsoft Store untuk aplikasi MSI atau EXE

Gunakan API pengiriman Microsoft Store untuk aplikasi MSI atau EXE untuk mengkueri dan membuat pengiriman secara terprogram untuk aplikasi MSI atau EXE untuk akun Pusat Mitra organisasi Anda. API ini berguna jika akun Anda mengelola banyak aplikasi, dan Anda ingin mengotomatiskan dan mengoptimalkan proses pengiriman untuk aset ini. API ini menggunakan ID Microsoft Entra untuk mengautentikasi panggilan dari aplikasi atau layanan Anda.

Langkah-langkah berikut menjelaskan proses end-to-end menggunakan API pengiriman Microsoft Store:

  1. Pastikan Anda telah menyelesaikan semua prasyarat.
  2. Sebelum Anda memanggil metode di MICROSOFT Store submission API, dapatkan token akses ID Microsoft Entra. Setelah mendapatkan token, Anda memiliki waktu 60 menit untuk menggunakan token ini dalam panggilan ke API pengiriman Microsoft Store sebelum token kedaluwarsa. Setelah token kedaluwarsa, Anda dapat menghasilkan token baru.
  3. Panggil API pengiriman Microsoft Store untuk aplikasi MSI atau EXE.

Langkah 1: Selesaikan prasyarat untuk menggunakan API pengiriman Microsoft Store

Sebelum Anda mulai menulis kode untuk memanggil API pengiriman Microsoft Store untuk aplikasi MSI atau EXE, pastikan Anda telah menyelesaikan prasyarat berikut.

  • Anda (atau organisasi Anda) harus memiliki direktori ID Microsoft Entra dan Anda harus memiliki izin Administrator global untuk direktori tersebut. Jika Anda sudah menggunakan Microsoft 365 atau layanan bisnis lainnya dari Microsoft, Anda sudah memiliki direktori ID Microsoft Entra. Jika tidak, Anda dapat membuat ID Microsoft Entra baru di Pusat Mitra tanpa biaya tambahan.
  • Anda harus mengaitkan aplikasi ID Microsoft Entra dengan akun Pusat Mitra Anda dan mendapatkan ID penyewa, ID klien, dan kunci Anda. Anda memerlukan nilai-nilai ini untuk mendapatkan token akses ID Microsoft Entra, yang akan Anda gunakan dalam panggilan ke API pengiriman Microsoft Store.
  • Siapkan aplikasi Anda untuk digunakan dengan API pengiriman Microsoft Store:
    • Jika aplikasi Anda belum ada di Pusat Mitra, Anda harus membuat aplikasi dengan mengirimkan namanya di Pusat Mitra. Anda tidak dapat menggunakan API pengiriman Microsoft Store untuk membuat aplikasi di Pusat Mitra; Anda harus bekerja di Pusat Mitra untuk membuatnya, lalu setelah itu Anda dapat menggunakan API untuk mengakses aplikasi dan membuat pengiriman secara terprogram untuk itu.
    • Sebelum dapat membuat pengiriman untuk aplikasi tertentu menggunakan API ini, Anda harus terlebih dahulu membuat satu pengiriman untuk aplikasi di Pusat Mitra, termasuk menjawab kuesioner peringkat usia. Setelah melakukan ini, Anda akan dapat membuat pengiriman baru secara terprogram untuk aplikasi ini menggunakan API.
    • Jika Anda membuat atau memperbarui pengiriman aplikasi dan Anda perlu menyertakan paket baru, siapkan detail paket.
    • Jika Anda membuat atau memperbarui pengiriman aplikasi dan Perlu menyertakan cuplikan layar atau gambar untuk daftar Toko, siapkan cuplikan layar dan gambar aplikasi.

Cara mengaitkan aplikasi ID Microsoft Entra dengan akun Pusat Mitra Anda

Sebelum dapat menggunakan API pengiriman Microsoft Store untuk aplikasi MSI atau EXE, Anda harus mengaitkan aplikasi ID Microsoft Entra dengan akun Pusat Mitra Anda, mengambil ID penyewa dan ID klien untuk aplikasi dan membuat kunci. Aplikasi ID Microsoft Entra mewakili aplikasi atau layanan tempat Anda ingin memanggil API pengiriman Microsoft Store. Anda memerlukan ID penyewa, ID klien, dan kunci untuk mendapatkan token akses ID Microsoft Entra yang Anda teruskan ke API.

Catatan

Anda hanya perlu melakukan tugas ini satu kali. Setelah Anda memiliki ID penyewa, ID klien, dan kunci, Anda dapat menggunakannya kembali kapan saja Anda perlu membuat token akses ID Microsoft Entra baru.

  1. Di Pusat Mitra, kaitkan akun Pusat Mitra organisasi Anda dengan direktori ID Microsoft Entra organisasi Anda.
  2. Selanjutnya, dari halaman Pengguna di bagian Pengaturan akun di Pusat Mitra, tambahkan aplikasi ID Microsoft Entra yang mewakili aplikasi atau layanan yang akan Anda gunakan untuk mengakses pengiriman untuk akun Pusat Mitra Anda. Pastikan Anda menetapkan aplikasi ini sebagai peranManajer. Jika aplikasi belum ada di direktori MICROSOFT Entra ID, Anda dapat membuat aplikasi ID Microsoft Entra baru di Pusat Mitra.
  3. Kembali ke halaman Pengguna, klik nama aplikasi ID Microsoft Entra Anda untuk masuk ke pengaturan aplikasi, dan salin nilai ID Penyewa dan ID Klien.
  4. Untuk menambahkan kunci baru atau Rahasia klien, lihat instruksi berikut atau lihat instruksi untuk mendaftarkan aplikasi melalui Portal Microsoft Azure:

Untuk mendaftarkan aplikasi Anda:

  1. Masuk ke portal Azure.

  2. Jika Anda memiliki akses ke beberapa penyewa, gunakan filter Direktori + langganan di menu atas untuk memilih penyewa tempat Anda ingin mendaftarkan aplikasi.

  3. Cari dan pilih Microsoft Entra ID Directory.

  4. Di bawah Kelola, pilih Pendaftaran aplikasi > Pilih aplikasi Anda.

  5. Pilih Sertifikat & rahasia > Rahasia > klien Rahasia klien baru.

  6. Tambahkan deskripsi untuk rahasia klien Anda.

  7. Pilih kedaluwarsa untuk rahasia atau tentukan masa pakai kustom.

  8. Masa pakai rahasia klien dibatasi hingga dua tahun (24 bulan) atau kurang. Anda tidak dapat menentukan masa pakai kustom lebih dari 24 bulan.

    Catatan

    Microsoft menyarankan agar Anda menetapkan nilai kedaluwarsa kurang dari 12 bulan.

  9. Pilih Tambahkan.

  10. Catat nilai rahasia untuk digunakan dalam kode aplikasi klien Anda. Nilai rahasia ini tidak pernah ditampilkan lagi setelah Anda meninggalkan halaman ini.

Langkah 2: Mendapatkan token akses ID Microsoft Entra

Sebelum Anda memanggil salah satu metode di API pengiriman Microsoft Store untuk aplikasi MSI atau EXE, Anda harus terlebih dahulu mendapatkan token akses ID Microsoft Entra yang Anda berikan ke header Otorisasi dari setiap metode di API. Setelah mendapatkan token akses, Anda memiliki waktu 60 menit untuk menggunakan token akses sebelum masa berlakunya habis. Setelah token kedaluwarsa, Anda dapat merefresh token sehingga Anda dapat terus menggunakannya dalam panggilan lebih lanjut ke API.

Untuk mendapatkan token akses, ikuti instruksi dalam Panggilan Layanan ke Layanan Menggunakan Kredensial Klien untuk mengirim HTTP POST ke https://login.microsoftonline.com/<titik akhir tenant_id>/oauth2/token. Berikut adalah contoh permintaan.

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

tenant_id Untuk nilai di POST URI dan client_id parameter dan client_secret , tentukan ID penyewa, ID klien, dan kunci untuk aplikasi yang Anda ambil dari Pusat Mitra di bagian sebelumnya. Untuk parameter cakupan, Anda harus menentukan https://api.store.microsoft.com/.default.

Setelah token akses kedaluwarsa, Anda dapat merefreshnya dengan mengikuti instruksi di sini.

Untuk contoh yang menunjukkan cara mendapatkan token akses dengan menggunakan C# atau Node.js, lihat contoh kode untuk API pengiriman Microsoft Store untuk aplikasi MSI atau EXE.

Langkah 3: Menggunakan API pengiriman Microsoft Store

Setelah Anda memiliki token akses ID Microsoft Entra, Anda dapat memanggil metode di API pengiriman Microsoft Store untuk aplikasi MSI atau EXE. API mencakup banyak metode yang dikelompokkan ke dalam skenario untuk aplikasi. Untuk membuat atau memperbarui pengiriman, Anda biasanya memanggil beberapa metode dalam urutan tertentu. Untuk informasi tentang setiap skenario dan sintaks setiap metode, lihat bagian berikut:

Catatan

Setelah mendapatkan token akses, Anda memiliki waktu 60 menit untuk memanggil metode di API pengiriman Microsoft Store untuk aplikasi MSI atau EXE sebelum token kedaluwarsa.

URL Dasar

URL dasar untuk MICROSOFT Store Submission API untuk exe atau aplikasi MSI adalah: https://api.store.microsoft.com

Kontrak API

Dapatkan API Metadata Pengiriman Draf Saat Ini

Mengambil metadata di setiap modul (daftar, properti, atau ketersediaan) di bawah pengiriman draf saat ini.

Jalur [Semua Modul]: /submission/v1/product/{productId}/metadata?languages={languages}&includelanguagelist={true/false}
Jalur [Modul Tunggal]: /submission/v1/product/{productId}/metadata/{moduleName}?languages={languages}&includelanguagelist={true/false}
Metode: GET

Parameter Jalur

Pengaturan Deskripsi
ID produk ID Pusat Mitra produk
nama modul Modul Pusat Mitra – daftar, properti, atau ketersediaan

Parameter Kueri:

Pengaturan Deskripsi
bahasa Opsional Filter bahasa daftar sebagai string yang dipisahkan koma [batas hingga 200 Bahasa].

Jika tidak ada, 200 metadata bahasa daftar pertama yang tersedia akan diambil. [ misalnya, "en-us, en-gb"].
daftarBahasaDimasukkan Boolean opsional – jika true, mengembalikan daftar bahasa daftar tambahan dan status kelengkapannya.

Header yang Diperlukan

Kepala Halaman Nilai
Authorization: Bearer <Token> ID aplikasi ID Microsoft Entra yang terdaftar di akun Pusat Mitra
X-Seller-Account-Id ID Penjual akun Pusat Mitra

Header Respons

Kepala Halaman Nilai
X-Correlation-ID ID unik jenis GUID untuk setiap permintaan. Ini dapat dibagikan dengan Tim Dukungan untuk menganalisis masalah apa pun.
Retry-After Waktu dalam detik klien harus menunggu sebelum memanggil API lagi karena pembatasan tarif.

Parameter Respons

Nama Tipe Deskripsi
dukungan aksesibilitas Boolean
Ketentuan Lisensi Tambahan string
ketersediaan Objek Data modul ketersediaan
kategori string Lihat daftar kategori di bawah ini
catatan sertifikasi string
kode string Kode kesalahan Pesan
informasi kontak string
hak cipta string
bergantungPadaDriverAtauNT Boolean
deskripsi string
dikembangkan oleh string
kemampuan penemuan string [DAPAT DITEMUKAN, DEEPLINK_ONLY]
enableInFutureMarkets Boolean
Kesalahan Array objek Daftar pesan kesalahan atau peringatan jika ada
freeTrial string [TIDAK_ADA_UJI_C
jenisItemPerangkatKeras string
Apakah Kebijakan Privasi Diperlukan Boolean
direkomendasikan Boolean
diharuskan Boolean
apakahBerhasil Boolean
apakahFiturSistemDiperlukan Array objek
bahasa string Lihat daftar bahasa di bawah ini
Daftar Array objek Mencantumkan data modul untuk setiap bahasa
pasar Array string Lihat daftar pasar di bawah ini
pesan string Deskripsi kesalahan
perangkat keras minimal string
persyaratan minimum string
penAndInkSupport Boolean
harga string [GRATIS, FREEMIUM, LANGGANAN, BERBAYAR]
urlKebijakanPrivasi string
deklarasiProduk Objek
fiturProduk Array string
properti Objek Data modul properti
perangkat keras yang direkomendasikan string
persyaratan yang direkomendasikan string
responseData Objek Berisi Payload respons aktual untuk Permintaan
persyaratan Array objek
Istilah Pencarian Array string
Deskripsi Singkat string
subkategori string Lihat daftar sub-kategori di bawah ini
InformasiKontakDukungan string
rincianPersyaratanSistem Array objek
sasaran string Entitas tempat Kesalahan berasal
situs web string
Apa yang Baru string

Memperbarui API Metadata Pengiriman Draf Saat Ini

Memperbarui metadata di setiap Modul di bawah pengiriman draf. Pemeriksaan API

  • Untuk Pengiriman Aktif. Jika Ada, Gagal dengan Pesan Kesalahan.
  • Jika semua modul dalam status siap untuk mengizinkan operasi Simpan Draf.
  • Setiap bidang dalam pengiriman divalidasi sesuai persyaratan Penyimpanan
  • Aturan validasi Detail Persyaratan Sistem:
    • Nilai yang Diizinkan dalam hardwareItemType = Memori: 300MB, 750MB, 1GB, 2GB, 4GB, 6GB, 8GB, 12GB, 16GB, 20GB
    • Nilai yang Diizinkan dalam hardwareItemType = DirectX: DX9, DX10, DX11, DX12-FEATURELEVEL11, DX12-FEATURELEVEL12
    • Nilai yang Diizinkan dalam hardwareItemType = Video_Memory: 1GB, 2GB, 4GB, 6GB

Jalur [Pembaruan Modul Lengkap]: /submission/v1/product/{productId}/metadata
Metode: PUT

Jalur [Module Patch Update]: /submission/v1/product/{productId}/metadata
Metode: PATCH

Perilaku API

Dalam kasus API Pembaruan Modul Lengkap – seluruh Data Modul perlu ada dalam Permintaan untuk pembaruan lengkap setiap bidang. Bidang apa pun yang tidak ada dalam Permintaan, nilai defaultnya digunakan untuk menimpa nilai saat ini untuk Modul tertentu tersebut.
Dalam kasus PATch Module Update API – hanya bidang yang akan diperbarui yang perlu ada dalam Permintaan. Nilai bidang dari Permintaan ini akan menimpa nilai yang ada, menjaga semua bidang lain yang tidak ada dalam Permintaan, sama seperti saat ini untuk Modul tertentu.

Parameter Jalur

Pengaturan Deskripsi
ID produk ID Pusat Mitra produk

Header yang Diperlukan

Kepala Halaman Nilai
Authorization: Bearer <Token> ID aplikasi ID Microsoft Entra yang terdaftar di akun Pusat Mitra
X-Seller-Account-Id ID Penjual akun Pusat Mitra

Parameter Permintaan

Nama Tipe Deskripsi
ketersediaan Objek Objek untuk menyimpan metadata Modul Ketersediaan
pasar Array string Diperlukan Lihat daftar pasar di bawah ini
kemampuan penemuan string Diperlukan [DAPAT DITEMUKAN, DEEPLINK_ONLY]
enableInFutureMarkets Boolean Diperlukan
harga string Diperlukan [GRATIS, FREEMIUM, LANGGANAN, BERBAYAR]
freeTrial string Diperlukan jika Harga BERBAYAR atau LANGGANAN [NO_FREE_TRIAL, FREE_TRIAL]
properti Objek Objek untuk menyimpan metadata Modul Properti
Apakah Kebijakan Privasi Diperlukan Boolean Diperlukan
urlKebijakanPrivasi string Diperlukan jika isPrivacyPolicyRequired = true Harus berupa URL yang valid
situs web string Harus berupa URL yang valid
InformasiKontakDukungan string Harus berupa URL atau alamat Email yang valid
catatan sertifikasi string Batas Karakter yang Direkomendasikan = 2000
kategori string Diperlukan Lihat daftar kategori di bawah ini
subkategori string Diperlukan Lihat daftar sub-kategori di bawah ini
deklarasiProduk Objek Diperlukan
apakahFiturSistemDiperlukan Array objek [Sentuh, Keyboard, Mouse, Kamera, NFC_HCE, NFC_Proximity, Bluetooth_LE, Telepon, Mikrofon]
diharuskan Boolean Diperlukan
direkomendasikan Boolean Diperlukan
jenisItemPerangkatKeras string Diperlukan
rincianPersyaratanSistem Array objek [Prosesor, Grafis, Memori, DirectX, Video_Memory]
persyaratan minimum string Diperlukan Untuk systemRequirementsText, MaxLength = 200

Nilai yang Diizinkan dalam hardwareItemType = Memori: [300MB, 750MB, 1GB, 2GB, 4GB, 6GB, 8GB, 12GB, 16GB, 20GB]

Nilai yang Diizinkan dalam hardwareItemType = DirectX: [DX9, DX10, DX11, DX12-FEATURELEVEL11, DX12-FEATURELEVEL12]

Nilai yang Diizinkan dalam hardwareItemType = Video_Memory: [1GB, 2GB, 4GB, 6GB]
persyaratan yang direkomendasikan string Diperlukan Untuk systemRequirementsText, MaxLength = 200

Nilai yang Diizinkan dalam hardwareItemType = Memori: [300MB, 750MB, 1GB, 2GB, 4GB, 6GB, 8GB, 12GB, 16GB, 20GB]

Nilai yang Diizinkan dalam hardwareItemType = DirectX: [DX9, DX10, DX11, DX12-FEATURELEVEL11, DX12-FEATURELEVEL12]

Nilai yang Diizinkan dalam hardwareItemType = Video_Memory: [1GB, 2GB, 4GB, 6GB]
bergantungPadaDriverAtauNT Boolean Diperlukan
dukungan aksesibilitas Boolean Diperlukan
penAndInkSupport Boolean Diperlukan
Daftar Objek Objek untuk mencantumkan data modul untuk satu bahasa
bahasa string Diperlukan Lihat daftar bahasa di bawah ini
deskripsi string Batas Karakter yang Diperlukan = 10000
Apa yang Baru string Batas karakter = 1500
fiturProduk Array String 200 karakter per fitur; Hingga 20 fitur
Deskripsi Singkat string Batas karakter = 1000
Istilah Pencarian Array String 30 karakter per istilah pencarian; Hingga 7 istilah pencarian

21 kata unik TOTAL di semua istilah pencarian
Ketentuan Lisensi Tambahan string Batas Karakter yang Diperlukan = 10000
hak cipta string Batas karakter = 200
dikembangkan oleh string Batas karakter = 255
persyaratan Array objek 200 karakter per item; TOTAL hingga 11 item antara minimum dan disarankan]
perangkat keras minimal string Batas karakter = 200
perangkat keras yang direkomendasikan string Batas karakter = 200
informasi kontak string Batas karakter = 200
daftar yang akan ditambahkan Array string Lihat daftar bahasa di bawah ini
daftarUntukDihapus Array string Lihat daftar bahasa di bawah ini

Pasar

Lihat tabel | Pasar | Singkatan | |--------|--------------| | Afghanistan | AF | | Albania | AL | | Aljazair | DZ | | Samoa Amerika | AS | | Andorra | AD | Angola | AO | | Anguilla | AI | | Antartika | AQ | | Antigua dan Barbuda | AG | | Argentina | AR | | Armenia | AM | | Aruba | AW | | Australia | AU | | Austria | AT | | Azerbaijan | AZ | | Bahama | BS | | Bahrain | BH | | Bangladesh | BD | | Barbados | BB | | Belarus | OLEH | | Belgia | BE | | Belize | BZ | | Benin | BJ | | Bermuda | BM | | Bhutan | BT | | Republik Bolivarian Venezuela | VE | | Bolivia | BO | | Bonaire | BQ | | Bosnia dan Herzegovina | BA | | Botswana | BW | | Pulau Bouvet | BV | | Brasil | BR | | Wilayah Samudera Hindia Inggris | IO | | Kepulauan Virgin Inggris | VG | | Brunei | BN | | Bulgaria | BG | | Burkina Faso | BF | | Burundi | BI | | Kamboja | KH | | Kamerun | CM | | Kanada | CA | | Cabo Verde | CV | | Kepulauan Cayman | KY | | Republik Afrika Tengah | CF | | Chad | TD | | Chili | CL | | Tiongkok | CN | | Pulau Christmas | CX | | Kepulauan Cocos (Keeling) | CC | | Kolombia | CO | | Komoto | KM | | Kongo | CG | | Kongo (DRC) | CD | | Kepulauan Cook | CK | | Kosta Rika | CR | | Kroasia | SDM | | Curaçao | CW | | Siprus | CY | | Republik Ceko | CZ | | Côte d'Ivoire | CI | | Denmark | DK | | Djibouti | DJ | | Dominika | DM | | Republik Dominika | DO | | Ekuador | EC | | Mesir | EG | | El Salvador | SV | | Guinea Ekuatorial | GQ | | Eritrea | ER | | Estonia | EE | | Ethiopia | ET | | Kepulauan Falkland | FK | | Kepulauan Faroe | FO | | Fiji | FJ | | Finlandia | FI | | Prancis | FR | | Guiana Prancis | GF | | Polinesia Prancis | PF | | Tanah Selatan dan Antartika Prancis | TF | | Gabon | GA | | Gambia | GM | | Georgia | GE | | Jerman | DE | | Ghana | GH | | Gibraltar | GI | | Yunani | GR | | Greenland | GL | | Grenada | GD | | Guadeloupe | GP | | Guam | GU | | Guatemala | GT | Guernsey | GG | | Guinea | GN | | Guinea-Bissau | GW | | Guyana | GY | | Haiti | HT | | Pulau Heard dan Kepulauan McDonald | HM | | Kota Vatikan | VA | | Honduras | HN | | Hong Kong SAR | HK | | Hongaria | HU | | Islandia | IS | | India | IN | | Indonesia | ID | | Irak | IQ | | Irlandia | IE | | Israel | IL | | Italia | IT | | Jamaika | JM | | Jepang | JP | | Jersey | JE | Yordania | JO | | Kazakhstan | KZ | | Kenya | KE | | Kiribati | KI | Korea | KR | | Kuwait | KW | | Kyrgyzstan | KG | | Laos | LA | Latvia | LV | | Lebanon | LB | | Lesotho | LS | | Liberia | LR | | Libya | LY | | Liechtenstein | LI | | Lituania | LT | | Luksemburg | LU | | Macao SAR | MO | | Makedonia Utara | MK | | Madagaskar | MG | | Malawi | MW | | Malaysia | MY | | Maladir | MV | | Mali | ML | | Malta | MT | | Isle of Man | IM | | Kepulauan Marshall | MH | | Martinique | MQ | | Mauritania | MR | | Mauritius | MU | | Mayotte | YT | | Meksiko | MX | | Mikronesia | FM | | Moldova | MD | | Monako | MC | | Mongolia | MN | | Montenegr - ME | Montserrat | MS | | Maroko | MA | | Mozambik | MZ | | Myanmar | MM | | Namibia | NA | | Nauru | NR | | Nepal | NP | | Belanda | NL | | Kaledonia Baru | NC | | Selandia Baru | NZ | | Nikaragua | NI | | Niger | NE | | Nigeria | NG | | Niue | NU | | Pulau Norfolk | NF | | Kepulauan Mariana Utara | MP | | Norwegia | TIDAK | Oman | OM | | Pakistan | PK | | Palau | PW | | Otoritas Palestina | PS | | Panama | PA | | Papua Nugini | PG | | Paraguay | PY | | Peru | PE | | Filipina | PH | | Kepulauan Pitcairn | PN | | Polandia | PL | | Portugal | PT | | Qatar | QA | | Reuni | RE | | Rumania | RO | | Rusia | RU | | Rwanda | RW | | Saint Barthélemy | BL | Saint Helena, Ascension dan Tristan da Cunha | SH | | Saint Kitts dan Nevis | KN | Saint Lucia | LC | | Saint Martin (Bagian Prancis) | MF | | Saint Pierre dan Miquelon | PM | | Saint Vincent dan Grenadines | VC | | Samoa | WS | | San Marino | SM | | Arab Saudi | SA | | Senegal | SN | | Serbia | RS | | Seychelles | SC | | Sierra Leone | SL | | Singapura | SG | | Sint Maarten (Bagian Belanda) | SX | | Slowakia | SK | | Slovenia | SI | | Kepulauan Solomon | SB | | Somalia | SO | | Afrika Selatan | ZA | | Georgia Selatan dan Kepulauan Sandwich Selatan | GS | | Spanyol | ES | | Sri Lanka | LK | | Suriname | SR | | Svalbard dan Jan Mayen | SJ | | Swaziland | SZ | | Swedia | SE | | Swiss | CH | | São Tomé dan Príncipe | ST | | Taiwan | TW | | Tajikistan | TJ | | Tanzania | TZ | | Thailand | TH | | Timor-Leste | TL | | Tog - TG | Tokelau | TK | | Tonga | KE | Trinidad dan Tobag - TT | | Tunisia | TN | | Türkiye | TR | | Turkmenistan | TM | | Kepulauan Turki dan Caicos | TC | | Tuvalu | TV | | Kepulauan Terluar Kecil A.S. | UM | | Kepulauan Virgin A.S. | VI | | Uganda | UG | | Ukraina | UA | | Uni Emirat Arab | AE | | Inggris Raya | GB | | Amerika Serikat | US | | Uruguay | UY | | Uzbekistan | UZ | | Vanuatu | VU | | Vietnam | VN | | Wallis dan Futuna | WF | | Yaman | YE | Zambia | ZM | | Zimbabwe | ZW | | Kepulauan Åland | AX |

Kategori dan Sub-kategori

Lihat tabel | Kategori | Subkataan | |-----------------------|---------------| | BooksAndReference | EReader, Fiksi, Nonfiksi, Referensi | | Bisnis | AccountingAndfinance, Collaboration, CRM, DataAndAnalytics, FileManagement, InventoryAndlogistics, LegalAndHR, ProjectManagement, RemoteDesktop, SalesAndMarketing, TimeAndExpenses | | DeveloperTools | Database, DesignTools, DevelopmentKits, Networking, ReferenceAndTraining, Server, Utilitas, WebHosting | Pendidikan | EducationBooksAndReference, EarlyLearning, InstructionalTools, Language, StudyAids | | Hiburan | (Tidak Ada) | | FoodAndDining | (Tidak Ada) | | GovernmentAndPolitics | (Tidak Ada) | | HealthAndFitness | (Tidak Ada) | | KidsAndFamily | KidsAndFamilyBooksAndReference, KidsAndFamilyEntertainment, HobbiesAndToys, SportsAndActivities, KidsAndFamilyTravel | | Gaya Hidup | Otomotif, DYI, HomeAndGarden, Hubungan, SpecialInterest, StyleAndFashion | | Medis | (Tidak Ada) | | MultimediaDesign | IlustrasiAndGraphicDesign, MusicProduction, PhotoAndVideoProduction | | Musik | (Tidak Ada) | | NavigationAndMaps | (Tidak Ada) | | NewsAndWeather | Berita, Cuaca | | PersonalFinance | BankingAndInvestments, BudgetingAndTaxes | | Personalisasi | RingtonesAndSounds, tema, WallpaperAndLockScreens | | PhotoAndVideo | (Tidak Ada) | | Produktivitas | (Tidak Ada) | | Keamanan | PCProtection, PersonalSecurity | | Belanja | (Tidak Ada) | | Sosial | (Tidak Ada) | | Olahraga | (Tidak Ada) | | Perjalanan | CityGuides, Hotel | | UtilitasAndTools | BackupAndManage, FileManager |

Bahasa

Lihat tabel | Nama bahasa | Kode bahasa yang didukung | |---------------|--------------------------| | Afrikaans | af, af-za | | Albania | sq, sq-al | | Amharik | am, am-et | | Armenia | hy, hy-am | | Assamese | as, as-in | | Azerbaijan | az-arab, az-arab-az, az-cyrl, az-cyrl-az, az-latn, az-latn-az | | Basque (Basque) | eu, eu-es | | Belarusia | be, be-by | | Bangla | bn, bn-bd, bn-in | | Bosnia | bs, bs-cyrl, bs-cyrl-ba, bs-latn, bs-latn-ba | | Bulgaria | bg, bg-bg | | Bahasa Katala | ca, ca-es, ca-es-valencia | | Cherokee | chr-cher, chr-cher-us, chr-latn | | Tionghoa (Sederhana) | zh-Hans, zh-cn, zh-hans-cn, zh-sg, zh-hans-sg | | Tionghoa (Tradisional) | 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 | | Kroasia | jam, hr-hr, hr-ba | | Ceko | cs, cs-cz | | Denmark | da, da-dk | | Dari | prs, prs-af, prs-arab | | Belanda | nl, nl-nl, nl-be | | Bahasa Inggris | 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 | | Estonia | et, et-ee | | Filipin - fil, fil-latn, fil-ph | | Bahasa Finlandia | fi, fi-fi | | Bahasa Prancis | 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 | | Galisia | gl, gl-es | | Georgian | ka, ka-ge | | Bahasa Jerman | de, de-at, de-ch, de-de, de-lu, de-li | | Yunani | el, el-gr | | Gujarati | gu, gu-in | | Hausa | ha, ha-latn, ha-latn-ng | | Bahasa Ibrani | he, he-il | | Bahasa Hindi | hai, hi-in | | Hongaria | hu, hu-hu | | Islandia | apakah, is-is | Igb - ig-latn, ig-ng | | Bahasa Indonesia | id, id-id | | Inuktitut (Latin) | iu-cans, iu-latn, iu-latn-ca | | Irlandia | ga, ga-ie | | isiXhosa | xh, xh-za | | isiZulu | zu, zu-za | | Italia | it, it-it, it-ch | | Bahasa Jepang | ja , ja-jp | | Kannada | kn, kn-in | | Kazakh | kk, kk-kz | | Khmer | km, km-kh | | K'iche' | quc-latn, qut-gt, qut-latn | | Kinyarwanda | rw, rw-rw | | KiSwahili | sw, sw-ke | | Konkani | kok, kok-in | | Bahasa Korea | ko, ko-kr | | Kurdi | ku-arab, ku-arab-iq | | Kyrgyz | ky-kg, ky-cyrl | | Lao | lo, lo-la | | Bahasa Latvia | lv, lv-lv | | Bahasa Lituania | lt, lt-lt | | Luksemburg | lb, lb-lu | | Makedonia | mk, mk-mk | | Melayu | ms, ms-bn, ms-my | | Malayalam | ml, ml-in | | Malta | mt, mt-mt | | Maori | mi, mi-latn, mi-nz | | Marathi | mr, mr-in | | Mongolia (Sirilik) | mn-cyrl, mn-mong, mn-mn, mn-phag | | Bahasa Nepal | ne, ne-np | | Norwegia | nb, nb-no, nn, nn-no, tidak, no-no | | Odia | atau, or-in | | Persia | fa, fa-ir | | Polandia | pl, pl-pl | | Portugis (Brasil) | pt-br | | Portugis (Portugal) | pt, pt-pt | | Punjabi | pa, pa-arab, pa-arab-pk, pa-deva, pa-in | | Quechua | quz, quz-bo, quz-ec, quz-pe | | Rumania | ro, ro-ro | | Rusia | ru , ru-ru | | Gaelik Skotlandia | gd-gb, gd-latn | | Serbia (Latin) | sr-Latn, sr-latn-cs, sr, sr-latn-ba, sr-latn-me, sr-latn-rs | | Serbia (Sirilik) | 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 | | Sinhala | si, si-lk | | Slowakia | sk, sk-sk | | Slovenia | sl, sl-si | | Spanyol | 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 | | Swedia | sv, sv-se, sv-fi | | Tajik (Sirilik) | tg-arab, tg-cyrl, tg-cyrl-tj, tg-latn | | Tamil | ta, ta-in | | Tatar | tt-arab, tt-cyrl, tt-latn, tt-ru | | Telugu | te, te-in | | Thailand | th, th-th | | Tigrinya | ti, ti-et | | Turki | tr, tr-tr | | Turkmen | tk-cyrl, tk-latn, tk-tm, tk-latn-tr, tk-cyrl-tr | | | Ukraina | uk, uk-ua | | Urdu | anda, ur-pk | | Uyghur | ug-arab, ug-cn, ug-cyrl, ug-latn | | Uzbek (Latin) | uz, uz-cyrl, uz-latn, uz-latn-uz | | Vietnam | vi, vi-vn | | Welsh | cy, cy-gb | | Wolof | wo, wo-sn | | Yoruba | yo-latn, yo-ng |

Permintaan Sampel

{
    "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"]
}

Header Respons

Kepala Halaman Nilai
X-Correlation-ID ID unik jenis GUID untuk setiap permintaan. Ini dapat dibagikan dengan Tim Dukungan untuk menganalisis masalah apa pun.
Retry-After Waktu dalam detik klien harus menunggu sebelum memanggil API lagi karena pembatasan tarif

Parameter Respons

Nama Tipe Deskripsi
apakahBerhasil Boolean
Kesalahan Array objek Daftar pesan kesalahan atau peringatan jika ada
kode string Kode kesalahan Pesan
pesan string Deskripsi kesalahan
sasaran string Entitas tempat Kesalahan berasal
responseData Objek Berisi Payload respons aktual untuk Permintaan
URL pemungutan suara string URL Polling untuk mendapatkan status Pengiriman Yang Sedang Berlangsung
IDPengajuanBerlangsung string Id Pengiriman dari Pengiriman yang Sudah Berlangsung

Respons Sampel

{
    "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": ""
    } 
}

Dapatkan API Paket Draf Saat Ini

Mengambil detail paket di bawah pengiriman draf saat ini.

Jalur [Semua Paket]: /submission/v1/product/{productId}/packages
Metode: GET

Jalur [Paket Tunggal]: /submission/v1/product/{productId}/packages/{packageId}
Metode: GET

Parameter Jalur

Nama Deskripsi
ID produk ID Pusat Mitra produk
packageId ID unik paket yang akan diambil

Header yang Diperlukan

Kepala Halaman Nilai
Authorization: Bearer <Token> Menggunakan ID aplikasi ID Microsoft Entra yang terdaftar di akun Pusat Mitra
X-Seller-Account-Id ID Penjual akun Pusat Mitra

Header Respons

Kepala Halaman Nilai
X-Correlation-ID ID unik jenis GUID untuk setiap permintaan. Ini dapat dibagikan dengan tim Dukungan untuk menganalisis masalah apa pun.
Retry-After Waktu dalam detik klien harus menunggu sebelum memanggil API lagi karena pembatasan tarif.

Parameter Respons

Nama Tipe Deskripsi
apakahBerhasil Boolean
Kesalahan Array objek Daftar kesalahan atau pesan peringatan jika ada
kode string Kode kesalahan Pesan
pesan string Deskripsi kesalahan
sasaran string Entitas tempat kesalahan berasal
responseData Objek
paket Array objek Objek untuk menyimpan data modul paket
packageId string
packageUrl string
bahasa Array string
Arsitektur Array string [Netral, X86, X64, Arm, Arm64]
isSilentInstall Boolean Ini harus ditandai sebagai true jika alat penginstal Anda berjalan dalam mode senyap tanpa memerlukan sakelar atau false lainnya
installerParameters string
genericDocUrl string
detailKesalahan Array objek
skenarioKesalahan string
errorScenarioDetails Array objek
nilaiKesalahan string
errorUrl string
jenis paket string

Respons Sampel

{   
    "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",
        }]
    }
}

Perbarui API Paket Draf Saat Ini

Memperbarui detail paket di bawah pengiriman draf saat ini.

Jalur [Pembaruan Modul Lengkap]: /submission/v1/product/{productId}/packages
Metode: PUT

Jalur [Pembaruan Patch Paket Tunggal]: /submission/v1/product/{productId}/packages/{packageId}
Metode: PATCH

Perilaku API

Dalam kasus API Pembaruan Modul Penuh - seluruh data paket perlu ada dalam permintaan untuk pembaruan penuh dari setiap bidang. Bidang apa pun yang tidak ada dalam permintaan, nilai defaultnya digunakan untuk menimpa nilai saat ini untuk modul tertentu tersebut. Ini menghasilkan penimpaan semua paket yang ada dengan sekumpulan paket baru dari permintaan. Ini akan mengakibatkan regenerasi Id Paket dan pengguna harus memanggil GET Packages API untuk Id Paket terbaru.

Dalam kasus API Pembaruan Patch Paket Tunggal – hanya bidang yang akan diperbarui untuk paket tertentu yang perlu ada dalam permintaan. Nilai bidang dari permintaan ini akan menimpa nilai yang ada, menyimpan semua bidang lain yang tidak ada dalam permintaan, sama seperti saat ini untuk paket tertentu tersebut. Paket lain dalam set tetap apa adanya.

Parameter Jalur

Nama Deskripsi
ID produk ID Pusat Mitra produk
packageId ID unik paket

Header yang Diperlukan

Kepala Halaman Nilai
Authorization: Bearer <Token> Menggunakan ID aplikasi ID Microsoft Entra yang terdaftar di akun Pusat Mitra
X-Seller-Account-Id ID Penjual akun Pusat Mitra

Parameter Permintaan

Nama Tipe Deskripsi
paket Array Objek Objek untuk menyimpan data Modul Paket [Hanya Diperlukan untuk Pembaruan Modul Penuh]
packageUrl string Diperlukan
bahasa Array string Diperlukan
Arsitektur Array string Diperlukan Harus berisi arsitektur tunggal - Netral, X86, X64, Arm, Arm64
isSilentInstall Boolean Diperlukan Ini harus ditandai sebagai true jika alat penginstal Anda berjalan dalam mode senyap tanpa memerlukan sakelar atau false lainnya
installerParameters string Diperlukan jika isSilentInstall salah
genericDocUrl string Diperlukan jika packageType adalah exe Link ke dokumen yang berisi detail kode kesalahan kustom untuk penginstal jenis EXE
detailKesalahan Array Objek Metadata untuk menyimpan kode kesalahan kustom dan detail untuk Penginstal jenis EXE.
skenarioKesalahan string Identifikasi skenario kesalahan tertentu. [instalasiDibatalkanOlehPengguna, aplikasiSudahAda, instalasiSedangBerlangsung, ruangDiskPenuh, perluRestart, kegagalanJaringan, paketDitolakSelamaInstalasi, instalasiBerhasil, lain-lain]
errorScenarioDetails Array Objek
nilaiKesalahan string Kode kesalahan yang dapat ada selama Penginstalan
errorUrl string URL untuk memiliki detail tentang kesalahan
jenis paket string Diperlukan [exe, msi]

Permintaan Sampel [Pembaruan Modul Lengkap]

{
    "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",
    }]
}

Permintaan Sampel [Pembaruan Patch Paket Tunggal]

{
    "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",
}

Header Respons

Kepala Halaman Nilai
X-Correlation-ID ID unik jenis GUID untuk setiap permintaan. Ini dapat dibagikan dengan tim Dukungan untuk menganalisis masalah apa pun.
Retry-After Waktu dalam detik klien harus menunggu sebelum memanggil API lagi karena pembatasan tarif.

Parameter Respons

Nama Tipe Deskripsi
apakahBerhasil Boolean
Kesalahan Array objek [Daftar pesan kesalahan atau peringatan jika ada]
kode string Kode Kesalahan Pesan
pesan string Deskripsi Kesalahan
sasaran string Entitas tempat Kesalahan berasal
responseData Objek
URL pemungutan suara string [URL Polling untuk mendapatkan Status Pengiriman jika ada Pengiriman yang Sudah Berlangsung]
IDPengajuanBerlangsung string [ID Pengiriman dari Pengiriman yang Sudah Berlangsung]

Respons Sampel

{
    "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": ""
    } 
}

Commit Packages API

Menerapkan kumpulan Paket baru yang diperbarui menggunakan API Pembaruan Paket di bawah pengiriman draf saat ini. API ini mengembalikan URL Polling untuk melacak Unggahan Paket.

Jalur: /submission/v1/product/{productId}/packages/commit
Metode: POST

Parameter Jalur

Nama Deskripsi
ID produk ID Pusat Mitra produk

Header yang Diperlukan

Kepala Halaman Nilai
Authorization: Bearer <Token> Menggunakan ID Aplikasi ID Microsoft Entra yang terdaftar di akun Pusat Mitra
X-Seller-Account-Id ID Penjual akun Pusat Mitra

Header Respons

Kepala Halaman Nilai
X-Correlation-ID ID unik jenis GUID untuk setiap permintaan. Ini dapat dibagikan dengan tim Dukungan untuk menganalisis masalah apa pun.
Retry-After Waktu dalam detik klien harus menunggu sebelum memanggil API lagi karena pembatasan tarif.

Parameter Respons

Nama Tipe Deskripsi
apakahBerhasil Boolean
Kesalahan Array objek [Daftar pesan kesalahan atau peringatan jika ada]
kode string Kode kesalahan Pesan
pesan string Deskripsi kesalahan
sasaran string Entitas tempat kesalahan berasal
responseData Objek
URL pemungutan suara string [URL Polling untuk mendapatkan status Status Unggahan atau Pengiriman Paket jika ada Pengiriman yang Sudah Berlangsung]
IDPengajuanBerlangsung string [Id Pengiriman dari Pengiriman yang Sudah Berlangsung]

Respons Sampel

{
    "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": ""
    } 
}

Dapatkan API Aset Daftar Draf Saat Ini

Mengambil detail aset daftar di bawah pengiriman draf saat ini.

Jalur: /submission/v1/product/{productId}/listings/assets?languages={languages}
Metode: GET

Parameter Jalur

Nama Deskripsi
ID produk ID Pusat Mitra produk

Parameter Kueri:

Nama Deskripsi
bahasa [Opsional] Bahasa daftar memfilter sebagai string yang dipisahkan koma [batas hingga 200 bahasa]. Jika tidak ada, 200 data aset bahasa daftar pertama yang tersedia akan diambil. (misalnya, "en-us, en-gb")

Header yang Diperlukan

Kepala Halaman Nilai
Authorization: Bearer <Token> Menggunakan ID Aplikasi ID Microsoft Entra yang terdaftar di akun Pusat Mitra
X-Seller-Account-Id ID Penjual akun Pusat Mitra

Header Respons

Kepala Halaman Nilai
X-Correlation-ID ID unik jenis GUID untuk setiap permintaan. Ini dapat dibagikan dengan tim Dukungan untuk menganalisis masalah apa pun.
Retry-After Waktu dalam detik klien harus menunggu sebelum memanggil API lagi karena pembatasan tarif.

Parameter Respons

Nama Tipe Deskripsi
apakahBerhasil Boolean
Kesalahan Array objek Daftar pesan kesalahan atau peringatan jika ada
kode string Kode kesalahan Pesan
pesan string Deskripsi kesalahan
sasaran string Entitas tempat kesalahan berasal
responseData Objek
daftarAset Array objek Mencantumkan detail aset untuk setiap bahasa
bahasa string
storeLogos Array objek
cuplikan layar Array objek
Id string
assetUrl string Harus berupa URL yang valid
ukuran gambar Objek
lebar Bilangan bulat
tinggi Bilangan bulat

Respons Sampel

{   
"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
                    }
                }
            ]
        }]
    }
}

Membuat API Aset Daftar

Membuat Unggahan Aset Daftar baru di bawah pengiriman draf saat ini.

Pembaruan aset Daftar

MICROSOFT Store Submission API untuk EXE atau aplikasi MSI menggunakan URL SAS yang dihasilkan runtime ke Blob Stores untuk setiap unggahan aset gambar individu, bersama dengan panggilan Commit API setelah pengunggahan berhasil. Untuk memiliki kemampuan untuk memperbarui aset daftar, dan pada gilirannya, untuk dapat menambahkan/menghapus lokal dalam modul daftar, pendekatan berikut dapat digunakan:

  1. Gunakan API Buat Aset Daftar untuk mengirim permintaan mengenai pengunggahan aset bersama dengan bahasa, jenis, dan jumlah aset.
  2. Berdasarkan jumlah aset yang diminta, ID Aset dibuat sesuai permintaan dan akan membuat URL SAS jangka pendek dan mengirimkannya kembali di Isi Respons di bawah jenis aset. Anda dapat menggunakan URL ini untuk mengunggah aset Gambar dari jenis tertentu menggunakan Klien HTTP [Put Blob (REST API) - Azure Storage | Microsoft Docs].
  3. Setelah mengunggah, Anda dapat menggunakan COMmit Listing Assets API untuk juga mengirim informasi ID Aset baru yang diterima sebelumnya dari panggilan API sebelumnya. API tunggal akan secara internal menerapkan data aset daftar setelah validasi.
  4. Pendekatan ini akan secara efektif menimpa seluruh set Gambar Sebelumnya dari Jenis Aset di bawah Bahasa tertentu yang sedang dikirim dalam Permintaan. Oleh karena itu, Aset yang diunggah sebelumnya akan dihapus.

Jalur: /submission/v1/product/{productId}/listings/assets/create
Metode: POST

Parameter Jalur

Nama Deskripsi
ID produk ID Pusat Mitra produk

Header yang Diperlukan

Kepala Halaman Deskripsi
Authorization: Bearer <Token> Menggunakan ID Aplikasi ID Microsoft Entra yang terdaftar di akun Pusat Mitra
X-Seller-Account-Id ID Penjual akun Pusat Mitra

Parameter Permintaan

Nama Tipe Deskripsi
bahasa string Diperlukan
buatPermintaanAset Objek Diperlukan
Cuplikan layar Bilangan bulat Diperlukan jika ISV perlu memperbarui cuplikan layar atau menambahkan bahasa daftar baru [1 - 10]
Logo Bilangan bulat Diperlukan jika ISV perlu memperbarui logo atau menambahkan bahasa daftar baru [1 atau 2]

Header Respons

Kepala Halaman Deskripsi
X-Correlation-ID ID unik jenis GUID untuk setiap permintaan. Ini dapat dibagikan dengan tim Dukungan untuk menganalisis masalah apa pun.
Retry-After Waktu dalam detik klien harus menunggu sebelum memanggil API lagi karena pembatasan tarif.

Parameter Respons

Nama Tipe Deskripsi
apakahBerhasil Boolean
Kesalahan Array objek Daftar pesan kesalahan atau peringatan jika ada
kode string Kode kesalahan Pesan
pesan string Deskripsi kesalahan
sasaran string Entitas tempat kesalahan berasal
responseData Objek
daftarAset Objek Objek yang berisi detail StoreLogos dan Cuplikan layar yang akan diunggah
bahasa string
storeLogos Array objek
cuplikan layar Array objek
Id string
URL Upload Aset Utama string URL utama untuk mengunggah aset daftar menggunakan Azure Blob REST API
URLUnggahAsetSekunder string URL sekunder untuk mengunggah aset daftar menggunakan Azure Blob REST API
Metode HTTP Metode HTTP Metode HTTP perlu digunakan untuk mengunggah Aset melalui URL Pengunggahan Aset – Primer atau Sekunder
httpHeader Objek Objek dengan kunci sebagai Header yang diperlukan untuk hadir dalam panggilan Unggah API ke URL Pengunggahan Aset. Jika nilainya tidak kosong, header harus memiliki nilai tertentu. Jika tidak, nilai dihitung selama panggilan API.

Respons Sampel

{
    "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"}

            }]
        }
    } 
}

Terapkan API Aset Daftar

Menerapkan Aset Daftar baru yang Diunggah menggunakan detail dari Buat Aset API di bawah pengiriman draf saat ini.

Jalur: /submission/v1/product/{productId}/listings/assets/commit
Metode: PUT

Parameter Jalur

Nama Deskripsi
ID produk ID Pusat Mitra produk

Header yang Diperlukan

Kepala Halaman Deskripsi
Authorization: Bearer <Token> Menggunakan ID Aplikasi ID Microsoft Entra yang terdaftar di akun Pusat Mitra
X-Seller-Account-Id ID Penjual akun Pusat Mitra

Parameter Permintaan

Nama Tipe Deskripsi
daftarAset Objek
bahasa string
storeLogos Array Objek
cuplikan layar Array Objek
Id string Harus berupa ID yang sudah ada yang ingin dipertahankan pengguna dari Get Current Listing Assets API atau ID baru di mana Aset baru diunggah di Create Listing Assets API.
assetUrl string Harus berupa URL Aset yang ada yang ingin dipertahankan pengguna dari Get Current Listing Assets API atau URL Unggah – Primer atau Sekunder, yang menggunakan Aset baru yang diunggah di Api Buat Aset Daftar. Harus berupa URL yang valid

Permintaan Sampel

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

Header Respons

Kepala Halaman Deskripsi
X-Correlation-ID ID unik jenis GUID untuk setiap permintaan. Ini dapat dibagikan dengan tim Dukungan untuk menganalisis masalah apa pun.
Retry-After Waktu dalam detik klien harus menunggu sebelum memanggil API lagi karena pembatasan tarif.

Parameter Respons

Nama Tipe Deskripsi
apakahBerhasil Boolean
Kesalahan Array objek Daftar pesan kesalahan atau peringatan jika ada
kode string Kode kesalahan Pesan
pesan string Deskripsi kesalahan
sasaran string Entitas tempat kesalahan berasal
responseData Objek
URL pemungutan suara string URL polling untuk mendapatkan status pengiriman yang sedang berlangsung
IDPengajuanBerlangsung string ID pengiriman dari pengiriman yang sudah berlangsung

Respons Sampel

{
    "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 Polling Status Modul

API untuk memeriksa kesiapan modul sebelum pengiriman dapat dibuat. Juga memvalidasi status unggahan paket.

Jalur: /submission/v1/product/{productId}/status
Metode: GET

Parameter Jalur

Nama Deskripsi
ID produk ID Pusat Mitra produk

Header yang Diperlukan

Kepala Halaman Deskripsi
Authorization: Bearer <Token> Menggunakan ID Aplikasi ID Microsoft Entra yang terdaftar di akun Pusat Mitra
X-Seller-Account-Id ID Penjual akun Pusat Mitra

Header Respons

Kepala Halaman Deskripsi
X-Correlation-ID ID unik jenis GUID untuk setiap permintaan. Ini dapat dibagikan dengan tim Dukungan untuk menganalisis masalah apa pun.
Retry-After Waktu dalam detik klien harus menunggu sebelum memanggil API lagi karena pembatasan tarif.

Parameter Respons

Nama Tipe Deskripsi
apakahBerhasil Boolean
Kesalahan Array objek Daftar pesan kesalahan atau peringatan jika ada
kode string Kode kesalahan Pesan
pesan string Deskripsi kesalahan
sasaran string Entitas tempat kesalahan berasal
responseData Objek
isReady Boolean Menunjukkan apakah semua Modul dalam status siap termasuk unggahan paket
IDPengajuanBerlangsung string ID pengiriman dari pengiriman yang sudah berlangsung

Respons Sampel

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

Membuat API Pengiriman

Membuat pengiriman dari draf saat ini untuk aplikasi MSI atau EXE. API memeriksa:

  • untuk pengiriman aktif dan gagal dengan pesan kesalahan jika pengiriman aktif ada.
  • jika semua modul dalam status siap untuk membuat pengiriman.
  • setiap bidang dalam pengiriman divalidasi sesuai persyaratan Penyimpanan

Jalur:/submission/v1/product/{productId}/submit
Metode: POST

Parameter Jalur

Nama Deskripsi
ID produk ID Pusat Mitra produk

Header yang Diperlukan

Kepala Halaman Deskripsi
Authorization: Bearer <Token> Menggunakan ID Aplikasi ID Microsoft Entra yang terdaftar di akun Pusat Mitra
X-Seller-Account-Id ID Penjual akun Pusat Mitra

Header Respons

Kepala Halaman Deskripsi
X-Correlation-ID ID unik jenis GUID untuk setiap permintaan. Ini dapat dibagikan dengan tim Dukungan untuk menganalisis masalah apa pun.
Retry-After Waktu dalam detik klien harus menunggu sebelum memanggil API lagi karena pembatasan tarif.

Parameter Respons

Nama Tipe Deskripsi
apakahBerhasil Boolean
Kesalahan Array objek Daftar pesan kesalahan atau peringatan jika ada
kode string Kode kesalahan Pesan
pesan string Deskripsi kesalahan
sasaran string Entitas tempat kesalahan berasal
responseData Objek
URL pemungutan suara string URL polling untuk mendapatkan status kesiapan modul termasuk unggahan paket untuk pengiriman
ID pengajuan string ID untuk Pengiriman yang baru dibuat
IDPengajuanBerlangsung string ID pengiriman dari pengiriman yang sudah berlangsung

Respons Sampel

{
    "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 Polling Status Pengiriman

API untuk memeriksa Status Pengiriman.

Jalur: /submission/v1/product/{productId}/submission/{submissionId}/status
Metode: GET

Parameter Jalur

Nama Deskripsi
ID produk ID Pusat Mitra produk

Header yang Diperlukan

Kepala Halaman Deskripsi
Authorization: Bearer <Token> Menggunakan ID Aplikasi ID Microsoft Entra yang terdaftar di akun Pusat Mitra
X-Seller-Account-Id ID Penjual akun Pusat Mitra

Header Respons

Kepala Halaman Deskripsi
X-Correlation-ID ID unik jenis GUID untuk setiap permintaan. Ini dapat dibagikan dengan tim Dukungan untuk menganalisis masalah apa pun.
Retry-After Waktu dalam detik klien harus menunggu sebelum memanggil API lagi karena pembatasan tarif.

Parameter Respons

Nama Tipe Deskripsi
apakahBerhasil Boolean
Kesalahan Array objek Daftar pesan kesalahan atau peringatan jika ada
kode string Kode kesalahan Pesan
pesan string Deskripsi kesalahan
sasaran string Entitas tempat kesalahan berasal
responseData Objek
status penerbitan string Status Penerbitan Pengiriman - [INPROGRESS, PUBLISHED, FAILED, UNKNOWN]
telah gagal Boolean Menunjukkan apakah Penerbitan Gagal dan tidak akan dicoba kembali

Respons Sampel

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

Contoh kode

Artikel berikut ini menyediakan contoh kode terperinci yang menunjukkan cara menggunakan API pengiriman Microsoft Store dalam bahasa pemrograman yang berbeda:

Sampel C#: MICROSOFT Store Submission API untuk aplikasi MSI atau EXE

Artikel ini menyediakan contoh kode C# yang menunjukkan cara menggunakan API pengiriman Microsoft Store untuk aplikasi MSI atau EXE. Anda dapat meninjau setiap contoh untuk mempelajari lebih lanjut tentang tugas yang ditunjukkannya, atau Anda dapat membuat semua contoh kode dalam artikel ini ke dalam aplikasi konsol.

Prasyarat Contoh ini menggunakan pustaka berikut:

  • Paket Newtonsoft.Json NuGet dari Newtonsoft.

Program utama Contoh berikut mengimplementasikan program baris perintah yang memanggil metode contoh lain dalam artikel ini untuk menunjukkan berbagai cara untuk menggunakan API pengiriman Microsoft Store. Untuk menyesuaikan program ini untuk penggunaan Anda sendiri:

  • Tetapkan properti SellerId ke ID Penjual akun Pusat Mitra Anda.
  • Tetapkan properti ApplicationId ke ID aplikasi yang ingin Anda kelola.
  • Tetapkan properti ClientId dan ClientSecret ke ID klien dan kunci untuk aplikasi Anda, dan ganti string tenantid di URL TokenEndpoint dengan ID penyewa untuk aplikasi Anda. Untuk informasi selengkapnya, lihat Cara mengaitkan aplikasi ID Microsoft Entra dengan akun Pusat Mitra Anda
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();

        }
    }
}

Kelas pembantu ClientConfiguration menggunakan C#

Aplikasi sampel menggunakan kelas pembantu ClientConfiguration untuk meneruskan data Microsoft Entra ID Directory dan data aplikasi ke setiap metode contoh yang menggunakan API pengiriman 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; }
    }
}

Membuat pengiriman aplikasi menggunakan C#

Contoh berikut mengimplementasikan kelas yang menggunakan beberapa metode di API pengiriman Microsoft Store untuk memperbarui pengiriman aplikasi.

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

Kelas pembantu IngestionClient menggunakan C#

Kelas IngestionClient menyediakan metode pembantu yang digunakan oleh metode lain dalam aplikasi sampel untuk melakukan tugas-tugas berikut:

  • Dapatkan token akses ID Microsoft Entra yang dapat digunakan untuk memanggil metode di API pengiriman Microsoft Store. Setelah mendapatkan token, Anda memiliki waktu 60 menit untuk menggunakan token ini dalam panggilan ke API pengiriman Microsoft Store sebelum token kedaluwarsa. Setelah token kedaluwarsa, Anda dapat menghasilkan token baru.
  • Proses permintaan HTTP untuk API pengiriman 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;
        }
    }
}

sampel Node.js: MICROSOFT Store Submission API untuk aplikasi MSI atau EXE

Artikel ini menyediakan contoh kode Node.js yang menunjukkan cara menggunakan API pengiriman Microsoft Store untuk aplikasi MSI atau EXE. Anda dapat meninjau setiap contoh untuk mempelajari lebih lanjut tentang tugas yang ditunjukkannya, atau Anda dapat membuat semua contoh kode dalam artikel ini ke dalam aplikasi konsol.

Prasyarat Contoh ini menggunakan pustaka berikut:

  • Gunakan perintah berikut untuk menginstal versi 2 dari node-fetch: node-fetch v2 [npm install node-fetch@2]

Membuat pengiriman aplikasi menggunakan node.js

Contoh berikut memanggil contoh metode lain dalam artikel ini untuk menunjukkan berbagai cara untuk menggunakan API pengiriman Microsoft Store. Untuk menyesuaikan program ini untuk penggunaan Anda sendiri:

  • Tetapkan properti SellerId ke ID Penjual akun Pusat Mitra Anda.
  • Tetapkan properti ApplicationId ke ID aplikasi yang ingin Anda kelola.
  • Tetapkan properti ClientId dan ClientSecret ke ID klien dan kunci untuk aplikasi Anda, dan ganti string tenantid di URL TokenEndpoint dengan ID penyewa untuk aplikasi Anda. Untuk informasi selengkapnya, lihat Cara mengaitkan aplikasi ID Microsoft Entra dengan akun Pusat Mitra Anda

Contoh berikut mengimplementasikan kelas yang menggunakan beberapa metode di API pengiriman Microsoft Store untuk memperbarui pengiriman aplikasi.

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

Pembantu ClientConfiguration

Aplikasi sampel menggunakan kelas pembantu ClientConfiguration untuk meneruskan data Microsoft Entra ID Directory dan data aplikasi ke setiap metode contoh yang menggunakan API pengiriman 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;

Pembantu IngestionClient menggunakan node.js

Kelas IngestionClient menyediakan metode pembantu yang digunakan oleh metode lain dalam aplikasi sampel untuk melakukan tugas-tugas berikut:

  • Dapatkan token akses ID Microsoft Entra yang dapat digunakan untuk memanggil metode di API pengiriman Microsoft Store. Setelah mendapatkan token, Anda memiliki waktu 60 menit untuk menggunakan token ini dalam panggilan ke API pengiriman Microsoft Store sebelum token kedaluwarsa. Setelah token kedaluwarsa, Anda dapat menghasilkan token baru.
  • Proses permintaan HTTP untuk API pengiriman 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;

Bantuan tambahan

Jika Anda memiliki pertanyaan tentang API pengiriman Microsoft Store atau memerlukan bantuan dalam mengelola pengiriman Anda dengan API ini, gunakan sumber daya berikut:

  • Ajukan pertanyaan Anda di forum kami.
  • Kunjungi halaman dukungan kami dan minta salah satu opsi dukungan yang dibantu untuk Pusat Mitra. Jika Anda diminta untuk memilih jenis dan kategori masalah, pilih Pengiriman dan sertifikasi aplikasi dan Mengirimkan aplikasi.