Regarding App Store Connect API v2.3

I'm contacting with a question regarding the in-app purchase price settings that use the App Store Connect API. Using App Store Connect API v2.3, we understand that we are supposed to be able to do the following: ・Change price for base country for in-app purchases ・Customize prices for in-app purchases

https://developer.apple.com/documentation/appstoreconnectapi/add_a_scheduled_price_change_to_an_in-app_purchase Following this, we made a payload and tried to use it.

・Change price for base country for in-app purchases This worked without issue.

・Customize prices for in-app purchases This did not work.

Regarding the customizaton of prices, is there any API available other than this one?: https://api.appstoreconnect.apple.com/v1/inAppPurchasePriceSchedules

Any help you can provide on customizing in-app purchase prices would be much appreciated.

For reference, here is the payload we tested:

payload := {
    "data": {
        "type": "inAppPurchasePriceSchedules",
        "relationships": {
            "baseTerritory": {
                "data": {
                    "type": "territories",
                    "id":   TERITORY_1(※),
                },
            },
            "inAppPurchase": {
                "data": {
                    "type": "inAppPurchases",
                    "id":   ITEM_ID(※),
                },
            },
            "manualPrices": {
                "data": {
                    {
                        "type": "inAppPurchasePrices",
                        "id":   PRICE_POINT_ID_1(※),
                    },
                },
            },
        },
    },
    "included": {
        {
            "attributes": {
                "startDate": null,
            },
            "relationships": {
                "inAppPurchasePricePoint": {
                    "data": {
                        "type": "inAppPurchasePricePoints",
                        "id":   PRICE_POINT_ID_2(※),
                    },
                },
                "inAppPurchaseV2": {
                    "data": {
                        "type": "inAppPurchases",
                        "id":   ITEM_ID(※),
                    },
                },
            },
            "type": "inAppPurchasePrices",
            "id":    PRICE_POINT_ID_3(※),
        },
        {
            "type": "territories",
            "id":   TERITORY_2(※),
        },
    },
}

We tested it in the following ways. Areas with (※) indicate changed values.

Pattern 1: Success (set base country price)
TERITORY_1: Base country code (e.g. USA
ITEM_ID: In-app purchase item ID
PRICE_POINT_ID_1-3: Base country price point (e.g. eyJzIjoiNjQ0NjQ3OTMwNSIsInQiOiJERVUiLCJwIjoiMTAzNTcifQ
TERITORY_2:  Base country code (e.g. USA
Pattern 2: Failure (customize price outside of base country)
TERITORY_1: Base country code (e.g. USA)
ITEM_ID: In-app purchase item ID
PRICE_POINT_ID_1: Base country price point (e.g. eyJzIjoiNjQ0NjQ3OTMwNSIsInQiOiJERVUiLCJwIjoiMTAzNTcifQ
PRICE_POINT_ID_2: Price point to be customized in another country (e.g. axKaHdnaoADFGojkpfafQ3OTMwNSIsInQiOldaDfaeAEfBdageDlkP
PRICE_POINT_ID_3: Price point to be customized in another country (e.g. axKaHdnaoADFGojkpfafQ3OTMwNSIsInQiOldaDfaeAEfBdageDlkP
TERITORY_2: Country code to be customized (e.g. JPN 

Error message:

{
  "errors" : [ {
    "id" : "e29b37ff-2159-4a15-b238-264ae96e9da1",
    "status" : "409",
    "code" : "ENTITY_ERROR.RELATIONSHIP.REQUIRED",
    "title" : "The provided entity is missing a required relationship",
    "detail" : "You must provide a value for the relationship 'inAppPurchasePricePoint' with this request",
    "source" : {
      "pointer" : "/included/0/relationships/inAppPurchasePricePoint"
    }
  } ]
}

Pattern 1 and 2 use the same payload, so we have set the "inAppPurchasePricePoint" in the relationship.

Post not yet marked as solved Up vote post of k-yamada Down vote post of k-yamada
1.2k views

Replies

PRICE_POINT_ID_1 and PRICE_POINT_ID_2,they're equivalent, and they're associated identifiers, so they have to be the same, and PRICE_POINT_ID_3 is the price point, which has nothing to do with 1 and 2.

@k-yamada

If you want to set a custom price in a certain country or region, request an example:


#Base territory
base_territory_id = "CHN"
base_territory_id2 = "HKG"

iap_price_id = "A random name, used to distinguish a price plan"
# Globally balanced prices
iap_price_point_id = "eyJzIjoiNjQ0NDY1MzEwNSIsInQiOiJDSE4iLCJwIjoiMTAwMDEifQ" # CNY¥ 1.00
iap_price_point_id2 = "eyJzIjoiNjQ0NDY1MzEwNSIsInQiOiJDSE4iLCJwIjoiMTAwMDUifQ" # CNY¥ 2.50
# Customised price
iap_price_point_id3 = "eyJzIjoiNjQ0NDY1MzEwNSIsInQiOiJIS0ciLCJwIjoiMTAwMTUifQ" # HKD $16.00

# Request body
body = {
	'data': {
		'relationships': {
			'inAppPurchase': {
				'data': {
					'id': f"{app_iap_id}",
					'type': 'inAppPurchases'
				}
			},
			'baseTerritory': {
				'data': {
					'id': f"{base_territory_id}",
					'type': 'territories'
				}
			},
			'manualPrices': {
				'data': [
					{
						'id': f'{iap_price_id}',
						'type': 'inAppPurchasePrices'
					},
					{
						'id': f"{iap_price_id}2",
						'type': 'inAppPurchasePrices'
					},
					{
						'id': f"{iap_price_id}3",
						'type': 'inAppPurchasePrices'
					}
				]
			}
		},
		'type': 'inAppPurchasePriceSchedules'
	},
	'included': [
		{
			'id': f'{iap_price_id}',
			'type': 'inAppPurchasePrices',
			'attributes': {
				'startDate': '2023-04-25',				
                'endDate': None
			},
			'relationships': {
				'inAppPurchasePricePoint': {
					'data': {
						'id': f"{iap_price_point_id}",
						'type': 'inAppPurchasePricePoints'
					}
				},
				'inAppPurchaseV2': {
					'data': {
						'id': f"{app_iap_id}",
						'type': 'inAppPurchases'
					}
				}
			}
		},
		{
			'id': f'{iap_price_id}2',
			'type': 'inAppPurchasePrices',
			'attributes': {
				'startDate': None,
				'endDate': '2023-04-25'
			},
			'relationships': {
				'inAppPurchasePricePoint': {
					'data': {
						'id': f"{iap_price_point_id2}",
						'type': 'inAppPurchasePricePoints'
					}
				},
				'inAppPurchaseV2': {
					'data': {
						'id': f"{app_iap_id}",
						'type': 'inAppPurchases'
					}
				}
			}
		},
		{
			'id': f'{iap_price_id}3',
			'type': 'inAppPurchasePrices',
			'attributes': {
				'startDate': None,
				'endDate': None
			},
			'relationships': {
				'inAppPurchasePricePoint': {
					'data': {
						'id': f"{iap_price_point_id3}",
						'type': 'inAppPurchasePricePoints'
					}
				},
				'inAppPurchaseV2': {
					'data': {
						'id': f"{app_iap_id}",
						'type': 'inAppPurchases'
					}
				}
			}
		}
	]
}

This example shows that the mainland China CHN is the benchmark country, and all countries and regions are set to have automatic global equilibrium prices, except Hong Kong, China HKG. Then from now to 2023-04-25, use the CNY¥2.50 price point of the benchmark country mainland China to set the global equilibrium price. Starting from 2023-04-25, use the CNY¥ 1.00 price of the benchmark country mainland China. Click to set the global equilibrium price. The exception is Hong Kong, China. From now on, it has been manually adjusting the custom price HKD $16.00, that is, the fixed price, without following the global equilibrium price adjustment.

There are many pits here. The baseTerritory benchmark country field must be set, otherwise an error will be reported:

{
  "errors" : [ {
    "id" : "82b5ea44-b220-402b-b7b9-88031f76a115",
    "status" : "409",
    "code" : "ENTITY_ERROR.ATTRIBUTE.REQUIRED",
    "title" : "The provided entity is missing a required field",
    "detail" : "You must provide a value for the field (baseTerritory) with this request",
    "source" : {
      "pointer" : "/data/attributes/baseTerritory"
    }
  } ]
}

Then although the manualPrices field means manual price, it does not mean customised price, indicating all the price schedule plans that need to be set. Here we have set three price time plans:

'manualPrices': {
	'data': [
		{
			'id': f'{iap_price_id}',
			'type': 'inAppPurchasePrices'
		},
		{
			'id': f"{iap_price_id}2",
			'type': 'inAppPurchasePrices'
		},
		{
			'id': f"{iap_price_id}3",
			'type': 'inAppPurchasePrices'
		}
	]
}

The id above represents the name of the price time schedule, which is used to distinguish each time schedule. Then, it is necessary to list the specific price schedule:

'included': [
		{
			'id': f'{iap_price_id}',
			'type': 'inAppPurchasePrices',
			'attributes': {
				'startDate': '2023-04-25',				
                'endDate': None
			},
			'relationships': {
				'inAppPurchasePricePoint': {
					'data': {
						'id': f"{iap_price_point_id}",
						'type': 'inAppPurchasePricePoints'
					}
				},
				'inAppPurchaseV2': {
					'data': {
						'id': f"{app_iap_id}",
						'type': 'inAppPurchases'
					}
				}
			}
		},
... Omit ...

... Omit ...
    ]

The most complicated thing here is two places, included.x.id and manualPrices.data.x.id are a correspondence, so there is a price schedule, there is a corresponding included.x.id , they keep up with relationships.inAppPurchasePricePoint.data.id is irrelevant, of course, if you find it convenient, it is also possible to set all three as the id of the price point.

Post not yet marked as solved Up vote reply of Efun Down vote reply of Efun
  • Extreamly useful information. I have wasted 3 days to solved this, as documentation is misleading or even incorrect. Thx you brother.

Add a Comment

Note that the price time schedule listed in the included.x.id array must be listed in manualPrices.data.x.id, otherwise an error will be reported:

{
  "errors" : [ {
    "id" : "13b3b82d-ba4b-4fda-97e1-2c30a37bd729",
    "status" : "409",
    "code" : "ENTITY_ERROR.RELATIONSHIP.REQUIRED",
    "title" : "The provided entity is missing a required relationship",
    "detail" : "You must provide a value for the relationship 'inAppPurchasePricePoint' with this request",
    "source" : {
      "pointer" : "/included/3/relationships/inAppPurchasePricePoint"
    }
  } ]
}

relationships.inAppPurchasePricePoint.data.id needs to be set to the price point id corresponding to the required country or region. This is mainland China, so it is set to the corresponding price point of CHN. For countries or regions that need to customise the price, they need to set the price point of the corresponding country or region.

In addition, it should be noted that startDate and endDate of the price schedule of the base country. If there are multiple schedules, it must include all time periods, otherwise an error will be reported:

{
  "errors" : [ {
    "id" : "8ad9f644-bdb5-4eaf-9029-6b6451b68677",
    "status" : "409",
    "code" : "ENTITY_ERROR.INVALID_INTERVAL",
    "title" : "There is a problem with the request entity",
    "detail" : "Entire timeline must be covered for CHN. Adjacent intervals must not have a gap in between: [null - 2023-04-24T00:00] and [2023-04-25T00:00 - null]",
    "source" : {
      "pointer" : "/data/relationships/manualPrices"
    }
  } ]
}

Finally, the price point corresponding to the baseTerritory benchmark country must be set, otherwise an error will be reported:

{
  "errors" : [ {
    "id" : "4cb1ed03-fea8-467b-a9b0-a563087584f7",
    "status" : "409",
    "code" : "ENTITY_ERROR.BASE_TERRITORY_INTERVAL_REQUIRED",
    "title" : "There is a problem with the request entity",
    "detail" : "There must be at least one manual price for the base territory.",
    "source" : {
      "pointer" : "/data/relationships/manualPrices"
    }
  } ]
}

Finally, there is another note. In our example, the benchmark country mainland China (CHN) sets the global equilibrium price from now to the CNY¥ 2.50 price point used by 2023-04-25, starting from 2023-04-25, so that Set the global equilibrium price with the CNY¥1.00 price point. The exception is Hong Kong, China. From now on, it has been manually adjusting the customised price HKD $16.00. But the price schedule displayed in the background of Apple ASC:

Only 22 countries or regions will follow 2023-04-25 for automatic adjustment. The remaining 152 countries or regions, because the global equilibrium prices corresponding to CNY¥1.00 and CNY¥2.50 in the benchmark countries are the same price point, so they will not be automatically adjusted with 2023-04-25. It should be noted that the subsequent Apple price adjustment plan is also affected by factors such as foreign exchange rate or tax rate adjustment.

Summary, the rules that must be followed when setting the interface of a price adjustment (IAP level) of an IAP:

  • The baseTerritory base country must be set
  • Time schedule of price points in the benchmark country, necessarily covering all time periods
  • If it is a custom price, it must be listed at the price point of each country, and multiple countries cannot be specified in batches
  • A time schedule with a custom price, can only include a startDate or endDate, or a full time period when both are empty.

The above request example is a streamlined content, detailed request example (Python code implementation) and request response content, we put it in the GitHub repository 37iOS/AppStoreConnectAPI-Demo, subsequent API upgrades will be updated together, and you can obtain them yourself.

Post not yet marked as solved Up vote reply of Efun Down vote reply of Efun

Thanks @Efun, that was very useful.