0
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

AppStoreConnect API をつかって、appやin-app purchaseのpriceをコントロールする

Last updated at Posted at 2025-04-07

目的

  • (大量にある)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でリクエストすると、おそらく今設定されているものがすべて上書きになる。したがって、PATCHDELETEは用意していないが、変更、削除は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つのアイテムだけを登録、startDateendDatenullにすれば、設定できます。

現在設定した価格変更の期間をキャンセルする

設定中の価格変更がどんなものであっても、結局最終的に見たい状態の価格スケジュールをPayloadに載せることがやれることの全て。なので、上の例の 6/1/2025からの変更を7/1/2025に変更したい場合は、全く同じPayloadで、endDatestartDate2025-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もUSAJPNなど、これまでにすでに出てきているもの。
  • 問題は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
0
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?