Changing a subscription price for dozens of countries in the App Store Connect UI is slow. The App Store Connect API can do it in a few calls. These are the requests AppPriceKit makes, taken from its open-source code.

1. Authenticate with a team API key

Create a team key in App Store Connect under Users and Access → Integrations, with App Manager access. Sign a JWT with the .p8 private key using ES256, the key ID as kid, your issuer ID as iss and appstoreconnect-v1 as aud. Tokens can last up to 20 minutes; AppPriceKit uses 15.

jwt.sign({ iss: issuerId, aud: "appstoreconnect-v1" }, privateKey, {
  algorithm: "ES256",
  expiresIn: "15m",
  header: { kid: keyId },
});

2. Find the subscription

GET /v1/apps
GET /v1/apps/{appId}/subscriptionGroups
GET /v1/subscriptionGroups/{groupId}/subscriptions

3. Read current prices

GET /v1/subscriptions/{subId}/prices?include=subscriptionPricePoint,territory&limit=200

Each price has a startDate. A price with a future start date is scheduled; the latest past one is current. Paginate with the links.next URL until it is absent.

4. Find the right price point

GET /v1/subscriptions/{subId}/pricePoints?filter[territory]=USA&include=territory&limit=200

Price points are specific to a subscription and a territory. To get the local equivalent of a US point in every other territory, follow its equalizations:

GET /v1/subscriptionPricePoints/{pricePointId}/equalizations?include=territory&limit=200

Use this mapping rather than matching price points by their position in each territory’s list; the ladders differ by currency. Background in how Apple sets prices in 175 countries.

5. Schedule the new price

POST /v1/subscriptionPrices
{
  "data": {
    "type": "subscriptionPrices",
    "attributes": { "startDate": "2026-10-10", "preserveCurrentPrice": true },
    "relationships": {
      "subscription": { "data": { "type": "subscriptions", "id": "{subId}" } },
      "subscriptionPricePoint": {
        "data": { "type": "subscriptionPricePoints", "id": "{pricePointId}" }
      }
    }
  }
}

The price point ID already identifies the territory, so one request schedules one country. preserveCurrentPrice keeps existing subscribers on their current price for increases; it has no effect on decreases. See Apple’s API reference.

Gotchas we hit

  • Start dates. Apple needs the start date a day or two ahead, depending on time zones. A same-day date is rejected.
  • 409 conflicts. Only one future change can exist per territory. If one is already scheduled, the request can fail with 409. Re-read prices to see what Apple actually holds before retrying.
  • Confirm after errors. A timeout doesn’t mean the write failed. Re-read the prices and check for your start date and price point before sending the request again.
  • Rate limits. Equalization lookups for 175 territories add up. Limit concurrency and retry 429s with backoff.

If you’d rather not write this yourself, AppPriceKit does all of it in the browser, and you can try it on sample data.

Try price-level pricing on sample data.

Free, open source, no sign-up. Nothing is sent to Apple.

Open the sample

By Ahtisham · Updated