AppStoreConnect API - How to set pricing

I am trying to use the AppStoreConnect API to set the price of an app. In the documentation (here) it suggests that it is possible to set the price using the API.

"To set a price for your app using App Store Connect API, create a relationship between the apps resource and appPrices"

However it links to the instructions on how to set a price using the AppStoreConnect web site.

Looking at the website it appears that the pricing is being set by sending a PATCH to the app record itself but on the API this results in a 405 (METHOD_NOT_ALLOWED)

Is it possible to set a price using the API, and if so what endpoint should I be sending to?

1.1k watchers on this question and still no response from Apple other than the copypasta of my original question. Really disappointing to be honest, do better Apple!

I'm still looking for a way to do this if anyone has any new suggestions.

I will say that this thread right here is THE reason why Stack Overflow is a much better resource. Given how responsive Apple has been here (and on other threads) I can't imagine they do any better at reading the feedback forms that they always ask to be filled out. It's probably the equivalent of dev>null

Ok, now it's getting ridiculous. If we check the existing AppStoreConnect Documentation that I've referenced many times already (here) the entire thing has been deprecated.

BUT following the link to (Set a price) takes you to new information on setting a price that includes a link titled "Learn how to set a price for your app with the App Store Connect API" and that link takes you back to ...

The first link that has everything deprecated and nothing about setting a price. 🤯

The UI for setting prices manually in the web interface has been updated and it is probably the worst it's ever been.

  • It will show you scheduled prices changes but won't tell you what the price is for that change unless you click on it.
  • The calendar is still "stupid", meaning it doesn't default to the next available day after the last scheduled change so you can easily goof up your schedule if you have to set a bunch of changes.
  • You can only schedule one change at a time. So if I want all of my Saturdays to be free I have to do that 52 times for a year then go back and do another 52 changes to set the price back to paid. (Then you start getting 500 errors from the server because it can't handle that "large" of a request)
  • The web interface now uses a POST to send the pricing updates, but every time you send a scheduled price change it sends the entire list of scheduled price changes to the server, not just the one you are setting. So every time you add a price change the request gets bigger. (The JSON format is pretty bad, you could cut the payload by half by simply cleaning up the payload)

Here's the thing, all I'm asking for is an API call where I can set the current price of my app effective immediately and with a simple "price=tierX" payload.

I don't want to deal with the horrible web interface and I don't think it's too much to ask because the API call is already in place for the web UI, it just needs to be made available through the ASC API.

@Claude31 Maybe you can clarify this for me.

Looking at this documentation https://developer.apple.com/documentation/appstoreconnectapi/add_a_scheduled_price_change_to_an_app

It clearly specifies that this call is a POST yet sending a POST results in a 405 Method Not Allowed. It also specifies in the url that this is an API v1 request, but it is flagged as API 2.3+

The documentation on this page has been updated since I last referenced it but now it is very unclear, can you clarify which method should be used on this call and if the URL is correct?

Also, are there any auth changes between v1 and v2.3 of the API?

I also noticed that the response from the API that returns a list of apps for an account changed yesterday afternoon. It was a breaking change in the JSON response for codables and I'm surprised this was done within the same version (API v1) and not for a newer version and a different endpoint.

Is there a separate URL set for versions of the API or can we expect that current endpoints will randomly return responses from newer versions of the API as those roll out?

As a follow up to the post above linking to the documentation for the appPriceSchedules API, a request that follows the documentation as written results in the following response:

{
	"errors": [{
		"status": "405",
		"code": "METHOD_NOT_ALLOWED",
		"title": "The request method is not valid for the resource path.",
		"detail": "The request method used for this request is not valid for the resource path. Please consult the documentation."
	}]
}

In an email thread with Apple about pricing I was told that a "paid download" is determined by "the price of the app at the time the payment goes through". I dismissed it as oddly worded because obviously when I purchase the app in order to download it the payment should go through at that point in time.

But now I'm curious, if I download an app when it is NOT free, but my payment doesn't go through until a time when the app IS free, does that count as a paid or free download and what is the user charged for the app?

When someone checks again on this thread could they please clarify this along with the above questions?

I realize it's a tough series of questions so while you're thinking about it (@Apple) can you also let me know why I am encountering so many 500 errors on calls that have worked fine for years? The errors seem to clear up after a while, but I'm not sure what the suggested delay should be for retrying a call that receives a 500. Currently I'm using 30m, does that sound reasonable to you guys?

Ok, I'm now noticing 404's coming back from an API call that has worked for years now. Specifically this is the error:

"errors" : [ { "id" : "90b84655-8c76-4647-b59c-e3bf357793ef", "status" : "404", "code" : "PATH_ERROR", "title" : "The URL path is not valid", "detail" : "The resource 'v1/appPriceSchedules' does not exist" } ]

Now I know this error has to be false because in the documentation here if you view the sample response and look at "manualPrices" it has the exact URL that I am calling (with a different appID of course)

"manualPrices" : { "links" : { "self" : "https://api.appstoreconnect.apple.com/v1/appPriceSchedules/6447402192/relationships/manualPrices", "related" : "https://api.appstoreconnect.apple.com/v1/appPriceSchedules/6447402192/manualPrices" } },

So can you explain why I'm now getting a 404 for this? Did something break on your end?

Also, why are all of the deprecated endpoints in the API (that are specifically "v1") being replaced with endpoints that also contain "v1" in the URL? Best practice would be to make a "v2" for the new endpoint, then deprecate, then remove the "v1". I really hope you guys aren't just actively "upgrading" the v1 API in place because that's beginner level server development and it's a HUGE pain for your API users.

Well I've been posting questions on this thread for over a year now with no input from Apple. @Apple, you do know that the ability to change pricing on our apps is part of our developer agreement right? And you do realize that with each iteration on your web portal you reduce that ability?

I can show that by not allowing me to set my pricing in the same way I did two years ago my monthly income on my apps has been reduced by $250. We are only 4 months into the year and I suspect that by the end of the year the financial impact will be greater. The reason I am trying to resolve the issue with the API is so I don't have to use the web interface which has degraded over the past year

Now that all the cards are on the table here, how about we discuss this API issue as I have described in the above 2 pages of posts.

Still at it here, trying to use some of the new tools that have been introduced since I started this unidirectional question answer session.

I thought it might be a good idea to try the new OpenAPI generator with the OpenAPI spec for the appstoreconnect api. But I'm encountering an issue there without even being able to get started.

Leaving the issue number here for reference: https://github.com/apple/swift-openapi-generator/issues/580

This has been going on for a while now and there hasnt been any clarity from apple and the documentation is a disaster. In my case, Im trying to automate creating new apps and submitting for review through fastlane and all of sudden submission no longer works asking for the app pricing and availability. The documentation only shows the territory part and its just a read resource. There is nothing about setting the price through the api. I then began this rabbit hole of trying to get this to work, even creating my own api requests with similar paths posted on this thread. Still no luck until now and it has been a while since I started this. I'm still waiting for anyone to be able to FINALLY go around this ridiculous and poorly documented resource. For such a very simple piece of information we need, the amount of work to get it is ridiculous. Hope we get anything from apple soon.

Here it is—after three days of effort, it's finally done. I hope this helps someone!

def set_app_price_to_zero(app_id, price_point_id, territory_id="USA"):
    
    # Sets the app's price to $0 for the USA territory.

    # Param:
    #   app_id (str): The app's ID.
    #    price_point_id (str): The price point ID for $0.
    #    territory_id (str): The territory ID, default is "USA".
    
    try:
        token = jwt_manager.get_token()  # Replace with your JWT token generation method
        headers = {
            'Authorization': f'Bearer {token}',
            'Content-Type': 'application/json'
        }

        url = "https://api.appstoreconnect.apple.com/v1/appPriceSchedules"
        payload = {
            "data": {
                "type": "appPriceSchedules",
                "relationships": {
                    "app": {
                        "data": {
                            "type": "apps",
                            "id": app_id
                        }
                    },
                    "baseTerritory": {
                        "data": {
                            "type": "territories",
                            "id": territory_id
                        }
                    },
                    "manualPrices": {
                        "data": [
                            {
                                "id": "manualPrice-0",
                                "type": "appPrices"
                            }
                        ]
                    }
                }
            },
            "included": [
                {
                    "id": "manualPrice-0",
                    "type": "appPrices",
                    "attributes": {
                        "startDate": None,
                        "endDate": None
                    },
                    "relationships": {
                        "appPricePoint": {
                            "data": {
                                "type": "appPricePoints",
                                "id": price_point_id
                            }
                        }
                    }
                }
            ]
        }

        response = requests.post(url, headers=headers, json=payload)
        
        if response.status_code == 201:
            print("App price set to $0 successfully!")
        else:
            print(f"Failed to set app price: {response.status_code}")
            print(response.json())
    except Exception as e:
        print(f"An error occurred: {e}")


if __name__ == "__main__":

# App ID and Price Point ID for $0
app_id = "**********"  # Replace with your app's ID
price_point_id = "eyJzIjoiNjczNjcxNzkzOCIsInQiOiJVU0EiLCJwIjoiMTAwMDAifQ"  # $0 price point ID

# Set the price to $0
set_app_price_to_zero(app_id, price_point_id)

@GrayDev, I think you should lookup the price_point_id each time; don’t hard-code it.

Anyway thanks for posting that, I hope OurBigAdventure will be pleased. It is quite similar to the code I linked to before for setting IAP prices ( https://developer.apple.com/forums/thread/732527 ), as I thought it would be.

@endecotp , You're correct about the price_point_id; it's a quick implementation for now. From what I understand, these price_point_id values have been quite stable over the years.

If I may add as well, this is how I get price points for $0.0 in USD and CAD, you can replace it with any currency.:

lane :get_app_price_points do |options|

    require 'json'
    require 'net/http'
  
    auth_token = options[:auth_token]  # Your App Store Connect API token
    app_id = options[:app_id]          # The app ID for which you want to list subscriptions
  
    # Define the URL for fetching subscriptions
    url = URI("https://api.appstoreconnect.apple.com/v1/apps/#{app_id}/appPricePoints?filter%5Bterritory%5D=USA,CAN&include=territory")
  
    # Create the HTTP request
    http = Net::HTTP.new(url.host, url.port)
    http.use_ssl = true
  
    # Set up headers for the App Store Connect API request
    headers = {
      "Authorization" => "Bearer #{auth_token}",
      "Content-Type" => "application/json"
    }
  
    # Prepare the GET request
    request = Net::HTTP::Get.new(url, headers)
  
    # Execute the request
    response = http.request(request)
  
    # Handle the response
    if response.code == "200"
        app_prices = JSON.parse(response.body)
        # UI.message("Subscriptions for app #{app_id}: #{response.body}")

        # Use the find method to get the free price point ID directly
        free_price_point = app_prices["data"].find do |price_point|
            price_point["attributes"]["customerPrice"] == "0.0"
        end

        free_price_point_id = free_price_point ? free_price_point["id"] : nil
        UI.message("Free Price Point ID: #{free_price_point_id}")

        # Return the ID of the price point with 0.0 price
        free_price_point_id
    else
      UI.error("Failed to fetch subscriptions: #{response.body}")
    end
  end

AppStoreConnect API - How to set pricing
 
 
Q