How to update subscription prices with the App Store Connect API
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}/subscriptions3. Read current prices
GET /v1/subscriptions/{subId}/prices?include=subscriptionPricePoint,territory&limit=200Each 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=200Price 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=200Use 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.