The App Store Connect API returns inconsistent results for IAP pricing.
https://api.appstoreconnect.apple.com/v1/inAppPurchasePriceSchedules/:iapId/manualPrices?include=inAppPurchasePricePoint&filter[territory]=USA
I expect to see at least two inAppPurchasePrices
objects, one with startDate: null
, representing the current, active price, and at least one with a non-null startDate
.
Many IAPs I query don't include an inAppPurchasePrices
object that has startDate: null
, forcing me to sort through the return objects for the latest startDate
(excluding those in the future).
Other IAPs I query return only one inAppPurchasePrices
object, and that object has startDate: null
.
Worst of all, sometimes the startDate: null
object points to the wrong price point!
To repro
Run this Node program I wrote using https://www.npmjs.com/package/node-app-store-connect-api
const { fetchJson } = await api({ issuerId: "***", apiKey: "***" });
const iaps = await fetchJson('apps/1302297731/inAppPurchasesV2?limit=200');
const output = {
noLatest: [],
noNull: [],
nullMismatchesLatest: [],
ok: [],
}
await Promise.all(iaps.map(async (iap) => {
const { data: inAppPurchasePrices, included } = await fetchJson(`inAppPurchasePriceSchedules/${iap.id}/manualPrices?include=inAppPurchasePricePoint&filter[territory]=USA`,
{ inclusions: 'tree' });
const latestStartPrice = inAppPurchasePrices.filter(price => price.attributes.startDate && new Date(price.attributes.startDate).getTime() < Date.now())
.sort((a, b) => b.attributes.startDate.localeCompare(a.attributes.startDate))[0];
const nullStartPrice = inAppPurchasePrices.filter(price => !price.attributes.startDate)[0];
if (!latestStartPrice) {
output.noLatest.push(iap.id);
}
if (!nullStartPrice) {
output.noNull.push(iap.id);
}
if (latestStartPrice && nullStartPrice) {
const latestStartPricePoint = included.inAppPurchasePricePoints[latestStartPrice.relationships.inAppPurchasePricePoint.data.id];
const nullStartPricePoint = included.inAppPurchasePricePoints[nullStartPrice.relationships.inAppPurchasePricePoint.data.id];
if (latestStartPricePoint !== nullStartPricePoint) {
output.nullMismatchesLatest.push(iap.id);
} else {
output.ok.push(iap.id);
}
}
}));
console.log(JSON.stringify(output, null, 2));
Expected
All IAPs should appear in the ok
array, having a startDate: null
price that matches the current latest price with a non-null startDate
.
Actual
{
"noLatest": [
"1497954161",
"1441701978",
"1435841888",
"1456629092",
"1381567394",
"1478155596",
"1420181684",
"1546010700",
"1307073664",
"1435842259",
"1447528634",
"1456628326",
"1355941688",
"1355943062",
"1389691983",
"1364108501",
"1614866807",
"1412920025",
"1412927608",
"1377458307",
"1635603476",
"1614867647",
"1402141384",
"1355943058",
"1522960459",
"1438261088",
"1355943066",
"1473496366",
"1435186057",
"1364106150",
"1443695443",
"1473495651",
"1624284308",
"1412923459",
"1532797948",
"1467986798",
"1364102273",
"1480297027",
"1391358524",
"1606438471",
"1497951341",
"1364106702",
"1332191975",
"1480298417",
"1454531393",
"1634234785",
"1496622145",
"1355942300",
"1607908448",
"1412924898",
"1452845547",
"1412922765",
"1614901335",
"1412928940",
"1601726945",
"1579373942",
"1635602874",
"1496621119",
"1402775284",
"1555535989",
"1481266301",
"1402141505",
"1467986077",
"1526194764",
"1584208741",
"1364106824",
"1522959003",
"1364107650",
"1450343495",
"1419335516",
"1473494688",
"1361358209",
"1440133234",
"1449545225",
"1529667540",
"1635603182",
"1412928190",
"1355943775",
"1441701155",
"1514835714",
"1634325161",
"1412923835"
],
"noNull": [
"1402141378",
"1402141617",
"1402141630",
"1402141433",
"1402141611",
"1402141281",
"1402141605",
"1402141608",
"1402141440",
"1402141273",
"1402141370",
"1402141442",
"1402141439",
"1402141437",
"1402141276",
"1402141389",
"1402141504",
"1402141502",
"1402141501",
"1402141607",
"1402141615",
"1402141613",
"1402141435",
"1402141619",
"1402141510",
"1402141429",
"1402141494",
"1402141279",
"1402141622",
"1402141623",
"1402141375",
"1402141610",
"1402141606",
"1402142202",
"1402141508",
"1402141609",
"1402141424",
"1402141503",
"1402141441",
"1402141509",
"1402141280",
"1402141430",
"1402141496",
"1402141616",
"1402141292",
"1402141295",
"1402141275",
"1402141612",
"1402141298",
"1402141385",
"1402141282",
"1402141272",
"1402141602",
"1402141423",
"1402141625",
"1402141629",
"1402141271",
"1402141387",
"1402141601",
"1402141386",
"1402141428",
"1402141421",
"1402141495",
"1402141294",
"1402141438",
"1402140691",
"1402141390",
"1402142201",
"1402141627",
"1402141620",
"1402141614",
"1402141604",
"1402141434",
"1402141296",
"1402141383",
"1402141278",
"1402141626",
"1402141621"
],
"nullMismatchesLatest": [
"1559613404",
"1480951433",
"1593896143",
"1624290126",
"1402141388",
"1497950653",
"1611780428",
"1478784036",
"1575588963",
"1607162006",
"1611045747",
"1575589112",
"1569461289",
"1619138153",
"1583793186",
"1601722583",
"1539790918",
"1487867489",
"1402141618",
"1506977067",
"1588425188",
"1632448119",
"1619138571",
"1497954915",
"1611045866",
"1593060899",
"1601719729",
"1482341662",
"1512806464",
"1532073035",
"1530425266",
"1617098896",
"1611046073",
"1633118569",
"1497959781",
"1412920918",
"1624064036",
"1497951222",
"1617100668",
"1578378729",
"1536619711",
"1569460808",
"1632483553",
"1478782797",
"1482341459",
"1543962463",
"1606792538",
"1402141426",
"1588968070",
"1493021281",
"1564178247",
"1624276610",
"1562385331",
"1585716972",
"1517480296",
"1402141422",
"1482781115"
],
"ok": [
"1402141274",
"1391871240",
"1402141293",
"1364108521",
"1469870296",
"1461673391",
"1443694803",
"1402141425",
"1481265446",
"1402141443",
"1412917867",
"1384042585",
"1562888619",
"1412920920",
"1402141507",
"1402141506",
"1402141452",
"1364107061",
"1447036664",
"1364107609"
]
}