Your First In-App Purchase Has to Ride With an App Version in App Store Connect
DEV Community

Your First In-App Purchase Has to Ride With an App Version in App Store Connect

Originally published on hexisteme notes.

On October 29 I went to submit the 1.0 of one of my apps, and that version carried the app's first in-app purchase, a non-consumable product. My normal release path submits the version, so on this release it would have left the product behind.

I did the setup through the API, got both items into a single submission through a short web flow with two traps in it, and then checked the result through the API. My record ends at WAITING_FOR_REVIEW for both items, so I can't tell you how the review went.

What Apple says

Apple's help page Overview for configuring In-App Purchases states the rule directly: If you're submitting your first In-App Purchase, you must submit it with a new version of your app.

The product screen in App Store Connect shows its own wording of the same rule: "Your first In-App Purchase must be submitted with a new app version". The rule is about the first one, so everything below applies only to the first.

The API page Managing In-App Purchases settles the automation question in an Important note: Submit your first In-App Purchase together with an app binary submission through appstoreconnect.apple.com. The review-submission API calls below don’t apply to that first submission. For subsequent In-App Purchases, submit using the API endpoints below without an associated app binary submission.

So the documented route for a first purchase is the website.

The API flow the note points to for later purchases is POST /v1/reviewSubmissions, a reviewSubmissionItems item with an inAppPurchaseVersion relationship, then submitted: true. The same page marks POST /v1/inAppPurchaseSubmissions deprecated as of 4.4.1 and sends new integrations to that review submissions workflow. I followed the note and never sent those calls for a first purchase, so I have no API error to show you.

One warning about how I checked: when I read the page through a scraper on November 4, the markdown had dropped the Important note, and I nearly wrote that Apple's API docs didn't mention the first purchase. The page's raw doc data has it. If a claim hangs on an Apple doc page, read the note boxes on the page itself.

Why my automation didn't carry the product

My normal release path is fastlane submit_review and a 3-step reviewSubmissions script. Both submit the version. If I had used either one here, the purchase would not have gone in.

A version approved without its product leaves one of two endings: a buy button that gets rejected, or a product waiting for the next version. I didn't run it that way, so those are the outcomes I was steering around and not something I observed.

One read also failed in a way that is easy to over-interpret. I asked the items endpoint to include the product:

GET /v1/reviewSubmissions/{id}/items?include=inAppPurchaseV2 -> 400 'inAppPurchaseV2' is not a valid relationship name

That 400 says the name is not accepted on this read. It says nothing about submitting a first purchase, and I don't use it as evidence for that. Apple's note is the evidence. It does mean this include can't show you the product inside a submission, which comes back when you verify the result.

Two traps in the web flow

Both traps involve the Add for Review button, which appears on the version screen and on the product screen.

The product button opens a menu. Add for Review on the product screen doesn't add the product directly. It opens a menu with two entries:

  • "iOS submission draft (1)"
  • "Create new submission"

Nothing happens unless you choose the existing draft. "Create new submission" would split the product from the version, which is the separation Apple's rule says not to make, so I did not take that entry.

The draft dialog covers the product button. Add for Review on the version screen first opens a "submission draft" dialog, and that dialog covers the Add for Review button on the product screen. My first click on the product button returned OK and had no effect, because the dialog was covering it. After I closed the dialog and clicked again, the menu appeared, and a MutationObserver caught its text.

I didn't check why a click on a covered button comes back OK. The practical result is that the OK told me nothing about whether the menu had opened.

A warning you can clear ahead of time

After the version's Add for Review, a warning said content rights info must be set in app info. contentRightsDeclaration is an app-level value, so a version metadata push doesn't fill it. Apps that have already shipped have it set, so you only hit this on a first app. It takes one API call, so I list it with the API work below, where it gets done before the web step starts.

The order that worked

The rule I kept: do everything the API can do first. That shrinks the web part to making the draft, putting the product in the draft, confirming two items, and submitting.

The API part uses key auth with a JWT of at most 1200 seconds. I wrote about that JWT expiry hard cap in Three App Store Connect API Hard Limits That Only Bite at a Fast Release Cadence.

The calls:

  • Attach the build: PATCH /v1/appStoreVersions/{ver}/relationships/build with {data:{type:"builds",id}}, which returns 204.
  • Set the release type: PATCH /v1/appStoreVersions/{ver} with releaseType as MANUAL or AFTER_APPROVAL.
  • Set content rights: PATCH /v1/apps/{app} with contentRightsDeclaration as DOES_NOT_USE_THIRD_PARTY_CONTENT or USES_THIRD_PARTY_CONTENT.
  • Check the product: GET /v2/inAppPurchases/{id} should return READY_TO_SUBMIT.

By this point the review screenshot, notes, price, and localizations were done.

Then the web part, in this order:

  1. On the version screen, press Add for Review and keep the attached build. A "submission draft" appears.
  2. Close that dialog.
  3. On the product screen, press Add for Review, the button outside any dialog.
  4. In the menu, pick the iOS submission draft, not Create new submission.
  5. The draft dialog must show 2 items ready, the version and the product. Press Submit for Review, and the screen reports "2 items submitted".

The version goes first so the product's menu has an existing draft to choose. The close step is there because leaving the dialog open is what made my first click do nothing.

Confirming it through the API

A successful click is not evidence. I had just seen one return OK and change nothing, so I check the item count on screen and through the API, and I don't submit a draft without the product.

After submitting, I ran these reads:

  • GET /v1/reviewSubmissions?filter[app]=<appId> -> state WAITING_FOR_REVIEW
  • GET /v1/reviewSubmissions/{id}/items -> 2 items
  • GET /v2/inAppPurchases/{id} -> WAITING_FOR_REVIEW

In the items response, the version item has an appStoreVersion relationship and the product item shows no relationship. So the product's item doesn't identify itself as a purchase there, and the include from earlier returns a 400. The count comes from that response and the product's state comes from its own endpoint, so I run all of these reads.

If you set releaseType to MANUAL, a person presses release after approval.

What I haven't established

The review outcome. My record stops at WAITING_FOR_REVIEW for both items, so nothing here shows that this submission passes review.

Other product types. I only ran the non-consumable case, on one app.

Why the screens behave this way. I recorded what they did on October 29 and didn't look into how they work.

This procedure is the one I know works up to the review queue. The next thing to check is how the review ends, and whether a first subscription needs the same path, which I haven't run.

Email list for these notes: hexisteme.beehiiv.com - no issue has gone out yet, so you would be on it before the first one. No welcome sequence, no course, no upsell. More notes at hexisteme.github.io/notes.

Read on DEV Community ↗ ← Back to News

Comments

No comments yet. Start the discussion.