MSI または EXE アプリの Microsoft Store 申請 API
MSI または EXE アプリ用の Microsoft Store 申請 API を使用して、自分または組織のパートナー センター アカウントの MSI または EXE アプリの申請をプログラムで照会して作成します。 この API は、アカウントで多数のアプリを管理しており、これらのアセットの申請プロセスを自動化および最適化する場合に便利です。 この API は、Azure Active Directory (Azure AD) を使って、アプリまたはサービスからの呼び出しを認証します。
次の手順では、Microsoft Store 申請 API を使用するエンド ツー エンドのプロセスについて説明します。
- すべての前提条件を完了したことを確認します。
- Microsoft Store 申請 API でメソッドを呼び出す前に、Azure AD アクセス トークンを取得します。 トークンを取得した後、Microsoft Store 申請 API の呼び出しでこのトークンを使用できるのは、その有効期限が切れるまでの 60 分間です。 トークンの有効期限が切れた後は、新しいトークンを生成できます。
- MSI または EXE アプリ用の Microsoft Store 申請 API を呼び出します。
手順 1: Microsoft Store 申請 API を使用するための前提条件を完了する。
MSI または EXE アプリ用の Microsoft Store 申請 API を呼び出すコードの記述を開始する前に、次の前提条件を満たしていることを確認してください。
- 自分 (または自分の組織) に Azure AD ディレクトリがあり、自分がそのディレクトリに対するグローバル管理者のアクセス許可を持っている必要があります。 Microsoft 365 または Microsoft の他のビジネス サービスをすでに使用している場合、Azure AD ディレクトリをすでに所有しています。 それ以外の場合は、追加料金なしにパートナー センターで新しい Azure AD を作成できます。
- Azure AD アプリケーションをパートナー センター アカウントと関連付け、テナント ID、クライアント ID、キーを取得する必要があります。 Azure AD アクセス トークンを取得するにはこれらの値が必要です。Microsoft Store 申請 API への呼び出しにこれらを使用します。
- Microsoft Store 申請 API で使用するアプリを準備します。
- パートナー センターにアプリがまだ存在しない場合は、パートナー センターでアプリの名前を予約してアプリを作成する必要があります。 Microsoft Store 申請 API を使ってパートナー センターにアプリを作成することはできません。パートナー センターを使ってアプリを作成する必要があります。その後、API を使ってアプリにアクセスし、プログラムでアプリの申請を作成できます。
- この API を使って特定のアプリの申請を作成する前に、年齢区分に関するアンケートへの回答など、最初にパートナー センターでアプリの申請を 1 つ作成する必要があります。 これを行うと、API を使用して、このアプリの新しい申請をプログラムで作成できるようになります。
- アプリの申請を作成または更新していて、新しいパッケージを含める必要がある場合は、パッケージの詳細を準備します。
- アプリの申請を作成または更新していて、ストア登録情報のスクリーンショットまたは画像を含める必要がある場合は、アプリのスクリーンショットと画像を準備します。
Azure AD アプリケーションをパートナー センター アカウントと関連付ける方法
MSI または EXE アプリ用の Microsoft Store 申請 API を使用する前に、Azure AD アプリケーションをパートナー センター アカウントに関連付け、アプリケーションのテナント ID とクライアント ID を取得して、キーを生成する必要があります。 Azure AD アプリケーションは、Microsoft Store 申請 API を呼び出すアプリまたはサービスを表します。 API に渡す Azure AD アクセス トークンを取得するには、テナント ID、クライアント ID、キーが必要です。
Note
この作業を行うのは一度だけです。 テナント ID、クライアント ID、キーがあれば、新しい Azure AD アクセス トークンを作成する必要がある度にそれらを再利用できます。
- パートナー センターで、組織のパートナー センター アカウントを組織の Azure AD ディレクトリに関連付けます。
- 次に、パートナー センターの [アカウント設定] セクションの [ユーザー] ページから、パートナー センター アカウントの申請にアクセスするために使用するアプリまたはサービスを表す Azure AD アプリケーションを追加します。 このアプリケーションにマネージャー ロールを確実に割り当てます。 アプリケーションがまだ Azure AD ディレクトリに存在しない場合、パートナー センターで新しい Azure AD アプリケーションを作成できます。
- [ユーザー] ページに戻り、Azure AD アプリケーションの名前をクリックしてアプリケーション設定に移動し、テナント ID とクライアント ID の値を書き留めます。
- 新しいキーまたはクライアント シークレットを追加するには、次の手順を参照するか、Azure Portal を使用してアプリを登録する手順を参照してください。
アプリを登録するには:
Azure portal にサインインします。
複数のテナントにアクセスできる場合は、トップ メニューの [ディレクトリとサブスクリプション] フィルター を使用して、アプリケーションを登録するテナントに切り替えます。
Azure Active Directory を検索して選択します。
[管理] で [アプリの登録] を選択し、>アプリケーションを選択します。
>[証明書 & シークレット][クライアント シークレット]>[新しいクライアント シークレット] を選択します。
クライアント シークレットの説明を追加します。
シークレットの有効期限を選択するか、カスタムの有効期間を指定します。
クライアント シークレットの有効期間は、2 年間 (24 か月) 以下に制限されています。 24 か月を超えるカスタムの有効期間を指定することはできません。
Note
Microsoft では、有効期限の値は 12 か月未満に設定することをお勧めしています。
[追加] を選択します。
クライアント アプリケーションのコードで使用できるように、"シークレットの値を記録します"。 このページからの移動後は、このシークレットの値は "二度と表示されません"。
手順 2:Azure AD アクセス トークンを取得する
MSI または EXE アプリ用の Microsoft Store 申請 API でメソッドを呼び出す前に、まず、API の各メソッドの Authorization ヘッダーに渡す Azure AD アクセス トークンを取得する必要があります。 アクセス トークンを取得したら、期限が切れる 60 分が経過する前に使用します。 トークンの有効期限が切れた後は、トークンを更新してそれ以降の API 呼び出しで引き続き使用できます。
アクセス トークンを取得するには、「[クライアント資格情報を使用したサービス間呼び出し]/azure/active-directory/azuread-dev/v1-oauth2-client-creds-grant-flow」の手順に従って、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_id
POST URI と client_id
andclient_secret
パラメーターの値には、前のセクションでパートナー センターから取得したアプリケーションのテナント ID、クライアント ID、およびキーを指定します。 scope パラメーターには、 を指定する必要がありますhttps://api.store.microsoft.com/.default
。
アクセス トークンの有効期限が切れた後は、この手順に従って更新できます。
C# または Node.js を使用してアクセス トークンを取得する方法を示す例については、MSI または EXE アプリの Microsoft Store 申請 API のコード例を参照してください。
手順 3: Microsoft Store 申請 API を使用する
Azure AD アクセス トークンを取得したら、MSI または EXE アプリ用の Microsoft Store 申請 API でメソッドを呼び出すことができます。 API には、アプリのシナリオにグループ化された多くのメソッドが含まれています。 申請を作成または更新するには、通常、複数のメソッドを特定の順序で呼び出します。 各シナリオと各メソッドの構文については、次のセクションを参照してください。
Note
アクセス トークンを取得した後、トークンの有効期限が切れる前に、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 |
moduleName | パートナー センター モジュール – 登録情報、プロパティ、または可用性 |
クエリ パラメーター
パラメーター | 説明 |
---|---|
languages | オプション: リスト言語はコンマ区切り文字列としてフィルタリングされます (最大 200 言語の制限)。 存在しない場合は、最初の 200 個の使用可能なリスト言語のメタデータが取得されます。 [ e.g.,“en-us, en-gb"]. |
includelanguagelist | オプションのブール値 – true の場合、追加されたリスト言語のリストとその完全性ステータスを返します。 |
必須のヘッダー
ヘッダー | 値 |
---|---|
Authorization: Bearer <Token> |
パートナー センター アカウントに登録されている Azure AD アプリ ID |
X-Seller-Account-Id |
パートナー センター アカウントの販売者 ID |
応答ヘッダー
ヘッダー | 値 |
---|---|
X-Correlation-ID |
各要求の GUID の種類の一意の ID。 これは、問題を分析するためにサポートチームと共有できます。 |
Retry-After |
レート制限のために API を再度呼び出す前にクライアントが待機する必要がある時間 (秒単位)。 |
応答パラメーター
名前 | 種類 | 説明 |
---|---|---|
accessibilitySupport | Boolean | |
additionalLicenseTerms | String | |
availability | Object | 可用性 モジュール データ |
category | String | 以下のカテゴリのリストを参照してください |
certificationNotes | String | |
code | String | メッセージのエラーコード |
ContactInfo | String | |
著作権 | String | |
dependsOnDriversOrNT | Boolean | |
description | String | |
developedBy | String | |
Discoverability | String | [DISCOVERABLE, DEEPLINK_ONLY] |
enableInFutureMarkets | Boolean | |
エラー | オブジェクトの配列 | エラーまたは警告メッセージのリスト (存在する場合) |
FreeTrial | String | [NO_FREE_TRIAL, FREE_TRIAL] |
hardwareItemType | String | |
isPrivacyPolicyRequired | Boolean | |
isRecommended | Boolean | |
isRequired | Boolean | |
IsSuccess | Boolean | |
isSystemFeatureRequired | オブジェクトの配列 | |
言語 | String | 以下の言語のリストを参照してください |
listings | オブジェクトの配列 | 各言語のモジュール・データのリスト |
市場 | 文字列の配列 | 以下の市場のリストを参照してください |
message | String | エラーの説明 |
minimumHardware | String | |
minimumRequirement | String | |
penAndInkSupport | Boolean | |
価格 | String | [無料、フリーミアム、サブスクリプション、有料] |
privacyPolicyUrl | String | |
productDeclarations | Object | |
ProductFeatures | 文字列の配列 | |
properties | Object | プロパティ モジュール データ |
recommendedHardware | String | |
recommendedRequirement | String | |
responseData | Object | 要求の実際の応答ペイロードが含まれます |
要件 | オブジェクトの配列 | |
SearchTerms | 文字列の配列 | |
shortDescription | String | |
subcategory | String | 以下のサブカテゴリのリストを参照してください |
supportContactInfo | String | |
systemRequirementDetails | オブジェクトの配列 | |
ターゲット | String | エラーの発生元エンティティ |
Web サイト | String | |
whatsNew | String |
応答のサンプル
{
"isSuccess": true,
"errors": [{
"code": "badrequest",
"message": "Error Message 1",
"target": "listings"
}, {
"code": "warning",
"message": "Warning Message 1",
"target": "properties"
}],
"responseData": {
"availability":{
"markets": ["US"],
"discoverability": "DISCOVERABLE",
"enableInFutureMarkets": true,
"pricing": "PAID",
"freeTrial": "NO_FREE_TRIAL"
},
"properties":{
"isPrivacyPolicyRequired": true,
"privacyPolicyUrl": "http://contoso.com",
"website": "http://contoso.com",
"supportContactInfo": "http://contoso.com",
"certificationNotes": "Certification Notes",
"category": "DeveloperTools",
"subcategory": "Database",
"productDeclarations": {
"dependsOnDriversOrNT": false,
"accessibilitySupport": false,
"penAndInkSupport": false
},
"isSystemFeatureRequired": [
{
"isRequired": true,
"isRecommended": false,
"hardwareItemType": "Touch"
},
{
"isRequired": true,
"isRecommended": false,
"hardwareItemType": "Keyboard"
},
{
"isRequired": false,
"isRecommended": false,
"hardwareItemType": "Mouse"
},
{
"isRequired": false,
"isRecommended": false,
"hardwareItemType": "Camera"
},
{
"isRequired": false,
"isRecommended": false,
"hardwareItemType": "NFC_HCE"
},
{
"isRequired": false,
"isRecommended": false,
"hardwareItemType": "NFC_Proximity"
},
{
"isRequired": false,
"isRecommended": false,
"hardwareItemType": "Bluetooth_LE"
},
{
"isRequired": false,
"isRecommended": false,
"hardwareItemType": "Telephony"
},
{
"isRequired": false,
"isRecommended": false,
"hardwareItemType": "Microphone"
}
],
"systemRequirementDetails": [
{
"minimumRequirement": "1GB",
"recommendedRequirement": "4GB",
"hardwareItemType": "Memory"
},
{
"minimumRequirement": "",
"recommendedRequirement": "",
"hardwareItemType": "DirectX"
},
{
"minimumRequirement": "",
"recommendedRequirement": "",
"hardwareItemType": "Video_Memory"
},
{
"minimumRequirement": "",
"recommendedRequirement": "",
"hardwareItemType": "Processor"
},
{
"minimumRequirement": "",
"recommendedRequirement": "",
"hardwareItemType": "Graphics"
}
]
},
"listings":[{
"language": "en-us",
"description": "Description",
"whatsNew": "What's New",
"productFeatures": ["Feature 1"],
"shortDescription": "Short Description",
"searchTerms": ["Search Ter 1"],
"additionalLicenseTerms": "License Terms",
"copyright": "Copyright Information",
"developedBy": "Developer Details",
"sortTitle": "Product 101",
"requirements": [
{
"minimumHardware": "Pentium4",
"recommendedHardware": "Corei9"
}
],
"contactInfo": "contactus@contoso.com"
}],
"listingLanguages": [{"language":"en-us", "isComplete": true}]
}
}
現在の下書き送信メタデータ API の更新
下書き提出中の各モジュールのメタデータを更新します。 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> |
パートナー センター アカウントに登録されている Azure AD アプリ ID |
X-Seller-Account-Id |
パートナー センター アカウントの販売者 ID |
要求パラメーター
名前 | 種類 | 説明 |
---|---|---|
availability | Object | 可用性モジュールのメタデータを保持するオブジェクト |
市場 | 文字列の配列 | 必須 以下の市場のリストを参照してください |
Discoverability | String | 必須[DISCOVERABLE, DEEPLINK_ONLY] |
enableInFutureMarkets | Boolean | 必須 |
価格 | String | 必須[無料、フリーミアム、サブスクリプション、有料] |
FreeTrial | String | 価格が有料またはサブスクリプションの場合は必須[NO_FREE_TRIAL、FREE_TRIAL] |
properties | Object | プロパティ モジュール のメタデータを保持するオブジェクト |
isPrivacyPolicyRequired | Boolean | 必須 |
privacyPolicyUrl | String | isPrivacyPolicyRequired = true の場合は必須 有効な URL である必要があります |
Web サイト | String | 有効な URI である必要があります。 |
supportContactInfo | String | 有効な URL またはメール アドレスである必要があります。 |
certificationNotes | String | 推奨文字数の制限 = 2000 |
category | String | 必須以下のカテゴリのリストを参照してください |
subcategory | String | 必須以下のサブカテゴリのリストを参照してください |
productDeclarations | Object | 必須 |
isSystemFeatureRequired | オブジェクトの配列 | [タッチ、キーボード、マウス、カメラ、NFC_HCE、NFC_Proximity、Bluetooth_LE、テレフォニー、マイク] |
isRequired | Boolean | 必須 |
isRecommended | Boolean | 必須 |
hardwareItemType | String | 必須 |
systemRequirementDetails | オブジェクトの配列 | [プロセッサ、グラフィックス、メモリ、DirectX、Video_Memory] |
minimumRequirement | String | 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 | String | 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 | Boolean | 必須 |
accessibilitySupport | Boolean | 必須 |
penAndInkSupport | Boolean | 必須 |
listings | Object | 単一言語のモジュール・データをリストするオブジェクト |
言語 | String | 必須 以下の言語のリストを参照してください |
description | String | 必須 文字の制限 = 10000 |
whatsNew | String | 文字数制限 = 1500 |
ProductFeatures | 文字列の配列 | 機能ごとに 200 文字。最大20の機能 |
shortDescription | String | 文字数制限 = 1000 |
SearchTerms | 文字列の配列 | 検索語句ごとに 30 文字。最大 7 つの検索語句 すべての検索語で合計 21 個の一意の単語 |
additionalLicenseTerms | String | 必須 文字の制限 = 10000 |
著作権 | String | 文字制限 = 200 |
developedBy | String | 文字制限 = 255 |
要件 | オブジェクトの配列 | 項目あたり 200 文字。最小と推奨の間で合計11項目まで] |
minimumHardware | String | 文字制限 = 200 |
recommendedHardware | String | 文字制限 = 200 |
ContactInfo | String | 文字制限 = 200 |
listingsToAdd | 文字列の配列 | 以下の言語のリストを参照してください |
listingsToRemove | 文字列の配列 | 以下の言語のリストを参照してください |
市場
マーケット | 省略形 |
---|---|
アフガニスタン | 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 |
ドミニカ共和国 | 推奨 |
エクアドル | 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 |
ノルウェー | 使用不可 |
オマーン | 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 |
Tog - TG | |
トケラウ | TK |
トンガ | TO |
トリニダード・トバッグ - TT | |
チュニジア | TN |
トルコ | TR |
トルクメニスタン | TM |
タークス・カイコス諸島 | TC |
ツバル | TV |
米領その他の米領諸島 | UM |
米領バージン諸島 | VI |
ウガンダ | UG |
ウクライナ | UA |
アラブ首長国連邦 | AE |
英国 | GB |
United States | US |
ウルグアイ | UY |
ウズベキスタン | UZ |
バヌアツ | VU |
ベトナム | VN |
ウォリス・フツナ | WF |
イエメン | YE |
ザンビア | ZM |
ジンバブエ | ZW |
オーランド諸島 | AX |
カテゴリとサブカテゴリ
カテゴリ | サブカテゴリー |
---|---|
書籍と参考書 | Eリーダー、フィクション、ノンフィクション、リファレンス |
事業 | 会計および財務、コラボレーション、CRM、データと分析、ファイル管理、在庫およびロジスティクス、法務および人事、プロジェクト管理、リモートデスクトップ、販売およびマーケティング、時間と費用 |
開発者ツール | データベース, 設計ツール, 開発キット, ネットワーキング, リファレンスとトレーニング, サーバー, ユーティリティ, ウェブホスティング |
教育 | 教育書籍と参考書、早期学習、教育ツール、言語、学習支援 |
エンターテイメント | (なし) |
フードとダイニング | (なし) |
政府と政治 | (なし) |
健康とフィットネス | (なし) |
子供と家族 | 子供と家族&書籍と参考書、キッズとファミリーエンターテイメント、趣味・玩具、スポーツとアクティビティ、キッズとファミリートラベル |
ライフスタイル | 自動車 、 DYI 、 ホームアンドガーデン 、 関係 、 スペシャルインタレスト 、 スタイルとファッション |
医療 | (なし) |
マルチメディアデザイン | イラスト・グラフィックデザイン、音楽制作、写真・映像制作 |
ミュージック | (なし) |
ナビゲーションと地図 | (なし) |
ニュースと天気予報 | ニュース, 天気 |
パーソナルファイナンス | 銀行と投資、予算編成と税金 |
パーソナル化 | 着メロとサウンド, テーマ, 壁紙とロック画面 |
写真とビデオ | (なし) |
生産性 | (なし) |
セキュリティ | 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 |
English | en、en-au、en-ca、en-gb、en-ie、en-in、en-nz、en-sg、en-us、en-za、en-bz、en-hk、en-id、en-jm、en-kz、en-mt、en-my、en-ph、en-pk、en-tt、en-vn、en-zw |
エストニア語 | et、et-ee |
Filipin - 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 |
Igb - 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 | Boolean | |
エラー | オブジェクトの配列 | エラーまたは警告メッセージのリスト (存在する場合) |
code | String | メッセージのエラーコード |
message | String | エラーの説明 |
ターゲット | String | エラーの発生元エンティティ |
responseData | Object | 要求の実際の応答ペイロードが含まれます |
pollingUrl | String | 進行中の送信のステータスを取得するためのポーリングURL |
ongoingSubmissionId | String | 既に進行中の提出書類の提出書類 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> |
パートナー センター アカウントに登録されている Azure AD アプリ ID を使用する |
X-Seller-Account-Id |
パートナー センター アカウントの販売者 ID |
応答ヘッダー
ヘッダー | 値 |
---|---|
X-Correlation-ID |
各要求の GUID の種類の一意の ID。 これは、問題を分析するためにサポートチームと共有できます。 |
Retry-After |
レート制限のために API を再度呼び出す前にクライアントが待機する必要がある時間 (秒単位)。 |
応答パラメーター
名前 | 種類 | 説明 |
---|---|---|
IsSuccess | Boolean | |
エラー | オブジェクトの配列 | エラーまたは警告メッセージのリスト (存在する場合) |
code | String | メッセージのエラーコード |
message | String | エラーの説明 |
ターゲット | String | エラーの発生元のエンティティ |
responseData | Object | |
packages | オブジェクトの配列 | パッケージ モジュール データを保持するオブジェクト |
packageId | String | |
packageUrl: | String | |
言語 | 文字列の配列 | |
architectures | 文字列の配列 | [Neutral, X86, X64, Arm, Arm64] |
isSilentInstall | Boolean | これは、インストーラーがスイッチを必要とせずにサイレントモードで実行されている場合はtrueとしてマークするか、そうでない場合はfalseにする必要があります。 |
installerParameters | String | |
genericDocUrl | String | |
errorDetails | オブジェクトの配列 | |
errorScenario | String | |
errorScenarioDetails | オブジェクトの配列 | |
errorValue | String | |
errorUrl | String | |
packageType | String |
応答のサンプル
{
"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
現在の下書き提出のパッケージの詳細を更新します。
Path [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> |
パートナー センター アカウントに登録されている Azure AD アプリ ID を使用する |
X-Seller-Account-Id |
パートナー センター アカウントの販売者 ID |
要求パラメーター
名前 | 種類 | 説明 |
---|---|---|
packages | オブジェクトの配列 | パッケージモジュールデータを保持するオブジェクト [モジュール全体の更新にのみ必要] |
packageUrl: | String | 必須 |
言語 | 文字列の配列 | 必須 |
architectures | 文字列の配列 | 必須 1 つのアーキテクチャ (Neutral、X86、X64、Arm、Arm64) を含める必要があります |
isSilentInstall | Boolean | 必須 これはインストーラーがスイッチを必要とせずにサイレントモードで実行されている場合は true としてマークするか、そうでない場合は false にする必要があります |
installerParameters | String | isSilentInstall が false の場合は必須 |
genericDocUrl | String | packageType が exe の場合は必須 EXE タイプのインストーラーのカスタム エラー コードの詳細を含むドキュメントへのリンク |
errorDetails | オブジェクトの配列 | EXE タイプのインストーラーのカスタム エラー コードと詳細を保持するメタデータ。 |
errorScenario | String | 具体的なエラーシナリオを特定します。 [installationCancelledByUser, applicationAlreadyExists, installationAlreadyInProgress, diskSpaceIsFull, rebootRequired, networkFailure, packageRejectedDuringInstallation, installationSuccessful, miscellaneous] |
errorScenarioDetails | オブジェクトの配列 | |
errorValue | String | インストール中に表示される可能性のあるエラーコード |
errorUrl | String | エラーの詳細が記載された URL |
packageType | String | 必須 [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 | Boolean | |
エラー | オブジェクトの配列 | [エラーまたは警告メッセージのリスト (存在する場合)] |
code | String | メッセージのエラーコード |
message | String | エラーの説明 |
ターゲット | String | エラーの発生元エンティティ |
responseData | Object | |
pollingUrl | String | [すでに進行中の提出の場合に提出ステータスを取得するためのポーリングURL] |
ongoingSubmissionId | String | [既に進行中の提出書類の提出書類 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> |
パートナー センター アカウントに登録されている Azure AD アプリ ID を使用する |
X-Seller-Account-Id |
パートナー センター アカウントの販売者 ID |
応答ヘッダー
ヘッダー | 値 |
---|---|
X-Correlation-ID |
各要求の GUID の種類の一意の ID。 これは、問題を分析するためにサポートチームと共有できます。 |
Retry-After |
レート制限のために API を再度呼び出す前にクライアントが待機する必要がある時間 (秒単位)。 |
応答パラメーター
名前 | 種類 | 説明 |
---|---|---|
IsSuccess | Boolean | |
エラー | オブジェクトの配列 | [エラーまたは警告メッセージのリスト (存在する場合)] |
code | String | メッセージのエラーコード |
message | String | エラーの説明 |
ターゲット | String | エラーの発生元のエンティティ |
responseData | Object | |
pollingUrl | String | [パッケージのアップロードのステータスを取得するためのポーリングURL、またはすでに進行中のサブミッションの場合のサブミッションステータス] |
ongoingSubmissionId | String | [既に進行中の提出書類の提出書類 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 |
クエリ パラメーター
名前 | 説明 |
---|---|
languages | [オプション]リスト言語は、コンマ区切りの文字列としてフィルタリングされます (最大 200 言語の制限)。 存在しない場合は、最初の 200 個の使用可能なリスト言語のアセットデータが取得されます。 (e.g., “en-us, en-gb") |
必須のヘッダー
ヘッダー | 値 |
---|---|
Authorization: Bearer <Token> |
パートナー センター アカウントに登録されている Azure AD アプリ ID を使用する |
X-Seller-Account-Id |
パートナー センター アカウントの販売者 ID |
応答ヘッダー
ヘッダー | 値 |
---|---|
X-Correlation-ID |
各要求の GUID の種類の一意の ID。 これは、問題を分析するためにサポートチームと共有できます。 |
Retry-After |
レート制限のために API を再度呼び出す前にクライアントが待機する必要がある時間 (秒単位)。 |
応答パラメーター
名前 | 種類 | 説明 |
---|---|---|
IsSuccess | Boolean | |
エラー | オブジェクトの配列 | エラーまたは警告メッセージのリスト (存在する場合) |
code | String | メッセージのエラーコード |
message | String | エラーの説明 |
ターゲット | String | エラーの発生元のエンティティ |
responseData | Object | |
listingAssets | オブジェクトの配列 | 各言語のアセット詳細の一覧表示 |
言語 | String | |
storeLogos | オブジェクトの配列 | |
スクリーンショット | オブジェクトの配列 | |
ID | String | |
assetUrl | String | 有効な URI である必要があります。 |
imageSize | Object | |
width | Integer | |
height | Integer |
応答のサンプル
{
"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 |
必須のヘッダー
Header | 説明 |
---|---|
Authorization: Bearer <Token> |
パートナー センター アカウントに登録されている Azure AD アプリ ID を使用する |
X-Seller-Account-Id |
パートナー センター アカウントの販売者 ID |
要求パラメーター
名前 | 種類 | 説明 |
---|---|---|
language | String | 必須 |
createAssetRequest | Object | 必須 |
Screenshot | Integer | ISV がスクリーンショットを更新したり、新しい登録言語を追加したりする必要がある場合は必須 [1 - 10] |
ロゴ | Integer | ISV がロゴを更新したり、新しい登録情報言語を追加したりする必要がある場合に必要 [1 または 2] |
応答ヘッダー
ヘッダー | 説明 |
---|---|
X-Correlation-ID |
各要求の GUID の種類の一意の ID。 これは、問題を分析するためにサポートチームと共有できます。 |
Retry-After |
レート制限のために API を再度呼び出す前にクライアントが待機する必要がある時間 (秒単位)。 |
応答パラメーター
名前 | 種類 | 説明 |
---|---|---|
IsSuccess | Boolean | |
エラー | オブジェクトの配列 | エラーまたは警告メッセージのリスト (存在する場合) |
code | String | メッセージのエラーコード |
message | String | エラーの説明 |
ターゲット | String | エラーの発生元のエンティティ |
responseData | Object | |
listingAssets | Object | アップロードするStoreLogosとスクリーンショットの詳細を含むオブジェクト |
言語 | String | |
storeLogos | オブジェクトの配列 | |
スクリーンショット | オブジェクトの配列 | |
ID | String | |
primaryAssetUploadUrl | String | Azure Blob REST API を使用して登録資産をアップロードするためのプライマリ URL |
secondaryAssetUploadUrl | String | Azure Blob REST API を使用して登録資産をアップロードするためのセカンダリ URL |
httpMethod | HTTP メソッド | HTTP メソッドは、アセットのアップロード URL (プライマリまたはセカンダリ) を介してアセットをアップロードするために使用する必要があります |
httpHeaders | Object | アセットアップロード 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 |
必須のヘッダー
Header | 説明 |
---|---|
Authorization: Bearer <Token> |
パートナー センター アカウントに登録されている Azure AD アプリ ID を使用する |
X-Seller-Account-Id |
パートナー センター アカウントの販売者 ID |
要求パラメーター
名前 | 種類 | 説明 |
---|---|---|
listingAssets | Object | |
言語 | String | |
storeLogos | オブジェクトの配列 | |
スクリーンショット | オブジェクトの配列 | |
ID | String | ユーザーがGet Current Listing Assets APIから保持する既存のID、またはCreate Listing Assets APIで新しいアセットがアップロードされた新しいIDのいずれかである必要があります。 |
assetUrl | String | ユーザーが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 | Boolean | |
エラー | オブジェクトの配列 | エラーまたは警告メッセージのリスト (存在する場合) |
code | String | メッセージのエラーコード |
message | String | エラーの説明 |
ターゲット | String | エラーの発生元のエンティティ |
responseData | Object | |
pollingUrl | String | 進行中の送信の状態を取得するためのポーリング URL |
ongoingSubmissionId | String | 既に進行中の提出書類の提出書類 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 |
必須のヘッダー
Header | 説明 |
---|---|
Authorization: Bearer <Token> |
パートナー センター アカウントに登録されている Azure AD アプリ ID を使用する |
X-Seller-Account-Id |
パートナー センター アカウントの販売者 ID |
応答ヘッダー
ヘッダー | 説明 |
---|---|
X-Correlation-ID |
各要求の GUID の種類の一意の ID。 これは、問題を分析するためにサポートチームと共有できます。 |
Retry-After |
レート制限のために API を再度呼び出す前にクライアントが待機する必要がある時間 (秒単位)。 |
応答パラメーター
名前 | 種類 | 説明 |
---|---|---|
IsSuccess | Boolean | |
エラー | オブジェクトの配列 | エラーまたは警告メッセージのリスト (存在する場合) |
code | String | メッセージのエラーコード |
message | String | エラーの説明 |
ターゲット | String | エラーの発生元のエンティティ |
responseData | Object | |
isReady | Boolean | パッケージのアップロードを含め、すべてのモジュールが準備完了状態にあるかどうかを示します。 |
ongoingSubmissionId | String | 既に進行中の提出書類の提出書類 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 |
必須のヘッダー
Header | 説明 |
---|---|
Authorization: Bearer <Token> |
パートナー センター アカウントに登録されている Azure AD アプリ ID を使用する |
X-Seller-Account-Id |
パートナー センター アカウントの販売者 ID |
応答ヘッダー
ヘッダー | 説明 |
---|---|
X-Correlation-ID |
各要求の GUID の種類の一意の ID。 これは、問題を分析するためにサポートチームと共有できます。 |
Retry-After |
レート制限のために API を再度呼び出す前にクライアントが待機する必要がある時間 (秒単位)。 |
応答パラメーター
名前 | 種類 | 説明 |
---|---|---|
IsSuccess | Boolean | |
エラー | オブジェクトの配列 | エラーまたは警告メッセージのリスト (存在する場合) |
code | String | メッセージのエラーコード |
message | String | エラーの説明 |
ターゲット | String | エラーの発生元のエンティティ |
responseData | Object | |
pollingUrl | String | 送信用のパッケージのアップロードなど、モジュールの準備状況を取得するためのポーリング URL |
submissionId | String | 新しく作成されたサブミッションの ID |
ongoingSubmissionId | String | 既に進行中の提出書類の提出書類 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 |
必須のヘッダー
Header | 説明 |
---|---|
Authorization: Bearer <Token> |
パートナー センター アカウントに登録されている Azure AD アプリ ID を使用する |
X-Seller-Account-Id |
パートナー センター アカウントの販売者 ID |
応答ヘッダー
ヘッダー | 説明 |
---|---|
X-Correlation-ID |
各要求の GUID の種類の一意の ID。 これは、問題を分析するためにサポートチームと共有できます。 |
Retry-After |
レート制限のために API を再度呼び出す前にクライアントが待機する必要がある時間 (秒単位)。 |
応答パラメーター
名前 | 種類 | 説明 |
---|---|---|
IsSuccess | Boolean | |
エラー | オブジェクトの配列 | エラーまたは警告メッセージのリスト (存在する場合) |
code | String | メッセージのエラーコード |
message | String | エラーの説明 |
ターゲット | String | エラーの発生元のエンティティ |
responseData | Object | |
publishingStatus | String | 提出書類の発行ステータス - [進行中、公開済み、失敗、不明] |
hasFailed | Boolean | 公開が失敗し、再試行されないかどうかを示します |
応答のサンプル
{
"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 に置き換えます。 詳しくは、「Azure AD アプリケーションをパートナー センター アカウントに関連付ける方法」をご覧ください。
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 ヘルパー クラスを使用して、Azure Active Directory データとアプリ データを、Microsoft Store 申請 API を使用する各サンプル メソッドに渡します。
using System;
using System.Collections.Generic;
using System.Text;
namespace Win32SubmissionApiCSharpSample
{
public class ClientConfiguration
{
/// <summary>
/// Client Id of your Azure Active Directory app.
/// Example" 00001111-aaaa-2222-bbbb-3333cccc4444
/// </summary>
public string ClientId { get; set; }
/// <summary>
/// Client secret of your Azure Active Directory app
/// </summary>
public string ClientSecret { get; set; }
/// <summary>
/// Service root endpoint.
/// Example: "https://api.store.microsoft.com"
/// </summary>
public string ServiceUrl { get; set; }
/// <summary>
/// Token endpoint to which the request is to be made. Specific to your Azure Active Directory app
/// Example: https://login.microsoftonline.com/d454d300-128e-2d81-334a-27d9b2baf002/oauth2/v2.0/token
/// </summary>
public string TokenEndpoint { get; set; }
/// <summary>
/// Resource scope. If not provided (set to null), default one is used for the production API
/// endpoint ("https://api.store.microsoft.com/.default")
/// </summary>
public string Scope { get; set; }
/// <summary>
/// Partner Center Application ID.
/// Example: 3e31a9f9-84e8-4d2d-9eba-487878d02ebf
/// </summary>
public string ApplicationId { get; set; }
/// <summary>
/// The Partner Center Seller Id
/// Example: 123456892
/// </summary>
public int SellerId { get; set; }
}
}
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 のメソッドを呼び出すために使用できる Azure AD アクセス トークンを取得します。 トークンを取得した後、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 Azure Active Directory allowing the caller to invoke the API
/// on behalf of a user
/// </param>
/// <param name="serviceUrl">The service URL.</param>
public SubmissionClient(string accessToken, string serviceUrl)
{
if (string.IsNullOrEmpty(accessToken))
{
throw new ArgumentNullException("accessToken");
}
if (string.IsNullOrEmpty(serviceUrl))
{
throw new ArgumentNullException("serviceUrl");
}
this.accessToken = accessToken;
this.httpClient = new HttpClient
{
BaseAddress = new Uri(serviceUrl)
};
this.imageUploadClient = new HttpClient();
this.DefaultHeaders = new Dictionary<string, string>();
}
/// <summary>
/// Gets or Sets the default headers.
/// </summary>
public Dictionary<string, string> DefaultHeaders { get; set; }
/// <summary>
/// Performs application-defined tasks associated with freeing, releasing, or resetting
/// unmanaged resources.
/// </summary>
public void Dispose()
{
if (this.httpClient != null)
{
this.httpClient.Dispose();
this.httpClient = null;
GC.SuppressFinalize(this);
}
}
/// <summary>
/// Gets the authorization token for the provided client id, client secret, and the scope.
/// This token is usually valid for 1 hour, so if your submission takes longer than that to complete,
/// make sure to get a new one periodically.
/// </summary>
/// <param name="tokenEndpoint">Token endpoint to which the request is to be made. Specific to your
/// Azure Active Directory app. Example: https://login.microsoftonline.com/d454d300-128e-2d81-334a-27d9b2baf002/oauth2/v2.0/token </param>
/// <param name="clientId">Client Id of your Azure Active Directory app. Example" 00001111-aaaa-2222-bbbb-3333cccc4444</param>
/// <param name="clientSecret">Client secret of your Azure Active Directory app</param>
/// <param name="scope">Scope. If not provided, default one is used for the production API endpoint.</param>
/// <returns>Autorization token. Prepend it with "Bearer: " and pass it in the request header as the
/// value for "Authorization: " header.</returns>
public static async Task<string> GetClientCredentialAccessToken(
string tokenEndpoint,
string clientId,
string clientSecret,
string scope = null)
{
if (scope == null)
{
scope = "https://api.store.microsoft.com/.default";
}
dynamic result;
using (HttpClient client = new HttpClient())
{
string tokenUrl = tokenEndpoint;
using (
HttpRequestMessage request = new HttpRequestMessage(
HttpMethod.Post,
tokenUrl))
{
string strContent =
string.Format(
"grant_type=client_credentials&client_id={0}&client_secret={1}&scope={2}",
clientId,
clientSecret,
scope);
request.Content = new StringContent(strContent, Encoding.UTF8,
"application/x-www-form-urlencoded");
using (HttpResponseMessage response = await client.SendAsync(request))
{
string responseContent = await response.Content.ReadAsStringAsync();
result = JsonConvert.DeserializeObject(responseContent);
}
}
}
return result.access_token;
}
/// <summary>
/// Invokes the specified HTTP method.
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="httpMethod">The HTTP method.</param>
/// <param name="relativeUrl">The relative URL.</param>
/// <param name="requestContent">Content of the request.</param>
/// <returns>instance of the type T</returns>
/// <exception cref="ServiceException"></exception>
public async Task<T> Invoke<T>(HttpMethod httpMethod,
string relativeUrl,
object requestContent)
{
using (var request = new HttpRequestMessage(httpMethod, relativeUrl))
{
this.SetRequest(request, requestContent);
using (HttpResponseMessage response = await this.httpClient.SendAsync(request))
{
T result;
if (this.TryHandleResponse(response, out result))
{
return result;
}
if (response.IsSuccessStatusCode)
{
var resource = JsonConvert.DeserializeObject<T>(await response.Content.ReadAsStringAsync());
return resource;
}
throw new Exception(await response.Content.ReadAsStringAsync());
}
}
}
/// <summary>
/// Uploads a given Image Asset file to Asset Storage
/// </summary>
/// <param name="assetUploadUrl">Asset Storage Url</param>
/// <param name="fileStream">The Stream instance of file to be uploaded</param>
/// <returns></returns>
/// <exception cref="Exception"></exception>
public async Task UploadAsset(string assetUploadUrl, Stream fileStream)
{
using (var request = new HttpRequestMessage(HttpMethod.Put, assetUploadUrl))
{
request.Headers.Add("x-ms-blob-type", "BlockBlob");
request.Content = new StreamContent(fileStream);
request.Content.Headers.ContentType = new MediaTypeHeaderValue(PngContentType);
using (HttpResponseMessage response = await this.imageUploadClient.SendAsync(request))
{
if (response.IsSuccessStatusCode)
{
return;
}
throw new Exception(await response.Content.ReadAsStringAsync());
}
}
}
/// <summary>
/// Sets the request.
/// </summary>
/// <param name="request">The request.</param>
/// <param name="requestContent">Content of the request.</param>
protected virtual void SetRequest(HttpRequestMessage request, object requestContent)
{
request.Headers.Authorization = new AuthenticationHeaderValue("Bearer", this.accessToken);
foreach (var header in this.DefaultHeaders)
{
request.Headers.Add(header.Key, header.Value);
}
if (requestContent != null)
{
request.Content = new StringContent(JsonConvert.SerializeObject(requestContent),
Encoding.UTF8,
JsonContentType);
}
}
/// <summary>
/// Tries the handle response.
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="response">The response.</param>
/// <param name="result">The result.</param>
/// <returns>true if the response was handled</returns>
protected virtual bool TryHandleResponse<T>(HttpResponseMessage response, out T result)
{
result = default(T);
return false;
}
}
}
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 に置き換えます。 詳しくは、「Azure AD アプリケーションをパートナー センター アカウントに関連付ける方法」をご覧ください。
次の例では、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 ヘルパー クラスを使用して、Azure Active 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 のメソッドを呼び出すために使用できる Azure AD アクセス トークンを取得します。 トークンを取得した後、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