MSI または EXE アプリの Microsoft Store 申請 API

MSI または EXE アプリ用の Microsoft Store 申請 API を使用して、自分または組織のパートナー センター アカウントの MSI または EXE アプリの申請をプログラムで照会して作成します。 この API は、アカウントで多数のアプリを管理しており、これらのアセットの申請プロセスを自動化および最適化する場合に便利です。 この API は、Microsoft Entra ID を使用して、アプリまたはサービスからの呼び出しを認証します。

次の手順では、Microsoft Store 申請 API を使用するエンド ツー エンドのプロセスについて説明します。

  1. すべての前提条件を完了したことを確認します。
  2. Microsoft Store 申請 API でメソッドを呼び出す前に、Microsoft Entra ID アクセス トークンを取得します。 トークンを取得した後、Microsoft Store 申請 API の呼び出しでこのトークンを使用できるのは、その有効期限が切れるまでの 60 分間です。 トークンの有効期限が切れた後は、新しいトークンを生成できます。
  3. 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 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 アクセス トークンを作成する必要がある場合は、いつでもそれらを再利用できます。

  1. パートナー センターで、 組織のパートナー センター アカウントを組織の Microsoft Entra ID ディレクトリに関連付けます。
  2. 次に、パートナー センターの [アカウント設定] セクションの [ユーザー] ページから、パートナー センター アカウントの申請にアクセスするために使用するアプリまたはサービスを表す Microsoft Entra ID アプリケーションを追加 します。 このアプリケーションにマネージャー ロールを確実に割り当てます。 アプリケーションが Microsoft Entra ID ディレクトリにまだ存在しない場合は、 パートナー センターで新しい Microsoft Entra ID アプリケーションを作成できます。
  3. [ユーザー] ページに戻り、Microsoft Entra ID アプリケーションの名前をクリックしてアプリケーション設定に移動し、テナント ID とクライアント ID の値をコピーします。
  4. 新しいキーまたはクライアント シークレットを追加するには、次の手順を参照するか、Azure portal を使用してアプリを登録する手順を参照してください。

アプリを登録するには:

  1. Azure portal にサインインします。

  2. 複数のテナントにアクセスできる場合は、トップ メニューの [ディレクトリとサブスクリプション] フィルター を使用して、アプリケーションを登録するテナントに切り替えます。

  3. Microsoft Entra ID Directory を検索して選択します。

  4. [管理] で [アプリの登録] を選択し、>アプリケーションを選択します。

  5. >[証明書 & シークレット][クライアント シークレット]>[新しいクライアント シークレット] を選択します。

  6. クライアント シークレットの説明を追加します。

  7. シークレットの有効期限を選択するか、カスタムの有効期間を指定します。

  8. クライアント シークレットの有効期間は、2 年間 (24 か月) 以下に制限されています。 24 か月を超えるカスタムの有効期間を指定することはできません。

    注

    Microsoft では、有効期限の値は 12 か月未満に設定することをお勧めしています。

  9. [追加] を選択します。

  10. クライアント アプリケーションのコードで使用できるように、"シークレットの値を記録します"。 このページからの移動後は、このシークレットの値は "二度と表示されません"。

手順 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 コントラクト

現在のドラフト提出メタデータ API を取得する

現在のドラフト送信内の各モジュール(listings、properties、availability)のメタデータを取得します。

パス [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
モジュール名 パートナー センター モジュール – 登録情報、プロパティ、または可用性

クエリ パラメーター

パラメーター 説明
languages オプション: リスト言語はコンマ区切り文字列としてフィルタリングされます (最大 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 を再度呼び出す前にクライアントが待機する必要がある時間 (秒単位)。

応答パラメーター

名前 タイプ 説明
アクセシビリティ対応 ブール値
追加ライセンス条項 糸
可用性 オブジェクト 可用性 モジュール データ
カテゴリ 糸 以下のカテゴリのリストを参照してください
認証メモ 糸
コード 糸 メッセージのエラーコード
連絡先情報 糸
著作権 糸
dependsOnDriversOrNT ブール値
説明 糸
developedBy 糸
発見可能性 糸 [DISCOVERABLE, DEEPLINK_ONLY]
enableInFutureMarkets ブール値
エラー オブジェクトの配列 エラーまたは警告メッセージのリスト (存在する場合)
FreeTrial 糸 [NO_FREE_TRIAL, FREE_TRIAL]
ハードウェア項目タイプ 糸
プライバシーポリシーが必要か ブール値
isRecommended ブール値
isRequired ブール値
isSuccess ブール値
システム機能が必要か オブジェクトの配列
言語 糸 以下の言語のリストを参照してください
listings オブジェクトの配列 各言語のモジュール・データのリスト
市場 文字列の配列 以下の市場のリストを参照してください
メッセージ 糸 エラーの説明
minimumHardware 糸
minimumRequirement 糸
ペンとインクのサポート ブール値
価格 糸 [無料、フリーミアム、サブスクリプション、有料]
プライバシーポリシーURL 糸
製品宣言 オブジェクト
productFeatures 文字列の配列
プロパティ オブジェクト プロパティ モジュール データ
推奨ハードウェア 糸
recommendedRequirement 糸
応答データ オブジェクト 要求の実際の応答ペイロードが含まれます
要件  オブジェクトの配列
searchTerms 文字列の配列
短い説明 糸
subcategory 糸 以下のサブカテゴリのリストを参照してください
サポート連絡先情報 糸
システム要件の詳細 オブジェクトの配列
ターゲット 糸 エラーの発生元エンティティ
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

パス [完全モジュール更新]: /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

要求パラメーター

名前 タイプ 説明
可用性 オブジェクト 可用性モジュールのメタデータを保持するオブジェクト
市場 文字列の配列 必須 以下の市場のリストを参照してください
発見可能性 糸 必須 [DISCOVERABLE, DEEPLINK_ONLY]
enableInFutureMarkets ブール値 必須
価格 糸 必須[無料、フリーミアム、サブスクリプション、有料]
FreeTrial 糸 価格が有料またはサブスクリプションの場合は必須[NO_FREE_TRIAL、FREE_TRIAL]
プロパティ オブジェクト プロパティ モジュール のメタデータを保持するオブジェクト
プライバシーポリシーが必要か ブール値 必須
プライバシーポリシーURL 糸 isPrivacyPolicyRequired = true の場合は必須 有効な URL である必要があります
Web サイト 糸 有効な URI である必要があります。
サポート連絡先情報 糸 有効な URL またはメール アドレスである必要があります。
認証メモ 糸 推奨文字数の制限 = 2000
カテゴリ 糸 必須以下のカテゴリのリストを参照してください
subcategory 糸 必須以下のサブカテゴリのリストを参照してください
製品宣言 オブジェクト 必須
システム機能が必要か オブジェクトの配列 [タッチ、キーボード、マウス、カメラ、NFC_HCE、NFC_Proximity、Bluetooth_LE、テレフォニー、マイク]
isRequired ブール値 必須
isRecommended ブール値 必須
ハードウェア項目タイプ 糸 必須
システム要件の詳細 オブジェクトの配列 [プロセッサ、グラフィックス、メモリ、DirectX、Video_Memory]
minimumRequirement 糸 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]
recommendedRequirement 糸 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]
dependsOnDriversOrNT ブール値 必須
アクセシビリティ対応 ブール値 必須
ペンとインクのサポート ブール値 必須
listings オブジェクト 単一言語のモジュール・データをリストするオブジェクト
言語 糸 必須 以下の言語のリストを参照してください
説明 糸 必須 文字の制限 = 10000
新着情報 糸 文字数制限 = 1500
productFeatures 文字列の配列 機能ごとに 200 文字。最大20の機能
短い説明 糸 文字数制限 = 1000
searchTerms 文字列の配列 検索語句ごとに 30 文字。最大 7 つの検索語句

すべての検索語で合計 21 個の一意の単語
追加ライセンス条項 糸 必須 文字の制限 = 10000
著作権 糸 文字制限 = 200
developedBy 糸 文字制限 = 255
要件  オブジェクトの配列 項目あたり 200 文字。最小と推奨の間で合計11項目まで]
minimumHardware 糸 文字制限 = 200
推奨ハードウェア 糸 文字制限 = 200
連絡先情報 糸 文字制限 = 200
listingsToAdd 文字列の配列 以下の言語のリストを参照してください
削除するリスト 文字列の配列 以下の言語のリストを参照してください

市場

表を表示 | 市場 | 略称 | |--------|--------------| | アフガニスタン | 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 | | ギニアビサウ | 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 | | 東ティモール | TL | | トーゴ | TG | | トケラウ | TK | | トンガ | TO | | トリニダード トバゴ | TT | | チュニジア | TN | | トルコ | TR | | トルクメニスタン | TM | | タークス カイコス諸島 | TC | | ツバル | TV | | 合衆国領有小離島 | UM | | 米領バージン諸島 | VI | | ウガンダ | UG | | ウクライナ | UA | | アラブ首長国連邦 | AE | | イギリス | GB | | アメリカ合衆国 | US | | ウルグアイ | UY | | ウズベキスタン | UZ | | バヌアツ | VU | | ベトナム | VN | | ウォリス フツナ | WF | | イエメン | YE | | ザンビア | ZM | | ジンバブエ | ZW | | オーランド諸島 | AX |

カテゴリとサブカテゴリ

表を表示 | カテゴリ | サブカテゴリ | |-----------------------|---------------| | 書籍とリファレンス | 電子書籍リーダー, フィクション, ノンフィクション, リファレンス | | ビジネス | 会計と財務, コラボレーション, CRM, データと分析, ファイル管理, 在庫と物流, 法務と人事, プロジェクト管理, リモート デスクトップ, 営業とマーケティング, 時間と経費 | | 開発者ツール | データベース, デザイン ツール, 開発キット, ネットワーク, リファレンスとトレーニング, サーバー, ユーティリティ, Web ホスティング | | 教育 | 教育向け書籍とリファレンス, 早期学習, 教育ツール, 言語, 学習支援 | | エンターテイメント | (なし) | | フードとダイニング | (なし) | | 政府と政治 | (なし) | | 健康とフィットネス | (なし) | | 子供と家族 | 子供と家族向け書籍とリファレンス, 子供と家族向けエンターテイメント, 趣味と玩具, スポーツとアクティビティ, 子供と家族向け旅行 | | ライフスタイル | 自動車, DIY, ホームとガーデン, 人間関係, 特別な関心事, スタイルとファッション | | 医療 | (なし) | | マルチメディア デザイン | イラストレーションとグラフィック デザイン, 音楽制作, 写真とビデオ制作 | | 音楽 | (なし) | | ナビゲーションと地図 | (なし) | | ニュースと天気 | ニュース, 天気 | | 個人向け金融 | 銀行と投資, 予算と税金 | | 個人設定 | 着信音とサウンド, テーマ, 壁紙とロック画面 | | 写真とビデオ | (なし) | | 生産性 | (なし) | | セキュリティ | 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-valencia | | チェロキー語 | 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 | | コサ語 | xh, xh-za | | ズールー語 | 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 ブール値
エラー オブジェクトの配列 エラーまたは警告メッセージのリスト (存在する場合)
コード 糸 メッセージのエラーコード
メッセージ 糸 エラーの説明
ターゲット 糸 エラーの発生元エンティティ
応答データ オブジェクト 要求の実際の応答ペイロードが含まれます
pollingUrl 糸 進行中のサブミッションのステータスを取得するためのポーリング URL
ongoingSubmissionId 糸 進行中の申請の申請 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 を取得する。

現在のドラフト送信に含まれるパッケージの詳細を取得します。

パス [すべてのパッケージ]: /submission/v1/product/{productId}/packages
メソッド: GET

パス [単一パッケージ]: /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 ブール値
エラー オブジェクトの配列 エラーまたは警告メッセージのリスト (存在する場合)
コード 糸 メッセージのエラーコード
メッセージ 糸 エラーの説明
ターゲット 糸 エラーの発生元のエンティティ
応答データ オブジェクト
packages オブジェクトの配列 パッケージ モジュール データを保持するオブジェクト
packageId 糸
packageUrl 糸
languages 文字列の配列
アーキテクチャ 文字列の配列 [Neutral, X86, X64, Arm, Arm64]
isSilentInstall ブール値 これは、インストーラーがスイッチを必要とせずにサイレントモードで実行されている場合はtrueとしてマークするか、そうでない場合はfalseにする必要があります。
インストーラーのパラメーター 糸
genericDocUrl 糸
エラー詳細 オブジェクトの配列
errorScenario 糸
エラーシナリオの詳細 オブジェクトの配列
エラー値 糸
errorUrl 糸
パッケージタイプ 糸

応答のサンプル

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

現在の下書き申請のパッケージの詳細を更新します。

パス [Full Module Update]: /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

要求パラメーター

名前 タイプ 説明
packages オブジェクトの配列 パッケージモジュールデータを保持するオブジェクト [モジュール全体の更新にのみ必要]
packageUrl 糸 必須
languages 文字列の配列 必須
アーキテクチャ 文字列の配列 必須 1 つのアーキテクチャ (Neutral、X86、X64、Arm、Arm64) を含める必要があります
isSilentInstall ブール値 必須 これはインストーラーがスイッチを必要とせずにサイレントモードで実行されている場合は true としてマークするか、そうでない場合は false にする必要があります
インストーラーのパラメーター 糸 isSilentInstall が false の場合は必須
genericDocUrl 糸 packageType が exe の場合は必須 EXE タイプのインストーラーのカスタム エラー コードの詳細を含むドキュメントへのリンク
エラー詳細 オブジェクトの配列 EXE タイプのインストーラーのカスタム エラー コードと詳細を保持するメタデータ。
errorScenario 糸 具体的なエラーシナリオを特定します。 [インストールがユーザーによってキャンセルされました, アプリケーションは既に存在します, インストールは既に進行中です, ディスクの空き領域が満杯です, 再起動が必要です, ネットワークエラー, インストール中にパッケージが拒否されました, インストール成功, その他]
エラーシナリオの詳細 オブジェクトの配列
エラー値 糸 インストール中に表示される可能性のあるエラーコード
errorUrl 糸 エラーの詳細が記載された 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 ブール値
エラー オブジェクトの配列 [エラーまたは警告メッセージのリスト (存在する場合)]
コード 糸 メッセージのエラーコード
メッセージ 糸 エラーの説明
ターゲット 糸 エラーの発生元エンティティ
応答データ オブジェクト
pollingUrl 糸 [すでに進行中の提出の場合に提出ステータスを取得するためのポーリングURL]
ongoingSubmissionId 糸 [進行中の申請の申請 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 ブール値
エラー オブジェクトの配列 [エラーまたは警告メッセージのリスト (存在する場合)]
コード 糸 メッセージのエラーコード
メッセージ 糸 エラーの説明
ターゲット 糸 エラーの発生元のエンティティ
応答データ オブジェクト
pollingUrl 糸 [パッケージのアップロードのステータスを取得するためのポーリングURL、またはすでに進行中のサブミッションの場合のサブミッションステータス]
ongoingSubmissionId 糸 [すでに進行中の申請 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": ""
    } 
}

Get Current Draft Listing Assets API

現在の下書き申請の掲載情報アセットの詳細を取得します。

パス: /submission/v1/product/{productId}/listings/assets?languages={languages}
メソッド: GET

パス パラメーター

名前 説明
productId 製品のパートナー センター ID

クエリ パラメーター

名前 説明
languages [オプション]リスト言語は、コンマ区切りの文字列としてフィルタリングされます (最大 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 ブール値
エラー オブジェクトの配列 エラーまたは警告メッセージのリスト (存在する場合)
コード 糸 メッセージのエラーコード
メッセージ 糸 エラーの説明
ターゲット 糸 エラーの発生元のエンティティ
応答データ オブジェクト
listingAssets オブジェクトの配列 各言語のアセット詳細の一覧表示
言語 糸
店舗のロゴ オブジェクトの配列
スクリーンショット オブジェクトの配列
ID 糸
assetUrl 糸 有効な 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 呼び出しを使用します。 リスティングアセットを更新し、リスティングモジュールでロケールを追加/削除できるようにするには、次のアプローチを使用できます。

  1. Create Listing Asset APIを使用して、アセットのアップロードに関するリクエストを、アセットの言語、種類、数とともに送信します。
  2. 要求されたアセット数に基づいて、アセット ID がオンデマンドで作成され、短期間有効な SAS URL が生成されて、Response Body の assets タイプ内で返されます。 この URL を使用して、HTTP クライアントを使用して特定の種類の画像アセットをアップロードできます [Put Blob (REST API) - Azure Storage |Microsoft Docs] です。
  3. アップロード後、Commit Listing Assets API を使用して、以前の API 呼び出しで以前に受信した新しいアセット ID 情報も送信できます。 単一のAPIは、検証後にリスト資産データを内部的にコミットします。
  4. このアプローチは、リクエストで送信されている特定の言語のアセットタイプの以前の画像のセット全体を事実上上書きします。 そのため、以前にアップロードされたアセットは削除されます。

パス: /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 ブール値
エラー オブジェクトの配列 エラーまたは警告メッセージのリスト (存在する場合)
コード 糸 メッセージのエラーコード
メッセージ 糸 エラーの説明
ターゲット 糸 エラーの発生元のエンティティ
応答データ オブジェクト
listingAssets オブジェクト アップロードするStoreLogosとスクリーンショットの詳細を含むオブジェクト
言語 糸
店舗のロゴ オブジェクトの配列
スクリーンショット オブジェクトの配列
ID 糸
primaryAssetUploadUrl 糸 Azure Blob REST API を使用して登録資産をアップロードするためのプライマリ URL
secondaryAssetUploadUrl 糸 Azure Blob REST API を使用して登録資産をアップロードするためのセカンダリ URL
httpMethod HTTP メソッド HTTP メソッドは、アセットのアップロード URL (プライマリまたはセカンダリ) を介してアセットをアップロードするために使用する必要があります
httpHeaders オブジェクト アセットアップロード 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"}

            }]
        }
    } 
}

Commit Listing Assets 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

要求パラメーター

名前 タイプ 説明
listingAssets オブジェクト
言語 糸
店舗のロゴ オブジェクトの配列
スクリーンショット オブジェクトの配列
ID 糸 Get Current Listing Assets API からユーザーが維持したい既存の ID、または Create Listing Assets API で新しいアセットをアップロードした際に付与された新しい ID のいずれかである必要があります。
assetUrl 糸 ユーザーが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 ブール値
エラー オブジェクトの配列 エラーまたは警告メッセージのリスト (存在する場合)
コード 糸 メッセージのエラーコード
メッセージ 糸 エラーの説明
ターゲット 糸 エラーの発生元のエンティティ
応答データ オブジェクト
pollingUrl 糸 進行中の任意の送信処理のステータスを取得するためのポーリング URL
ongoingSubmissionId 糸 進行中の申請の申請 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 ブール値 パッケージのアップロードを含め、すべてのモジュールが準備完了状態にあるかどうかを示します。
ongoingSubmissionId 糸 進行中の申請の申請 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 ブール値
エラー オブジェクトの配列 エラーまたは警告メッセージのリスト (存在する場合)
コード 糸 メッセージのエラーコード
メッセージ 糸 エラーの説明
ターゲット 糸 エラーの発生元のエンティティ
応答データ オブジェクト
pollingUrl 糸 送信用のパッケージのアップロードなど、モジュールの準備状況を取得するためのポーリング URL
submissionId 糸 新しく作成されたサブミッションの ID
ongoingSubmissionId 糸 進行中の申請の申請 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": ""
    }
}

Submission Status Polling 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 を使用した申請の管理についてサポートが必要な場合は、次のリソースを使用してください。

  • フォーラムで質問してください。
  • サポート ページにアクセスし、パートナー センターのサポート オプションのいずれかをリクエストしてください。 問題の種類とカテゴリを選択するように求められたら、それぞれ [アプリの申請と認定] と [アプリの申請] を選択します。

よく寄せられる質問

  1. Microsoft Store申請 API を使用してできること

    Microsoft Store 申請 API を使用すると、開発者は次のようなアプリ管理タスクを自動化できます。

    • 新しいアプリ更新プログラムの作成と送信。
    • アプリ パッケージのアップロードと管理。
    • メタデータとストア登録情報の更新。

    この API を継続的インテグレーションまたはワークフローの構築に統合し、定期的なタスクを自動化して発行プロセスを効率化できます。