目的
- (大量にある)Appやin-app purchaseをAppStoreConnectでセールのたびに値札を付け替えるのは疲れる。
- APIで一気にやれたらうれしい。
ref.
前提
- JWTをとる、とかそういうのはもうできているとする。(あとで書き加えるかもしれないが)
価格をつける・付け直す
- これは
priceSchedule
をつける、ということ。今の価格を変更するというよりは、価格変更のスケジュールを追加する。 - しかるに以下のAPI エンドポイントに
POST
リクエストを送りつける、ということ。
https://api.appstoreconnect.apple.com/v1/appPriceSchedules
具体的には以下のようになる。
curl -X POST \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d "$JSON_PAYLOAD" \
"https://api.appstoreconnect.apple.com/v1/appPriceSchedules"
JSON_PAYLOAD
は以下のような内容。どのアプリについて、どの地域の価格をいくらに変更するかを示す必要があり、それらが記述されている。以下が注意点
- 価格には、いつから、いつまで、も含む
- 価格は即値を入れるのではなく、価格IDをいれる。これもAPIから取得する。
- 価格IDに国・地域の場所の情報が畳み込まれている。
-
POST
でリクエストすると、おそらく今設定されているものがすべて上書きになる。したがって、PATCH
やDELETE
は用意していないが、変更、削除はPOST
から行う。
ここで、
$APP_ID
は該当アプリのID。以下のURLから取得できる。
curl -H "Authorization: Bearer $TOKEN" "https://api.appstoreconnect.apple.com/v1/apps"
$TERRITORY
は国・地域コード。以下のURLより。
curl -H "Authorization: Bearer $TOKEN" "https://api.appstoreconnect.apple.com/v1/appPriceSchedules/$APP_ID/baseTerritory"
${XXXX}
はAppStore Connect APIで使用可能なプレイスフォルダーで、実際の内容をincluded
以下に書いている。
{
"data": {
"type": "appPriceSchedules",
"relationships": {
"app": {
"data": {
"type": "apps",
"id": "'$APP_ID'"
}
},
"baseTerritory": {
"data": {
"type": "territories",
"id": "'$TERRITORY'"
}
},
"manualPrices": {
"data": [
{
"type": "appPrices",
"id": "${new-price-0}"
},
{
...
}
]
}
}
},
"included": [
{
"id": "${new-price-0}",
"type": "appPrices",
"attributes": {
"startDate": null,
"endDate": "2025-06-01"
},
"relationships": {
"appPricePoint": {
"data": {
"type": "appPricePoints",
"id": "'$ID_07_99'"
}
}
}
},
{
"id": "${new-price-1}",
"type": "appPrices",
"attributes": {
"startDate": "2025-06-01",
"endDate": null
},
"relationships": {
"appPricePoint": {
"data": {
"type": "appPricePoints",
"id": "'$ID_03_99'"
}
}
}
}
]
}
manualPrices::data
には、複数個のエントリーを入れることができる。というか、通常は(つまり、価格変更のスケジュールを行うには) 2つのエントリーが入ることになる。1つは、現在価格のエントリー。2つ目は価格変更のエントリー。ほぼ繰り返しの説明となるが、新価格のスケジュールをつける場合にAPI越しでこれを達成するためには、現在の価格に関する情報もJSONに載せないとならない。
以下included
の説明。ここで、${XXXX}
で定義したmanualPrices
のアイテムを記述している。上記の例では、2つのアイテムについて記述している。つまり、2025-06-01
までの価格と、その日以降の価格である。ここでの注意点:
-
appPricePoint::data::id
の内容は、以下のURLで取得できるIDであること。この例ではterritory=USA
でフィルタしているが、それぞれのbaseTerritory
で読み替えてください。
curl -H "Authorization: Bearer $TOKEN" "https://api.appstoreconnect.apple.com/v1/apps/$APP_ID/appPricePoints?filter\[territory\]=USA&limit=100
他の例
設定した価格変更をキャンセルする
他、例えば、価格変更をキャンセルする場合は、現在の価格のIDをとってきて、included
に1つのアイテムだけを登録、startDate
とendDate
をnull
にすれば、設定できます。
現在設定した価格変更の期間をキャンセルする
設定中の価格変更がどんなものであっても、結局最終的に見たい状態の価格スケジュールをPayloadに載せることがやれることの全て。なので、上の例の 6/1/2025からの変更を7/1/2025に変更したい場合は、全く同じPayloadで、endDate
とstartDate
を2025-07-01
に変更してPOSTします。
ある国(たとえば日本)だけ、価格を変更する。
まず、日本のpricePointsを確認する。
curl -H "Authorization: Bearer $TOKEN" "https://api.appstoreconnect.apple.com/v1/apps/$APP_ID/appPricePoints?filter\[territory\]=JPN&limit=100"
設定したいPrice pointのIDを取得して、これをPayloadに組み入れます。manualPrices
としては2つのアイテムが必要です。一つは、グローバル・プライスの再設定。二つ目は、この日本の価格設定です。
"included": [
{
"id": "${new-price-0}",
"relationships": {
"appPricePoint": {
"data": {
"type": "appPricePoints",
"id": "'$ID_01_99'"
}
}
},
"type": "appPrices",
"attributes": {
"startDate": null,
"endDate": null
}
},
{
"id": "${new-price-1}",
"relationships": {
"appPricePoint": {
"data": {
"type": "appPricePoints",
"id": "'$JPY_1030'"
}
}
},
"type": "appPrices",
"attributes": {
"startDate": null,
"endDate": null
}
}
]
日本とそれ以外のpricePoint IDをいれて、それぞれの attributeをnull
にすれば、現在の価格が直接updateされることになるでしょう。スケジュールしたい場合は、endDate
だけnull
にすればok
in-app purchaseの場合
in-app purchaseの場合もそれほど変わりません。まず、変更したいin-app purchaseのIDを取得します。
curl -H "Authorization: Bearer $TOKEN" "https://api.appstoreconnect.apple.com/v1/apps/$APP_ID/inAppPurchasesV2"
現在のmanualPrices
をしらべます。また、ターゲットのprice pointを決定しIDを取得します。
curl -H "Authorization: Bearer $TOKEN" "https://api.appstoreconnect.apple.com/v1/inAppPurchasePriceSchedules/$IAP_ID/manualPrices"
curl -H "Authorization: Bearer $TOKEN" "https://api.appstoreconnect.apple.com/v2/inAppPurchases/$IAP_ID/pricePoints?filter\[territory\]=USA&limit=100"
以下のURLにPOSTメッセージを送信して、アップデートします。
curl -X POST \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d "$JSON_IAP_PAYLOAD" \
"https://api.appstoreconnect.apple.com/v1/inAppPurchasePriceSchedules"
ここで JSON_IAP_PAYLOAD
は例えば以下のようになります。
{
"data": {
"type": "inAppPurchasePriceSchedules",
"relationships": {
"inAppPurchase": {
"data": {
"type": "inAppPurchases",
"id": "'$IAP_ID'"
}
},
"baseTerritory": {
"data": {
"type": "territories",
"id": "USA"
}
},
"manualPrices": {
"data": [
{
"type": "inAppPurchasePrices",
"id": "${new-price-0}"
},
{
"type": "inAppPurchasePrices",
"id": "${new-price-1}"
}
]
}
}
},
"included": [
{
"id": "${new-price-0}",
"relationships": {
"inAppPurchasePricePoint": {
"data": {
"type": "inAppPurchasePricePoints",
"id": "'$IAP_06_99'"
}
}
},
"type": "inAppPurchasePrices",
"attributes": {
"startDate": null,
"endDate": "2025-05-01"
}
},
{
"id": "${new-price-1}",
"relationships": {
"inAppPurchasePricePoint": {
"data": {
"type": "inAppPurchasePricePoints",
"id": "'$IAP_03_99'"
}
}
},
"type": "inAppPurchasePrices",
"attributes": {
"startDate": "2025-05-01",
"endDate": null
}
}
]
}
アプリの価格変更Payloadから見た違いは以下。
- app/apps となっているところは inAppPurchase/inAppPurchases
- pricePointもきちんとin-app purchaseの pricePoints API で調べてIDをゲットする。
バッチ処理する場面において
- APP_ID や IAP_ID は調べておく。これらは後から変更されるものではない。これらを配列につめてループする。
- pricePointはもし、appやin-app purchaseで固有ならば、それらを取らないといけないが、IDにはなにやら法則性があるから、その辺りに頑張りどころがあるかもしれない。以下に調べた結果を示す。
price point ID について
curl -s -H "Authorization: Bearer $TOKEN" "https://api.appstoreconnect.apple.com/v1/apps/$APP_ID/appPricePoints?filter\[territory\]=USA&limit=10" | grep -o '"id" : "[^"]*"' | head -5
上記URLなどで調べられる、price point IDはBASE64
でエンコードされたトークンとなっている。
{"s":"ID","t":"3CHAR_TERRITORY","p":"PRICE_ID"}
ここで、
- IDはAPP_IDやIAP_IDなど、APIから取得できるID
- 3CHAR_TERRITORYも
USA
やJPN
など、これまでにすでに出てきているもの。 - 問題は
PRICE_ID
。これについてはundocumentedのようだが、free(つまり tier 0)のものが10000
で、そこからtier(900種類に増えたやつ)を登っていくようだ。
例
USA(USD) | PRICE_ID |
---|---|
0.00 | 10000 |
7.99 | 10101 |
9.99 | 10127 |
13.99 | 10147 |
15.99 | 10157 |
17.99 | 10167 |
19.99 | 10177 |