MSI または EXE アプリ用の Microsoft Store 申請 API を使用して、自分または組織のパートナー センター アカウントの MSI または EXE アプリの申請をプログラムで照会して作成します。 この API は、アカウントで多数のアプリを管理しており、これらのアセットの申請プロセスを自動化および最適化する場合に便利です。 この API は、Microsoft Entra ID を使用して、アプリまたはサービスからの呼び出しを認証します。
次の手順では、Microsoft Store 申請 API を使用するエンド ツー エンドのプロセスについて説明します。
- すべての前提条件を完了したことを確認します。
- Microsoft Store 申請 API でメソッドを呼び出す前に、Microsoft Entra ID アクセス トークンを取得します。 トークンを取得した後、Microsoft Store 申請 API の呼び出しでこのトークンを使用できるのは、その有効期限が切れるまでの 60 分間です。 トークンの有効期限が切れた後は、新しいトークンを生成できます。
- MSI または EXE アプリ用の Microsoft Store 申請 API を呼び出します。
手順 1: Microsoft Store 申請 API を使用するための前提条件を完了する。
MSI または EXE アプリ用の Microsoft Store 申請 API を呼び出すコードの記述を開始する前に、次の前提条件を満たしていることを確認してください。
- ユーザー (または組織) は Microsoft Entra ID ディレクトリを持っている必要があり、ディレクトリの全体管理者アクセス許可が必要です。 Microsoft 365 または Microsoft の他のビジネス サービスを既に使用している場合は、Microsoft Entra ID ディレクトリが既にあります。 それ以外の場合は、 パートナー センターで新しい Microsoft Entra ID を 追加料金なしで作成できます。
- Microsoft Entra ID アプリケーションをパートナー センター アカウントに関連付け、テナント ID、クライアント ID、キーを取得する必要があります。 Microsoft Entra ID アクセス トークンを取得するには、これらの値が必要です。これは、Microsoft Store 申請 API の呼び出しで使用します。
- Microsoft Store 申請 API で使用するアプリを準備します。
- パートナー センターにアプリがまだ存在しない場合は、パートナー センターでアプリの名前を予約してアプリを作成する必要があります。 Microsoft Store 申請 API を使ってパートナー センターにアプリを作成することはできません。パートナー センターを使ってアプリを作成する必要があります。その後、API を使ってアプリにアクセスし、プログラムでアプリの申請を作成できます。
- この API を使って特定のアプリの申請を作成する前に、年齢区分に関するアンケートへの回答など、最初にパートナー センターでアプリの申請を 1 つ作成する必要があります。 これを行うと、API を使用して、このアプリの新しい申請をプログラムで作成できるようになります。
- アプリの申請を作成または更新していて、新しいパッケージを含める必要がある場合は、パッケージの詳細を準備します。
- アプリの申請を作成または更新していて、ストア登録情報のスクリーンショットまたは画像を含める必要がある場合は、アプリのスクリーンショットと画像を準備します。
Microsoft Entra ID アプリケーションをパートナー センター アカウントに関連付ける方法
MSI または EXE アプリ用の Microsoft Store 申請 API を使用する前に、Microsoft Entra ID アプリケーションをパートナー センター アカウントに関連付け、アプリケーションのテナント ID とクライアント ID を取得し、キーを生成する必要があります。 Microsoft Entra ID アプリケーションは、Microsoft Store 申請 API を呼び出すアプリまたはサービスを表します。 API に渡す Microsoft Entra ID アクセス トークンを取得するには、テナント ID、クライアント ID、キーが必要です。
注
この作業を行うのは一度だけです。 テナント ID、クライアント ID、およびキーを取得したら、新しい Microsoft Entra ID アクセス トークンを作成する必要がある場合は、いつでもそれらを再利用できます。
- パートナー センターで、 組織のパートナー センター アカウントを組織の Microsoft Entra ID ディレクトリに関連付けます。
- 次に、パートナー センターの [アカウント設定] セクションの [ユーザー] ページから、パートナー センター アカウントの申請にアクセスするために使用するアプリまたはサービスを表す Microsoft Entra ID アプリケーションを追加 します。 このアプリケーションにマネージャー ロールを確実に割り当てます。 アプリケーションが Microsoft Entra ID ディレクトリにまだ存在しない場合は、 パートナー センターで新しい Microsoft Entra ID アプリケーションを作成できます。
- [ユーザー] ページに戻り、Microsoft Entra ID アプリケーションの名前をクリックしてアプリケーション設定に移動し、テナント ID とクライアント ID の値をコピーします。
- 新しいキーまたはクライアント シークレットを追加するには、次の手順を参照するか、Azure Portal を使用してアプリを登録する手順を参照してください。
アプリを登録するには:
Azure portal にサインインします。
複数のテナントにアクセスできる場合は、トップ メニューの [ディレクトリとサブスクリプション] フィルター を使用して、アプリケーションを登録するテナントに切り替えます。
Microsoft Entra ID Directory を検索して選択します。
[管理] で [アプリの登録] を選択し、>アプリケーションを選択します。
>[証明書 & シークレット][クライアント シークレット]>[新しいクライアント シークレット] を選択します。
クライアント シークレットの説明を追加します。
シークレットの有効期限を選択するか、カスタムの有効期間を指定します。
クライアント シークレットの有効期間は、2 年間 (24 か月) 以下に制限されています。 24 か月を超えるカスタムの有効期間を指定することはできません。
注
Microsoft では、有効期限の値は 12 か月未満に設定することをお勧めしています。
[追加] を選択します。
クライアント アプリケーションのコードで使用できるように、"シークレットの値を記録します"。 このページからの移動後は、このシークレットの値は "二度と表示されません"。
手順 2: Microsoft Entra ID アクセス トークンを取得する
MSI または EXE アプリの Microsoft Store 申請 API のメソッドを呼び出す前に、API の各メソッドの Authorization ヘッダーに渡す Microsoft Entra ID アクセス トークンを最初に取得する必要があります。 アクセス トークンを取得したら、期限が切れる 60 分が経過する前に使用します。 トークンの有効期限が切れた後は、トークンを更新してそれ以降の API 呼び出しで引き続き使用できます。
アクセス トークンを取得するには、「 クライアント資格情報を使用したサービス間呼び出し 」の手順に従って、 https://login.microsoftonline.com/<tenant_id>/oauth2/token エンドポイントに HTTP POST を送信します。 要求の例を次に示します。
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_idPOST URI と client_idandclient_secret パラメーターの値には、前のセクションでパートナー センターから取得したアプリケーションのテナント ID、クライアント ID、およびキーを指定します。 scope パラメーターには、 を指定する必要がありますhttps://api.store.microsoft.com/.default。
アクセス トークンの有効期限が切れた後は、この手順に従って更新できます。
C# または Node.js を使用してアクセス トークンを取得する方法を示す例については、MSI または EXE アプリの Microsoft Store 申請 API のコード例を参照してください。
手順 3: Microsoft Store 申請 API を使用する
Microsoft Entra ID アクセス トークンを取得したら、MSI または EXE アプリの Microsoft Store 申請 API でメソッドを呼び出すことができます。 API には、アプリのシナリオにグループ化された多くのメソッドが含まれています。 申請を作成または更新するには、通常、複数のメソッドを特定の順序で呼び出します。 各シナリオと各メソッドの構文については、次のセクションを参照してください。
注
アクセス トークンを取得した後、トークンの有効期限が切れる前に、MSI または EXE アプリ用の Microsoft Store 申請 API でメソッドを呼び出すために 60 分かかります。
ベース URL
EXE または MSI アプリ用の Microsoft Store 申請 API のベース URL は次のとおりです。https://api.store.microsoft.com
API コントラクト
Current Draft Submission Metadata API を取得する
現在の下書き送信の下書きにある各モジュールのメタデータ(リスト、プロパティ、または可用性)を取得します。
パス [All Modules]:/submission/v1/product/{productId}/metadata?languages={languages}&includelanguagelist={true/false}
パス [Single Module]:/submission/v1/product/{productId}/metadata/{moduleName}?languages={languages}>includelanguagelist={true/false}
メソッド: GET
パス パラメーター
| パラメーター | 説明 |
|---|---|
| productId | 製品のパートナー センター ID |
| モジュール名 | パートナー センター モジュール – 登録情報、プロパティ、または可用性 |
クエリ パラメーター
| パラメーター | 説明 |
|---|---|
| 言語 |
オプション: リスト言語はコンマ区切り文字列としてフィルタリングされます (最大 200 言語の制限)。 存在しない場合は、最初の 200 個の使用可能なリスト言語のメタデータが取得されます。 [ e.g.,“en-us, en-gb"]. |
| 言語リストを含む | オプションのブール値 – true の場合、追加されたリスト言語のリストとその完全性ステータスを返します。 |
必須のヘッダー
| ヘッダー | 値 |
|---|---|
Authorization: Bearer <Token> |
パートナー センター アカウントに登録されている Microsoft Entra ID アプリ ID |
X-Seller-Account-Id |
パートナー センター アカウントの販売者 ID |
応答ヘッダー
| ヘッダー | 値 |
|---|---|
X-Correlation-ID |
各要求の GUID の種類の一意の ID。 これは、問題を分析するためにサポートチームと共有できます。 |
Retry-After |
レート制限のために API を再度呼び出す前にクライアントが待機する必要がある時間 (秒単位)。 |
応答パラメーター
| 名前 | タイプ | 説明 |
|---|---|---|
| アクセシビリティ対応 | ブール値 | |
| 追加ライセンス条項 | 糸 | |
| 可用性 | オブジェクト | 可用性 モジュール データ |
| カテゴリ | 糸 | 以下のカテゴリのリストを参照してください |
| 認証メモ | 糸 | |
| コード | 糸 | メッセージのエラーコード |
| ContactInfo | 糸 | |
| 著作権 | 糸 | |
| ドライバーまたはNTに依存 | ブール値 | |
| 説明 | 糸 | |
| 開発者 | 糸 | |
| Discoverability | 糸 | [DISCOVERABLE, DEEPLINK_ONLY] |
| 将来市場で有効化する | ブール値 | |
| エラー | オブジェクトの配列 | エラーまたは警告メッセージのリスト (存在する場合) |
| FreeTrial | 糸 | [NO_FREE_TRIAL,FREE_TRIAL] |
| ハードウェア項目タイプ | 糸 | |
| プライバシーポリシーが必要か | ブール値 | |
| おすすめ | ブール値 | |
| 必須 | ブール値 | |
| IsSuccess | ブール値 | |
| システム機能が必要か | オブジェクトの配列 | |
| 言語 | 糸 | 以下の言語のリストを参照してください |
| 一覧 | オブジェクトの配列 | 各言語のモジュール・データのリスト |
| 市場 | 文字列の配列 | 以下の市場のリストを参照してください |
| メッセージ | 糸 | エラーの説明 |
| 最小ハードウェア | 糸 | |
| 最低要件 | 糸 | |
| ペンとインクのサポート | ブール値 | |
| 価格 | 糸 | [無料、フリーミアム、サブスクリプション、有料] |
| プライバシーポリシーURL | 糸 | |
| 製品宣言 | オブジェクト | |
| ProductFeatures | 文字列の配列 | |
| プロパティ | オブジェクト | プロパティ モジュール データ |
| 推奨ハードウェア | 糸 | |
| 推奨要件 | 糸 | |
| 応答データ | オブジェクト | 要求の実際の応答ペイロードが含まれます |
| 要件 | オブジェクトの配列 | |
| SearchTerms | 文字列の配列 | |
| 短い説明 | 糸 | |
| サブカテゴリ | 糸 | 以下のサブカテゴリのリストを参照してください |
| サポート連絡先情報 | 糸 | |
| システム要件の詳細 | オブジェクトの配列 | |
| ターゲット | 糸 | エラーの発生元エンティティ |
| Web サイト | 糸 | |
| 新着情報 | 糸 |
現在の下書き送信メタデータ API の更新
下書き提出中の各モジュールのメタデータを更新します。 API チェック
- アクティブな申請の場合。 存在する場合は、エラー メッセージで失敗します。
- すべてのモジュールが「ドラフトの保存」操作を許可する準備完了状態にある場合。
- 申請の各フィールドは、ストアの要件に従って検証されます
- システム要件の詳細検証ルール:
- hardwareItemType = メモリで使用できる値: 300MB、750MB、1GB、2GB、4GB、6GB、8GB、12GB、16GB、20GB
- hardwareItemType = DirectX で使用できる値: DX9、DX10、DX11、DX12-FEATURELEVEL11、DX12-FEATURELEVEL12
- hardwareItemType = Video_Memory で使用できる値: 1 GB、2 GB、4 GB、6 GB
Path [Full Module Update]:/submission/v1/product/{productId}/metadata
メソッド: PUT
Path [Module Patch Update]:/submission/v1/product/{productId}/metadata
メソッド: パッチ
API ビヘイビアー
Full Module Update API の場合 – すべてのフィールドを完全に更新するには、モジュールデータ全体が Request に存在する必要があります。 リクエストに存在しないフィールドの場合、そのデフォルト値は、その特定のモジュールの現在の値を上書きするために使用されます。
パッチ モジュール更新 API の場合、更新するフィールドのみが要求に存在する必要があります。 リクエストのこれらのフィールド値は既存の値を上書きし、リクエストに存在しない他のすべてのフィールドは、その特定のモジュールの現在のフィールドと同じままになります。
パス パラメーター
| パラメーター | 説明 |
|---|---|
| productId | 製品のパートナー センター ID |
必須のヘッダー
| ヘッダー | 値 |
|---|---|
Authorization: Bearer <Token> |
パートナー センター アカウントに登録されている Microsoft Entra ID アプリ ID |
X-Seller-Account-Id |
パートナー センター アカウントの販売者 ID |
要求パラメーター
| 名前 | タイプ | 説明 |
|---|---|---|
| 可用性 | オブジェクト | 可用性モジュールのメタデータを保持するオブジェクト |
| 市場 | 文字列の配列 | 必須 以下の市場のリストを参照してください |
| Discoverability | 糸 | 必須[DISCOVERABLE, DEEPLINK_ONLY] |
| 将来市場で有効化する | ブール値 | 必須 |
| 価格 | 糸 | 必須[無料、フリーミアム、サブスクリプション、有料] |
| FreeTrial | 糸 | 価格が有料またはサブスクリプションの場合は必須[NO_FREE_TRIAL、FREE_TRIAL] |
| プロパティ | オブジェクト | プロパティ モジュール のメタデータを保持するオブジェクト |
| プライバシーポリシーが必要か | ブール値 | 必須 |
| プライバシーポリシーURL | 糸 | isPrivacyPolicyRequired = true の場合は必須 有効な URL である必要があります |
| Web サイト | 糸 | 有効な URI である必要があります。 |
| サポート連絡先情報 | 糸 | 有効な URL またはメール アドレスである必要があります。 |
| 認証メモ | 糸 | 推奨文字数の制限 = 2000 |
| カテゴリ | 糸 | 必須以下のカテゴリのリストを参照してください |
| サブカテゴリ | 糸 | 必須以下のサブカテゴリのリストを参照してください |
| 製品宣言 | オブジェクト | 必須 |
| システム機能が必要か | オブジェクトの配列 | [タッチ、キーボード、マウス、カメラ、NFC_HCE、NFC_Proximity、Bluetooth_LE、テレフォニー、マイク] |
| 必須 | ブール値 | 必須 |
| おすすめ | ブール値 | 必須 |
| ハードウェア項目タイプ | 糸 | 必須 |
| システム要件の詳細 | オブジェクトの配列 | [プロセッサ、グラフィックス、メモリ、DirectX、Video_Memory] |
| 最低要件 | 糸 | systemRequirementsText に必須、MaxLength = 200 hardwareItemType で使用できる値 = メモリ: [300MB、750MB、1GB、2GB、4GB、6GB、8GB、12GB、16GB、20GB] hardwareItemType = DirectX で使用できる値: [DX9, DX10, DX11, DX12-FEATURELEVEL11, DX12-FEATURELEVEL12] hardwareItemType = Video_Memory で使用できる値: [1GB, 2GB, 4GB, 6GB] |
| 推奨要件 | 糸 | systemRequirementsText に必須、MaxLength = 200 hardwareItemType で使用できる値 = メモリ: [300MB、750MB、1GB、2GB、4GB、6GB、8GB、12GB、16GB、20GB] hardwareItemType = DirectX で使用できる値: [DX9, DX10, DX11, DX12-FEATURELEVEL11, DX12-FEATURELEVEL12] hardwareItemType = Video_Memory で使用できる値: [1GB, 2GB, 4GB, 6GB] |
| ドライバーまたはNTに依存 | ブール値 | 必須 |
| アクセシビリティ対応 | ブール値 | 必須 |
| ペンとインクのサポート | ブール値 | 必須 |
| 一覧 | オブジェクト | 単一言語のモジュール・データをリストするオブジェクト |
| 言語 | 糸 | 必須 以下の言語のリストを参照してください |
| 説明 | 糸 | 必須 文字の制限 = 10000 |
| 新着情報 | 糸 | 文字数制限 = 1500 |
| ProductFeatures | 文字列の配列 | 機能ごとに 200 文字。最大20の機能 |
| 短い説明 | 糸 | 文字数制限 = 1000 |
| SearchTerms | 文字列の配列 | 検索語句ごとに 30 文字。最大 7 つの検索語句 すべての検索語で合計 21 個の一意の単語 |
| 追加ライセンス条項 | 糸 | 必須 文字の制限 = 10000 |
| 著作権 | 糸 | 文字制限 = 200 |
| 開発者 | 糸 | 文字制限 = 255 |
| 要件 | オブジェクトの配列 | 項目あたり 200 文字。最小と推奨の間で合計11項目まで] |
| 最小ハードウェア | 糸 | 文字制限 = 200 |
| 推奨ハードウェア | 糸 | 文字制限 = 200 |
| ContactInfo | 糸 | 文字制限 = 200 |
| 新規リスト追加 | 文字列の配列 | 以下の言語のリストを参照してください |
| 削除するリスト | 文字列の配列 | 以下の言語のリストを参照してください |
市場
テーブルの表示
|市場 |省略形 | |--------|--------------| |アフガニスタン |AF | |アルバニア |AL | |アルジェリア |DZ |アメリカ領サモア |AS | |アンドラ |AD | |アンゴラ |AO |アンギラ |AI | |南極 |AQ | |アンティグア・バーブーダ |AG |アルゼンチン |AR |アルメニア |AM | |アルバ |AW |オーストラリア |AU | |オーストリア |AT | |アゼルバイジャン |AZ | |バハマ |BS |バーレーン |BH |バングラデシュ |BD | |バルバドス |BB |ベラルーシ |BY | |ベルギー |BE | |ベリーズ |BZ |ベナン |BJ |バミューダ諸島 |BM | |ブータン |BT |ベネズエラボリバル共和国 |VE | |ボリビア |BO |ボネール島 |BQ |ボスニア・ヘルツェゴビナ |BA | |ボツワナ |BW | |ブーベ島 |BV |ブラジル |BR |イギリス領インド洋地域 |IO |イギリス領バージン諸島 |VG | |ブルネイ |BN |ブルガリア |BG | |ブルキナファソ |BF |ブルンジ |BI | |カンボジア |KH |カメルーン |CM | |カナダ |CA | |カーボベルデ |CV |ケイマン諸島 |KY |中央アフリカ共和国 |CF |チャド |TD | |チリ |CL |中国 |CN | |クリスマス島 |CX | |ココス諸島 |CC | |コロンビア |CO |コモロ |KM |コンゴ共和国 |CG |コンゴ共和国 |CD | |クック諸島 |CK |コスタリカ |CR | |クロアチア |HR | |キュラソー |CW |キプロス |CY | |チェコ共和国 |CZ |コートジボワール |CI | |デンマーク |DK |ジブチ |DJ |ドミニカ |DM | |ドミニカ共和国 |DO | |エクアドル |EC | |エジプト |EG | |エルサルバドル |SV |赤道ギニア |GQ |エリトリア |ER |エストニア |EE |エチオピア |ET | |フォークランド諸島 |FK |フェロー諸島 |FO | |フィジー |FJ |フィンランド |FI | |フランス |FR | |フランス領ギアナ |GF |フランス領ポリネシア |PF | |フランス南部と南極の土地 |TF | |ガボン |GA |ガンビア |GM |ジョージア |GE |ドイツ |DE | |ガーナ |GH |ジブラルタル |GI | |ギリシャ |GR |グリーンランド |GL |グレナダ |GD | |グアドループ |GP | |グアム |GU |グアテマラ |GT | |ガーンジー島 |GG |ギニア |GN |Guinea-Bissau |GW |ガイアナ |GY |ハイチ |HT |ハード島とマクドナルド諸島 |HM |バチカン市国 |VA | |ホンジュラス |HN |香港特別行政区 |HK |ハンガリー |HU | |アイスランド |IS | |インド |IN | |インドネシア |ID | |イラク |IQ | |アイルランド |IE | |イスラエル |IL | |イタリア |IT | |ジャマイカ |JM |日本 |JP | |ジャージー |JE | |ヨルダン |JO | |カザフスタン |KZ |ケニア |KE |キリバス |KI |韓国 |KR |クウェート |KW |キルギズスタン |KG |ラオス |LA | |ラトビア |LV |レバノン |LB | |レソト |LS | |リベリア |LR | |リビア |LY | |リヒテンシュタイン |LI |リトアニア |LT |ルクセンブルク |LU | |マカオ特別行政区 |MO |北マケドニア |MK |マダガスカル |MG |マラウイ |MW |マレーシア |MY | |モルディブ |MV | |マリ |ML | |マルタ |MT |マン島 |IM | |マーシャ諸島 |MH |マルティニーク |MQ |モーリタニア |MR | |モーリシャス |MU | |マイヨット |YT |メキシコ |MX | |ミクロネシア |FM |モルドバ |MD | |モナコ |MC | |モンゴル |MN |モンテネグル - ME | |モントセラト |MS | |モロッコ |MA | |モザンビーク |MZ |ミャンマー |MM |ナミビア |NA | |ナウル |NR |ネパール |NP | |オランダ |NL | |ニューカレドニア |NC |ニュージーランド |NZ |ニカラグア |NI |ニジェール |NE |ナイジェリア |NG | |ニウエ |NU |ノーフォーク島 |NF | |北マリアナ諸島 |MP | |ノルウェー |NO | |オマーン |OM | |パキスタン |PK |パラオ |PW | |パレスチナ自治政府 |PS | |パナマ |PA | |パプアニューギニア |PG | |パラグアイ |PY | |ペルー |PE | |フィリピン |PH | |ピトケアン諸島 |PN |ポーランド |PL | |ポルトガル |PT |カタール |QA | |レユニオン |RE | |ルーマニア |RO |ロシア |RU | |ルワンダ |RW |サン・バルテルミー |BL |セントヘレナ、アセンション、トリスタン・ダ・クーニャ |SH | |セントキッツとネイビス |KN |セントルシア |LC | |サン マルタン (フランス語) |MF | |サンピエール島とミクロン島 |PM | |セントビンセント・グレナディーン諸島 |VC | |サモア |WS | |サン・マリーノ |SM | |サウジアラビア |SA | |コロンビア |SN |セルビア |RS | |セーシェル |SC | |シエラレオネ |SL | |シンガポール |SG |シント・マールテン語 (オランダ語パート) |SX | |スロバキア |SK | |スロベニア |SI | |ソロモン諸島 |SB | |ソマリア |SO | |南アフリカ |ZA | |サウスジョージアと南サンドイッチ諸島 |GS | |スペイン |ES | |スリランカ |LK |スリナム |SR |スバールバル諸島とヤンマイエン |SJ | |スワジランド |SZ | |スウェーデン |SE | |スイス |CH | |サントメ・プリンシペ |ST | |台湾 |TW | |タジキスタン |TJ |タンザニア |TZ |タイ |TH | |Timor-Leste |TL |Tog - TG |トケラウ |TK |トンガ |TO | |トリニダード・トバグ - TT |チュニジア |TN |Türkiye |TR | |トルクメニスタン |TM |タークス・カイコス諸島 |TC |ツバル |テレビ |米国の小さな離島 |UM | |米領バージン諸島 |VI | |ウガンダ |UG |ウクライナ |UA |アラブ首長国連邦 |AE |イギリス |GB | |米国 |米国 | |ウルグアイ |UY |ウズベキスタン |UZ |バヌアツ |VU |ベトナム |VN | |ウォリスとフトゥナ |WF | |イエメン |YE | |ザンビア |ZM |ジンバブエ |ZW |オーランド諸島 |AX |カテゴリとサブカテゴリ
テーブルの表示
|カテゴリ |サブカテゴリ | |-----------------------|---------------| |BooksAndReference |電子書籍リーダー、フィクション、ノンフィクション、リファレンス | |ビジネス |会計と財務、コラボレーション、CRM、データと分析、ファイル管理、在庫と物流、法律と人事、プロジェクト管理、リモートデスクトップ、営業とマーケティング、時間と経費 | |DeveloperTools |データベース、デザインチュールズ、開発キット、ネットワーキング、参考資料とトレーニング、サーバー、ユーティリティ、ウェブホスティング |教育 |教育書籍とリファレンス、早期学習、指導ツール、言語、学習補助 | |エンターテイメント |(なし) | |フードとダイニング |(なし) | |政府と政治 |(なし) | |健康とフィットネス |(なし) | |キッズとファミリー |キッズとファミリー書籍とリファレンス、キッズとファミリーエンターテイメント、趣味とおもちゃ、スポーツと活動、キッズとファミリー旅行 | |ライフスタイル |オートモーティブ、DIY、ホームとガーデン、関係、特別興味、スタイルとファッション |医療 |(なし) | |MultimediaDesign |イラストとグラフィックデザイン、音楽制作、写真とビデオ制作 | |音楽 |(なし) | |ナビゲーションと地図 |(なし) | |ニュースと天気 |ニュース、天気 |個人金融 |銀行と投資、予算編成と税金 | |パーソナル化 |着信音とサウンド、テーマ、壁紙とロックスクリーン | |写真とビデオ |(なし) | |生産性 |(なし) | |セキュリティ |PC保護、個人セキュリティ | |ショッピング |(なし) | |ソーシャル |(なし) | |スポーツ |(なし) | |旅行 |市内ガイド、ホテル |ユーティリティとツール |バックアップと管理、ファイルマネージャー |言語
テーブルの表示
|言語名 |サポートされている言語コード | |---------------|--------------------------| |アフリカーンス語 |af, af-za | |アルバニア語 |sq, sq-al | |アムハラ語 |am, am-et | |アルメニア語 |hy, hy-am | |アッサム語 |as, as-in | |アゼルバイジャン語 |az-arab, az-arab-az, az-cyrl, az-cyrl-az, az-latn, az-latn-az | |バスク語 (バスク) |eu, eu-es | |ベラルーシ語 |be, be-by | |ベンガル語 |bn, bn-bd, bn-in | |ボスニア語 |bs, bs-cyrl, bs-cyrl-ba, bs-latn, bs-latn-ba | |ブルガリア語 |bg, bg-bg | |カタロニア語 |ca, ca-es, ca-es-バレンシア | |チェロキー語 |chr-cher, chr-cher-us, chr-latn | |中国語 (簡体字) |zh-Hans, zh-cn, zh-hans-cn, zh-sg, zh-hans-sg | |中国語 (繁体字) |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 | |クロアチア語 |hr, hr-hr, hr-ba | |チェコ語 |cs, cs-cz | |デンマーク語 |da, da-dk | |ダリー語 |prs, prs-af, prs-arab | |オランダ語 |nl, nl-nl, nl-be | |英語 |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 | |エストニア語 |et, et-ee | |フィリピン語 |fil, fil-latn, fil-ph | |フィンランド語 |fi, fi-fi | |フランス語 |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 | |ガリシア語 |gl, gl-es | |ジョージア語 |ka, ka-ge | |ドイツ語 |de, de-at, de-ch, de-de, de-lu, de-li | |ギリシャ語 |el, el-gr | |グジャラート語 |gu, gu-in | |ハウサ語 |ha, ha-latn, ha-latn-ng | |ヘブライ語 |he, he-il | |ヒンディー語 |hi, hi-in | |ハンガリー語 |hu, hu-hu | |アイスランド語 |is, is-is | |イグボ語 |ig-latn, ig-ng | |インドネシア語 |id, id-id | |イヌクティトゥット語 (ラテン) |iu-cans, iu-latn, iu-latn-ca | |アイルランド語 |ga, ga-ie | |isiXhosa |xh, xh-za | |isiZulu |zu, zu-za | |イタリア語 |it, it-it, it-ch | |日本語 |ja, ja-jp | |カンナダ語 |kn, kn-in | |カザフ語 |kk, kk-kz | |クメール語 |km, km-kh | |キチェ語 |quc-latn, qut-gt, qut-latn | |キニャルワンダ語 |rw, rw-rw | |スワヒリ語 |sw, sw-ke | |コンカニ語 |kok, kok-in | |韓国語 |ko, ko-kr | |クルド語 |ku-arab, ku-arab-iq | |キルギス語 |ky-kg, ky-cyrl | |ラオ語 |lo, lo-la | |ラトビア語 |lv, lv-lv | |リトアニア語 |lt, lt-lt | |ルクセンブルク語 |lb, lb-lu | |マケドニア語 |mk, mk-mk | |マレー語 |ms, ms-bn, ms-my | |マラヤラム語 |ml, ml-in | |マルタ語 |mt, mt-mt | |マオリ語 |mi, mi-latn, mi-nz | |マラーティー語 |mr, mr-in | |モンゴル語 (キリル文字) |mn-cyrl, mn-mong, mn-mn, mn-phag | |ネパール語 |ne, ne-np | |ノルウェー語 |nb, nb-no, nn, nn-no, no, no-no | |オディア語 |or, or-in | |ペルシャ語 |fa, fa-ir | |ポーランド語 |pl, pl-pl | |ポルトガル語 (ブラジル) |pt-br | |ポルトガル語 (ポルトガル) |pt, pt-pt | |パンジャーブ語 |pa, pa-arab, pa-arab-pk, pa-deva, pa-in | |ケチュア語 |quz, quz-bo, quz-ec, quz-pe | |ルーマニア語 |ro, ro-ro | |ロシア語 |ru, ru-ru | |スコットランド・ゲール語 |gd-gb, gd-latn | |セルビア語 (ラテン文字) |sr-Latn, sr-latn-cs, sr, sr-latn-ba, sr-latn-me, sr-latn-rs | |セルビア語 (キリル文字) |sr-cyrl, sr-cyrl-ba, sr-cyrl-cs, sr-cyrl-me, sr-cyrl-rs | |セソト・サ・レボア |nso, nso-za | |ツワナ語 |tn, tn-bw, tn-za | |シンド語 |sd-arab, sd-arab-pk, sd-deva | |シンハラ語 |si, si-lk | |スロバキア語 |sk, sk-sk | |スロベニア語 |sl, sl-si | |スペイン語 |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 | |スウェーデン語 |sv, sv-se, sv-fi | |タジク語 (キリル文字) |tg-arab, tg-cyrl, tg-cyrl-tj, tg-latn | |タミル語 |ta, ta-in | |タタール語 |tt-arab, tt-cyrl, tt-latn, tt-ru | |テルグ語 |te, te-in | |タイ語 |th, th-th | |ティグリニャ語 |ti, ti-et | |トルコ語 |tr, tr-tr | |トルクメン語 |tk-cyrl, tk-latn, tk-tm, tk-latn-tr, tk-cyrl-tr | |ウクライナ語 |uk, uk-ua | |ウルドゥー語 |ur, ur-pk | |ウイグル語 |ug-arab, ug-cn, ug-cyrl, ug-latn | |ウズベク語 (ラテン文字) |uz, uz-cyrl, uz-latn, uz-latn-uz | |ベトナム語 |vi, vi-vn | |ウェールズ語 |cy, cy-gb | |ウォロフ語 |wo, wo-sn | |ヨルバ語 |yo-latn, yo-ng |要求のサンプル
{
"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"]
}
応答ヘッダー
| ヘッダー | 値 |
|---|---|
X-Correlation-ID |
各要求の GUID の種類の一意の ID。 これは、問題を分析するためにサポートチームと共有できます。 |
Retry-After |
レート制限のためにクライアントが API を再度呼び出すまでに待機する必要がある時間 (秒単位) |
応答パラメーター
| 名前 | タイプ | 説明 |
|---|---|---|
| IsSuccess | ブール値 | |
| エラー | オブジェクトの配列 | エラーまたは警告メッセージのリスト (存在する場合) |
| コード | 糸 | メッセージのエラーコード |
| メッセージ | 糸 | エラーの説明 |
| ターゲット | 糸 | エラーの発生元エンティティ |
| 応答データ | オブジェクト | 要求の実際の応答ペイロードが含まれます |
| ポーリングURL | 糸 | 進行中の送信のステータスを取得するためのポーリングURL |
| 進行中の提出ID | 糸 | 既に進行中の提出書類の提出書類 ID |
サンプル応答
{
"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 を取得する。
現在の下書き提出でパッケージの詳細を取得します。
パス [All Packages]: /submission/v1/product/{productId}/packages
メソッド: GET
パス [Single Package]: /submission/v1/product/{productId}/packages/{packageId}
メソッド: GET
パス パラメーター
| 名前 | 説明 |
|---|---|
| productId | 製品のパートナー センター ID |
| packageId | フェッチするパッケージの一意の ID |
必須のヘッダー
| ヘッダー | 値 |
|---|---|
Authorization: Bearer <Token> |
パートナー センター アカウントに登録されている Microsoft Entra ID アプリ ID の使用 |
X-Seller-Account-Id |
パートナー センター アカウントの販売者 ID |
応答ヘッダー
| ヘッダー | 値 |
|---|---|
X-Correlation-ID |
各要求の GUID の種類の一意の ID。 これは、問題を分析するためにサポートチームと共有できます。 |
Retry-After |
レート制限のために API を再度呼び出す前にクライアントが待機する必要がある時間 (秒単位)。 |
応答パラメーター
| 名前 | タイプ | 説明 |
|---|---|---|
| IsSuccess | ブール値 | |
| エラー | オブジェクトの配列 | エラーまたは警告メッセージのリスト (存在する場合) |
| コード | 糸 | メッセージのエラーコード |
| メッセージ | 糸 | エラーの説明 |
| ターゲット | 糸 | エラーの発生元のエンティティ |
| 応答データ | オブジェクト | |
| パッケージ | オブジェクトの配列 | パッケージ モジュール データを保持するオブジェクト |
| packageId | 糸 | |
| packageUrl: | 糸 | |
| 言語 | 文字列の配列 | |
| アーキテクチャ | 文字列の配列 | [Neutral, X86, X64, Arm, Arm64] |
| isSilentInstall | ブール値 | これは、インストーラーがスイッチを必要とせずにサイレントモードで実行されている場合はtrueとしてマークするか、そうでない場合はfalseにする必要があります。 |
| インストーラーのパラメーター | 糸 | |
| genericDocUrl | 糸 | |
| エラー詳細 | オブジェクトの配列 | |
| エラーシナリオ | 糸 | |
| エラーシナリオの詳細 | オブジェクトの配列 | |
| エラー値 | 糸 | |
| エラーURL | 糸 | |
| パッケージタイプ | 糸 |
応答のサンプル
{
"isSuccess": true,
"errors": [{
"code": "badrequest",
"message": "Error Message 1",
"target": "listings"
}, {
"code": "warning",
"message": "Warning Message 1",
"target": "properties"
}],
"responseData":{
"packages":[{
"packageId": "pack0832",
"packageUrl": "https://www.contoso.com/downloads/1.1/setup.exe",
"languages": ["en-us"],
"architectures": ["X86"],
"isSilentInstall": true,
"installerParameters": "/s",
"genericDocUrl": "https://docs.contoso.com/doclink",
"errorDetails": [{
"errorScenario": "rebootRequired",
"errorScenarioDetails": [{
"errorValue": "ERR001001",
"errorUrl": "https://errors.contoso.com/errors/ERR001001"
}]
}],
"packageType": "exe",
}]
}
}
現在のドラフトパッケージの更新 API
現在の下書き提出のパッケージの詳細を更新します。
パス [完全なモジュール更新]: /submission/v1/product/{productId}/packages
メソッド: PUT
パス [Single Package Patch Update]: /submission/v1/product/{productId}/packages/{packageId}
メソッド: パッチ
API ビヘイビアー
完全モジュール更新 API の場合、すべてのフィールドの完全な更新の要求には、パッケージデータ全体が存在する必要があります。 リクエストに存在しないフィールドは、そのデフォルト値を使用して、その特定のモジュールの現在の値を上書きします。 これにより、既存のすべてのパッケージが、要求からの新しいパッケージのセットで上書きされます。 これにより、パッケージ ID が再生成され、ユーザーは最新のパッケージ ID に対して GET Packages API を呼び出す必要があります。
単一パッケージ・パッチ更新APIの場合、特定のパッケージに対して更新されるフィールドのみがリクエストに存在する必要があります。 リクエストからのこれらのフィールド値は既存の値を上書きし、リクエストに存在しない他のすべてのフィールドは、その特定のパッケージの現在のフィールドと同じままにします。 セット内の他のパッケージはそのまま残ります。
パス パラメーター
| 名前 | 説明 |
|---|---|
| productId | 製品のパートナー センター ID |
| packageId | パッケージの一意の ID |
必須のヘッダー
| ヘッダー | 値 |
|---|---|
Authorization: Bearer <Token> |
パートナー センター アカウントに登録されている Microsoft Entra ID アプリ ID の使用 |
X-Seller-Account-Id |
パートナー センター アカウントの販売者 ID |
要求パラメーター
| 名前 | タイプ | 説明 |
|---|---|---|
| パッケージ | オブジェクトの配列 | パッケージモジュールデータを保持するオブジェクト [モジュール全体の更新にのみ必要] |
| packageUrl: | 糸 | 必須 |
| 言語 | 文字列の配列 | 必須 |
| アーキテクチャ | 文字列の配列 | 必須 1 つのアーキテクチャ (Neutral、X86、X64、Arm、Arm64) を含める必要があります |
| isSilentInstall | ブール値 | 必須 これはインストーラーがスイッチを必要とせずにサイレントモードで実行されている場合は true としてマークするか、そうでない場合は false にする必要があります |
| インストーラーのパラメーター | 糸 | isSilentInstall が false の場合は必須 |
| genericDocUrl | 糸 | packageType が exe の場合は必須 EXE タイプのインストーラーのカスタム エラー コードの詳細を含むドキュメントへのリンク |
| エラー詳細 | オブジェクトの配列 | EXE タイプのインストーラーのカスタム エラー コードと詳細を保持するメタデータ。 |
| エラーシナリオ | 糸 | 具体的なエラーシナリオを特定します。 [インストールがユーザーによってキャンセルされました, アプリケーションは既に存在します, インストールは既に進行中です, ディスクの空き領域が満杯です, 再起動が必要です, ネットワークエラー, インストール中にパッケージが拒否されました, インストール成功, その他] |
| エラーシナリオの詳細 | オブジェクトの配列 | |
| エラー値 | 糸 | インストール中に表示される可能性のあるエラーコード |
| エラーURL | 糸 | エラーの詳細が記載された URL |
| パッケージタイプ | 糸 | 必須 [exe, msi] |
サンプル要求 [Full Module Update]
{
"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",
}]
}
サンプル要求 [Single Package Patch Update]
{
"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",
}
応答ヘッダー
| ヘッダー | 値 |
|---|---|
X-Correlation-ID |
各要求の GUID の種類の一意の ID。 これは、問題を分析するためにサポートチームと共有できます。 |
Retry-After |
レート制限のために API を再度呼び出す前にクライアントが待機する必要がある時間 (秒単位)。 |
応答パラメーター
| 名前 | タイプ | 説明 |
|---|---|---|
| IsSuccess | ブール値 | |
| エラー | オブジェクトの配列 | [エラーまたは警告メッセージのリスト (存在する場合)] |
| コード | 糸 | メッセージのエラーコード |
| メッセージ | 糸 | エラーの説明 |
| ターゲット | 糸 | エラーの発生元エンティティ |
| 応答データ | オブジェクト | |
| ポーリングURL | 糸 | [すでに進行中の提出の場合に提出ステータスを取得するためのポーリングURL] |
| 進行中の提出ID | 糸 | [既に進行中の提出書類の提出書類 ID] |
応答のサンプル
{
"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
現在の下書き申請で、パッケージ更新 API を使用して更新された新しいパッケージ セットをコミットします。 この API は、パッケージのアップロードを追跡するためのポーリング URL を返します。
パス: /submission/v1/product/{productId}/packages/commit
メソッド: POST
パス パラメーター
| 名前 | 説明 |
|---|---|
| productId | 製品のパートナー センター ID |
必須のヘッダー
| ヘッダー | 値 |
|---|---|
Authorization: Bearer <Token> |
パートナー センター アカウントに登録されている Microsoft Entra ID アプリ ID の使用 |
X-Seller-Account-Id |
パートナー センター アカウントの販売者 ID |
応答ヘッダー
| ヘッダー | 値 |
|---|---|
X-Correlation-ID |
各要求の GUID の種類の一意の ID。 これは、問題を分析するためにサポートチームと共有できます。 |
Retry-After |
レート制限のために API を再度呼び出す前にクライアントが待機する必要がある時間 (秒単位)。 |
応答パラメーター
| 名前 | タイプ | 説明 |
|---|---|---|
| IsSuccess | ブール値 | |
| エラー | オブジェクトの配列 | [エラーまたは警告メッセージのリスト (存在する場合)] |
| コード | 糸 | メッセージのエラーコード |
| メッセージ | 糸 | エラーの説明 |
| ターゲット | 糸 | エラーの発生元のエンティティ |
| 応答データ | オブジェクト | |
| ポーリングURL | 糸 | [パッケージのアップロードのステータスを取得するためのポーリングURL、またはすでに進行中のサブミッションの場合のサブミッションステータス] |
| 進行中の提出ID | 糸 | [既に進行中の提出書類の提出書類 ID] |
応答のサンプル
{
"isSuccess": true,
"errors": [{
"code": "badrequest",
"message": "Error Message 1",
"target": "listings"
}, {
"code": "warning",
"message": "Warning Message 1",
"target": "properties"
}],
"responseData": {
"pollingUrl": "/submission/v1/product/{productId}/status",
"ongoingSubmissionId": ""
}
}
現在のドラフト リスト アセット API を取得する
現在の下書き提出でリスト資産の詳細をフェッチします。
パス: /submission/v1/product/{productId}/listings/assets?languages={languages}
メソッド: GET
パス パラメーター
| 名前 | 説明 |
|---|---|
| productId | 製品のパートナー センター ID |
クエリ パラメーター
| 名前 | 説明 |
|---|---|
| 言語 | [オプション]リスト言語は、コンマ区切りの文字列としてフィルタリングされます (最大 200 言語の制限)。 存在しない場合は、最初の 200 個の使用可能なリスト言語のアセットデータが取得されます。 (例: "en-us、en-gb") |
必須のヘッダー
| ヘッダー | 値 |
|---|---|
Authorization: Bearer <Token> |
パートナー センター アカウントに登録されている Microsoft Entra ID アプリ ID の使用 |
X-Seller-Account-Id |
パートナー センター アカウントの販売者 ID |
応答ヘッダー
| ヘッダー | 値 |
|---|---|
X-Correlation-ID |
各要求の GUID の種類の一意の ID。 これは、問題を分析するためにサポートチームと共有できます。 |
Retry-After |
レート制限のために API を再度呼び出す前にクライアントが待機する必要がある時間 (秒単位)。 |
応答パラメーター
| 名前 | タイプ | 説明 |
|---|---|---|
| IsSuccess | ブール値 | |
| エラー | オブジェクトの配列 | エラーまたは警告メッセージのリスト (存在する場合) |
| コード | 糸 | メッセージのエラーコード |
| メッセージ | 糸 | エラーの説明 |
| ターゲット | 糸 | エラーの発生元のエンティティ |
| 応答データ | オブジェクト | |
| 資産のリスト化 | オブジェクトの配列 | 各言語のアセット詳細の一覧表示 |
| 言語 | 糸 | |
| 店舗のロゴ | オブジェクトの配列 | |
| スクリーンショット | オブジェクトの配列 | |
| ID | 糸 | |
| アセットURL | 糸 | 有効な URI である必要があります。 |
| 画像サイズ | オブジェクト | |
| 幅 | 整数 | |
| 高さ | 整数 |
応答のサンプル
{
"isSuccess": true,
"errors": [{
"code": "badrequest",
"message": "Error Message 1",
"target": "listings"
}, {
"code": "warning",
"message": "Warning Message 1",
"target": "properties"
}],
"responseData":{
"listingAssets": [{
"language": "en-us",
"storeLogos": [
{
"id": "1234567890abcdefgh",
"assetUrl": "https://contoso.com/blob=1234567890abcdefgh",
"imageSize": {
"width": 2160,
"height": 2160
}
}
],
"screenshots": [
{
"id": "1234567891abcdefgh",
"assetUrl": "https://contoso.com/blob=1234567891abcdefgh",
"imageSize": {
"width": 2160,
"height": 2160
}
}
]
}]
}
}
リスティングアセット API の作成
現在の下書きの提出の下に新しいリストアセットのアップロードを作成します。
リスティング資産の更新
EXE または MSI アプリ用の Microsoft Store 申請 API では、個々の画像資産のアップロードごとに、ランタイムで生成された SAS URL を BLOB ストアに使用し、アップロードが成功した後の Commit API 呼び出しを使用します。 リスティングアセットを更新し、リスティングモジュールでロケールを追加/削除できるようにするには、次のアプローチを使用できます。
- Create Listing Asset APIを使用して、アセットのアップロードに関するリクエストを、アセットの言語、種類、数とともに送信します。
- 要求された資産の数に基づいて、資産 ID はオンデマンドで作成され、短期間の SAS URL が作成され、資産の種類の応答本文で返送されます。 この URL を使用して、HTTP クライアントを使用して特定の種類の画像アセットをアップロードできます [Put Blob (REST API) - Azure Storage |Microsoft Docs] です。
- アップロード後、Commit Listing Assets API を使用して、以前の API 呼び出しで以前に受信した新しいアセット ID 情報も送信できます。 単一のAPIは、検証後にリスト資産データを内部的にコミットします。
- このアプローチは、リクエストで送信されている特定の言語のアセットタイプの以前の画像のセット全体を事実上上書きします。 そのため、以前にアップロードされたアセットは削除されます。
パス: /submission/v1/product/{productId}/listings/assets/create
メソッド: POST
パス パラメーター
| 名前 | 説明 |
|---|---|
| productId | 製品のパートナー センター ID |
必須のヘッダー
| ヘッダー | 説明 |
|---|---|
Authorization: Bearer <Token> |
パートナー センター アカウントに登録されている Microsoft Entra ID アプリ ID の使用 |
X-Seller-Account-Id |
パートナー センター アカウントの販売者 ID |
要求パラメーター
| 名前 | タイプ | 説明 |
|---|---|---|
| 言語 | 糸 | 必須 |
| アセット作成リクエスト | オブジェクト | 必須 |
| スクリーンショット | 整数 | ISV がスクリーンショットを更新したり、新しい登録言語を追加したりする必要がある場合は必須 [1 - 10] |
| ロゴ | 整数 | ISV がロゴを更新したり、新しい登録情報言語を追加したりする必要がある場合に必要 [1 または 2] |
応答ヘッダー
| ヘッダー | 説明 |
|---|---|
X-Correlation-ID |
各要求の GUID の種類の一意の ID。 これは、問題を分析するためにサポートチームと共有できます。 |
Retry-After |
レート制限のために API を再度呼び出す前にクライアントが待機する必要がある時間 (秒単位)。 |
応答パラメーター
| 名前 | タイプ | 説明 |
|---|---|---|
| IsSuccess | ブール値 | |
| エラー | オブジェクトの配列 | エラーまたは警告メッセージのリスト (存在する場合) |
| コード | 糸 | メッセージのエラーコード |
| メッセージ | 糸 | エラーの説明 |
| ターゲット | 糸 | エラーの発生元のエンティティ |
| 応答データ | オブジェクト | |
| 資産のリスト化 | オブジェクト | アップロードするStoreLogosとスクリーンショットの詳細を含むオブジェクト |
| 言語 | 糸 | |
| 店舗のロゴ | オブジェクトの配列 | |
| スクリーンショット | オブジェクトの配列 | |
| ID | 糸 | |
| プライマリアセットアップロードURL | 糸 | Azure Blob REST API を使用して登録資産をアップロードするためのプライマリ URL |
| セカンダリ資産アップロードURL | 糸 | Azure Blob REST API を使用して登録資産をアップロードするためのセカンダリ URL |
| httpMethod | HTTP メソッド | HTTP メソッドは、アセットのアップロード URL (プライマリまたはセカンダリ) を介してアセットをアップロードするために使用する必要があります |
| HTTPヘッダー | オブジェクト | アセットアップロード URL へのアップロード API 呼び出しに存在する 要求された ヘッダーとしてのキーを持つオブジェクト。 値が空でない場合、ヘッダーには特定の値が必要です。 それ以外の場合、値は API 呼び出し中に計算されます。 |
応答のサンプル
{
"isSuccess": true,
"errors": [{
"code": "badrequest",
"message": "Error Message 1",
"target": "listings"
}, {
"code": "warning",
"message": "Warning Message 1",
"target": "properties"
}],
"responseData": {
"listingAssets": {
"language": "en-us",
"storeLogos":[{
"id": "1234567890abcdefgh",
"primaryAssetUploadUrl": "https://contoso.com/upload?blob=1234567890abcdefgh&sig=12345",
"secondaryAssetUploadUrl": "https://contoso.com/upload?blob=0987654321abcdfger&sig=54326",
"httpMethod": "PUT",
"httpHeaders": {"Required Header Name": "Header Value"}
}],
"screenshots":[{
"id": "0987654321abcdfger",
"primaryAssetUploadUrl": "https://contoso.com/upload?blob=0987654321abcdfger&sig=54321",
"secondaryAssetUploadUrl": "https://contoso.com/upload?blob=0987654321abcdfger&sig=54322",
"httpMethod": "PUT",
"httpHeaders": {"Required Header Name": "Header Value"}
}]
}
}
}
コミット リスティングアセット API
現在の下書き送信で、Create Assets API の詳細を使用してアップロードされた新しいリストアセットをコミットします。
パス: /submission/v1/product/{productId}/listings/assets/commit
メソッド: PUT
パス パラメーター
| 名前 | 説明 |
|---|---|
| productId | 製品のパートナー センター ID |
必須のヘッダー
| ヘッダー | 説明 |
|---|---|
Authorization: Bearer <Token> |
パートナー センター アカウントに登録されている Microsoft Entra ID アプリ ID の使用 |
X-Seller-Account-Id |
パートナー センター アカウントの販売者 ID |
要求パラメーター
| 名前 | タイプ | 説明 |
|---|---|---|
| 資産のリスト化 | オブジェクト | |
| 言語 | 糸 | |
| 店舗のロゴ | オブジェクトの配列 | |
| スクリーンショット | オブジェクトの配列 | |
| ID | 糸 | ユーザーがGet Current Listing Assets APIから保持する既存のID、またはCreate Listing Assets APIで新しいアセットがアップロードされた新しいIDのいずれかである必要があります。 |
| アセットURL | 糸 | ユーザーがGet Current Listing Assets APIから保持する既存のアセットのURL、またはCreate Listing Assets APIで新しいアセットがアップロードされたアップロードURL - プライマリまたはセカンダリのいずれかである必要があります。 有効な URI である必要があります。 |
要求のサンプル
{
"listingAssets": {
"language": "en-us",
"storeLogos": [
{
"id": "1234567890abcdefgh",
"assetUrl": "https://contoso.com/blob=1234567890abcdefgh",
}
],
"screenshots": [
{
"id": "1234567891abcdefgh",
"assetUrl": "https://contoso.com/blob=1234567891abcdefgh",
}
]
}
}
応答ヘッダー
| ヘッダー | 説明 |
|---|---|
X-Correlation-ID |
各要求の GUID の種類の一意の ID。 これは、問題を分析するためにサポートチームと共有できます。 |
Retry-After |
レート制限のために API を再度呼び出す前にクライアントが待機する必要がある時間 (秒単位)。 |
応答パラメーター
| 名前 | タイプ | 説明 |
|---|---|---|
| IsSuccess | ブール値 | |
| エラー | オブジェクトの配列 | エラーまたは警告メッセージのリスト (存在する場合) |
| コード | 糸 | メッセージのエラーコード |
| メッセージ | 糸 | エラーの説明 |
| ターゲット | 糸 | エラーの発生元のエンティティ |
| 応答データ | オブジェクト | |
| ポーリングURL | 糸 | 進行中の送信の状態を取得するためのポーリング URL |
| 進行中の提出ID | 糸 | 既に進行中の提出書類の提出書類 ID |
応答のサンプル
{
"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
送信前にモジュールの準備状況を確認するための API。 また、パッケージのアップロード状態も検証します。
パス: /submission/v1/product/{productId}/status
メソッド: GET
パス パラメーター
| 名前 | 説明 |
|---|---|
| productId | 製品のパートナー センター ID |
必須のヘッダー
| ヘッダー | 説明 |
|---|---|
Authorization: Bearer <Token> |
パートナー センター アカウントに登録されている Microsoft Entra ID アプリ ID の使用 |
X-Seller-Account-Id |
パートナー センター アカウントの販売者 ID |
応答ヘッダー
| ヘッダー | 説明 |
|---|---|
X-Correlation-ID |
各要求の GUID の種類の一意の ID。 これは、問題を分析するためにサポートチームと共有できます。 |
Retry-After |
レート制限のために API を再度呼び出す前にクライアントが待機する必要がある時間 (秒単位)。 |
応答パラメーター
| 名前 | タイプ | 説明 |
|---|---|---|
| IsSuccess | ブール値 | |
| エラー | オブジェクトの配列 | エラーまたは警告メッセージのリスト (存在する場合) |
| コード | 糸 | メッセージのエラーコード |
| メッセージ | 糸 | エラーの説明 |
| ターゲット | 糸 | エラーの発生元のエンティティ |
| 応答データ | オブジェクト | |
| isReady | ブール値 | パッケージのアップロードを含め、すべてのモジュールが準備完了状態にあるかどうかを示します。 |
| 進行中の提出ID | 糸 | 既に進行中の提出書類の提出書類 ID |
応答のサンプル
{
"isSuccess": true,
"errors": [{
"code": "badrequest",
"message": "Error Message 1",
"target": "listings"
}, {
"code": "warning",
"message": "Warning Message 1",
"target": "properties"
}],
"responseData": {
"isReady": true,
"ongoingSubmissionId": ""
}
}
申請 API の作成
MSI または EXE アプリの現在の下書きから申請を作成します。 API チェック:
- アクティブな送信の場合、アクティブな送信が存在する場合、エラー メッセージが表示されて失敗します。
- すべてのモジュールが提出書類を作成する準備完了状態にある場合。
- 申請の各フィールドは、ストアの要件に従って検証されます
パス:/submission/v1/product/{productId}/submit
メソッド: POST
パス パラメーター
| 名前 | 説明 |
|---|---|
| productId | 製品のパートナー センター ID |
必須のヘッダー
| ヘッダー | 説明 |
|---|---|
Authorization: Bearer <Token> |
パートナー センター アカウントに登録されている Microsoft Entra ID アプリ ID の使用 |
X-Seller-Account-Id |
パートナー センター アカウントの販売者 ID |
応答ヘッダー
| ヘッダー | 説明 |
|---|---|
X-Correlation-ID |
各要求の GUID の種類の一意の ID。 これは、問題を分析するためにサポートチームと共有できます。 |
Retry-After |
レート制限のために API を再度呼び出す前にクライアントが待機する必要がある時間 (秒単位)。 |
応答パラメーター
| 名前 | タイプ | 説明 |
|---|---|---|
| IsSuccess | ブール値 | |
| エラー | オブジェクトの配列 | エラーまたは警告メッセージのリスト (存在する場合) |
| コード | 糸 | メッセージのエラーコード |
| メッセージ | 糸 | エラーの説明 |
| ターゲット | 糸 | エラーの発生元のエンティティ |
| 応答データ | オブジェクト | |
| ポーリングURL | 糸 | 送信用のパッケージのアップロードなど、モジュールの準備状況を取得するためのポーリング URL |
| サブミッションID | 糸 | 新しく作成されたサブミッションの ID |
| 進行中の提出ID | 糸 | 既に進行中の提出書類の提出書類 ID |
応答のサンプル
{
"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
申請状況を確認するための API。
パス: /submission/v1/product/{productId}/submission/{submissionId}/status
メソッド: GET
パス パラメーター
| 名前 | 説明 |
|---|---|
| productId | 製品のパートナー センター ID |
必須のヘッダー
| ヘッダー | 説明 |
|---|---|
Authorization: Bearer <Token> |
パートナー センター アカウントに登録されている Microsoft Entra ID アプリ ID の使用 |
X-Seller-Account-Id |
パートナー センター アカウントの販売者 ID |
応答ヘッダー
| ヘッダー | 説明 |
|---|---|
X-Correlation-ID |
各要求の GUID の種類の一意の ID。 これは、問題を分析するためにサポートチームと共有できます。 |
Retry-After |
レート制限のために API を再度呼び出す前にクライアントが待機する必要がある時間 (秒単位)。 |
応答パラメーター
| 名前 | タイプ | 説明 |
|---|---|---|
| IsSuccess | ブール値 | |
| エラー | オブジェクトの配列 | エラーまたは警告メッセージのリスト (存在する場合) |
| コード | 糸 | メッセージのエラーコード |
| メッセージ | 糸 | エラーの説明 |
| ターゲット | 糸 | エラーの発生元のエンティティ |
| 応答データ | オブジェクト | |
| 公開状況 | 糸 | 提出書類の発行ステータス - [進行中、公開済み、失敗、不明] |
| 失敗しました | ブール値 | 公開が失敗し、再試行されないかどうかを示します |
応答のサンプル
{
"isSuccess": true,
"errors": [{
"code": "badrequest",
"message": "Error Message 1",
"target": "listings"
}, {
"code": "warning",
"message": "Warning Message 1",
"target": "properties"
}],
"responseData": {
"publishingStatus": "INPROGRESS",
"hasFailed": false
}
}
コード例
次の記事では、さまざまなプログラミング言語で Microsoft Store 申請 API を使用する方法を示す詳細なコード例を示します。
C# サンプル: MSI または EXE アプリ用の Microsoft Store 申請 API
この記事では、MSI または EXE アプリ用の Microsoft Store 申請 API を使用する方法を示す C# コード例を示します。 各例を確認して、それぞれが対応するタスクについて詳しく知ることができます。また、この記事のすべてのコード例を使って、コンソール アプリケーションをビルドすることもできます。
前提条件 これらの例では、次のライブラリを使用します。
- Newtonsoft の Newtonsoft.Json NuGet パッケージ。
メイン プログラム 次の例では、この記事の他のメソッド例を呼び出すコマンド ライン プログラムを実装して、Microsoft Store 申請 API を使用するさまざまな方法を示します。 このプログラムを自分の用途に適合させるには:
- 販売者 ID プロパティをパートナー センター アカウントの販売者 ID に割り当てます。
- アプリケーション ID プロパティを、管理するアプリの ID に割り当てます。
- クライアント ID プロパティと クライアントシークレット プロパティをアプリのクライアント ID とキーに割り当て、トークンエンドポイント URL の テナント ID 文字列をアプリのテナント ID に置き換えます。 詳細については、「Microsoft Entra ID アプリケーションをパートナー センター アカウントに関連付ける方法」を参照してください。
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();
}
}
}
C# を使用したクライアント構成ヘルパー クラス
サンプル アプリでは、ClientConfiguration ヘルパー クラスを使用して、Microsoft Entra ID Directory データとアプリ データを、Microsoft Store 申請 API を使用する各サンプル メソッドに渡します。
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; }
}
}
C# を使用してアプリの申請を作成する。
次の例では、Microsoft Store 申請 API のいくつかのメソッドを使用してアプリの申請を更新するクラスを実装します。
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.
}
}
}
C# を使用した IngestionClient ヘルパー クラス
インジェスト クライアント クラスには、サンプル アプリ内の他のメソッドによって次のタスクを実行するために使用されるヘルパー メソッドが用意されています。
- Microsoft Store 申請 API でメソッドを呼び出すために使用できる Microsoft Entra ID アクセス トークンを取得します。 トークンを取得した後、Microsoft Store 申請 API の呼び出しでこのトークンを使用できるのは、その有効期限が切れるまでの 60 分間です。 トークンの有効期限が切れた後は、新しいトークンを生成できます。
- Microsoft Store 申請 API の HTTP 要求を処理します。
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;
}
}
}
Node.js サンプル: MSI または EXE アプリ用の Microsoft Store 申請 API
この記事では、MSI または EXE アプリ用の Microsoft Store 申請 API の使用方法を示す Node.js コード例を示します。 各例を確認して、それぞれが対応するタスクについて詳しく知ることができます。また、この記事のすべてのコード例を使って、コンソール アプリケーションをビルドすることもできます。
前提条件 これらの例では、次のライブラリを使用します。
- node-fetch v2 [npm install node-fetch@2]
node.js を使用してアプリの申請を作成する
次の例では、この記事の他のサンプル メソッドを呼び出して、Microsoft Store 申請 API を使用するさまざまな方法を示します。 このプログラムを自分の用途に適合させるには:
- 販売者 ID プロパティをパートナー センター アカウントの販売者 ID に割り当てます。
- アプリケーション ID プロパティを、管理するアプリの ID に割り当てます。
- クライアント ID プロパティと クライアントシークレット プロパティをアプリのクライアント ID とキーに割り当て、トークンエンドポイント URL の テナント ID 文字列をアプリのテナント ID に置き換えます。 詳細については、「Microsoft Entra ID アプリケーションをパートナー センター アカウントに関連付ける方法」を参照してください。
次の例では、Microsoft Store 申請 API のいくつかのメソッドを使用してアプリの申請を更新するクラスを実装します。
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();
クライアント構成 ヘルパー
サンプル アプリでは、ClientConfiguration ヘルパー クラスを使用して、Microsoft Entra ID Directory データとアプリ データを、Microsoft Store 申請 API を使用する各サンプル メソッドに渡します。
/** 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;
Node.js を使用した インジェストクライアント ヘルパー
インジェスト クライアント クラスには、サンプル アプリ内の他のメソッドによって次のタスクを実行するために使用されるヘルパー メソッドが用意されています。
- Microsoft Store 申請 API でメソッドを呼び出すために使用できる Microsoft Entra ID アクセス トークンを取得します。 トークンを取得した後、Microsoft Store 申請 API の呼び出しでこのトークンを使用できるのは、その有効期限が切れるまでの 60 分間です。 トークンの有効期限が切れた後は、新しいトークンを生成できます。
- Microsoft Store 申請 API の HTTP 要求を処理します。
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;
追加のヘルプ
Microsoft Store 申請 API について質問がある場合、またはこの API を使用した申請の管理についてサポートが必要な場合は、次のリソースを使用してください。
Windows developer