An iOS subscription or in-app purchase is reviewed as a chain, not a single screen. Apple looks at the product record in App Store Connect, the identifier the submitted binary actually requests, the paywall a stranger sees on first launch, the purchase and restore behaviour, and whether every intended item travelled with that version into review. One weak link fails the whole submission, and the failure message rarely tells you which link it was.

This guide is the map of that chain. It will not tell you your subscription is approved; nothing short of Apple’s decision does that. It will tell you where to look first, which fixes need a new build and which do not, and where the nine failure modes in this cluster branch off into their own diagnosis.

The workflow below was checked against App Review Guidelines on 4 August 2026, cross-referenced with Offer auto-renewable subscriptions for the current App Store Connect workflow. Apple owns the rule; this article owns the diagnosis.

The short version

  • Confirm agreements, tax, and banking tasks required for paid content are complete in your account.
  • Put related durations or tiers that represent one service in the appropriate subscription group.
  • Complete each product’s pricing, localization, and review information before assembling the submission.
  • Load title, billing period, and localized price from StoreKit rather than copying values into the app.
  • Show working Terms of Use, Privacy Policy, and Restore Purchases controls on the paywall.

Map the complete purchase chain

Three systems own three different things, and confusing them is where most subscription rejections start. App Store Connect owns the product record and the review state: name, price tier, group, and whether the item is currently included in a submission. StoreKit owns the transaction on the device: what actually gets purchased, at what price, for which identifier. Your entitlement layer, whether that is a server you run or a wrapper such as RevenueCat, decides what the paying user is allowed to do next.

A wrapper can coordinate product data and entitlement state across platforms, which is genuinely useful, but it does not create App Store Connect records or submit anything to Apple on your behalf. Write the product identifier down at each of the three boundaries and compare the strings character for character. A trailing space or a swapped hyphen is enough to make a product invisible to the exact build Apple is holding.

Configure products before polishing the paywall

Decide the purchase type before you touch the interface. Auto-renewable subscriptions belong inside a subscription group, even when you currently sell only one. A non-consumable is a durable, one-time unlock; a consumable is something the user spends and can buy again. Getting this wrong is expensive to fix later, because the product type changes restore behaviour and the promise you are making to the user, which usually means touching both App Store Connect and the app’s purchase code.

Complete every field on the product page, including localization and review information, before you go anywhere near the draft submission. A product that looks finished in Monetization can still be missing the detail that keeps it out of a review-ready state. If a subscription record refuses to leave a pending or incomplete status once everything visible looks correct, the fastest way to find the blocking field is the object-by-object walkthrough in subscription stuck in Waiting for Review, and a product that exists but never reached the reviewer at all has its own separate diagnosis in in-app purchase not submitted for review.

Build a paywall the reviewer can verify

A reviewer arriving at your paywall has no context beyond what is on the screen: what is being sold, the billing period, the localized price, what unlocks, and the policy links that back the purchase. None of that can depend on the reviewer already knowing your product. The full requirement list for that screen, including what “vague premium language” actually means to Apple, is covered in iOS paywall requirements rather than repeated here.

The screen you need reviewed does not have to exist behind a shipped release. You can make an unreleased paywall reachable and testable through TestFlight and Apple’s sandbox well before the app goes live, and the discipline for doing that safely is in App Review paywall testing. Whichever stage you are at, keep the screen useful when products fail to load: say the store is temporarily unavailable and offer a retry, rather than leaving a spinner that looks identical to a crash.

Assemble the review submission

Use Apple’s current submission help rather than a screenshot from an old tutorial; App Store Connect’s labels move. Add the app version and every intended in-app purchase or subscription item to the same draft submission, not to separate ones. If the current flow asks for a new subscription group that has not been approved before, include it exactly as instructed rather than working around it. Reopen the draft once everything is added and count what is actually present, item by item, before you select Submit for Review.

Run a distribution-build test

Test the archive you are about to submit, not a development build that merely resembles it. Install it through TestFlight or an equivalent distribution path, use a sandbox account, and record the product identifiers, storefront, build number, result, and whether the entitlement changed. Then reinstall and test restore from the same build. This is the only way to separate a defect in the shipped app from a local-development setup that never existed in what Apple received. If sandbox and production keep behaving differently for reasons you cannot explain, the four-environment breakdown in sandbox vs production purchases walks through why a paywall can work for you and not for App Review.

Keep a small evidence note with:

  • app version and build number;
  • product identifiers tested;
  • account type and storefront;
  • time of the test and observed result;
  • whether the entitlement changed after relaunch.

Choose the next action from the failed layer

Do not treat every purchase rejection the same way. The right fix depends entirely on which layer actually failed, and mixing up the layers is how founders end up shipping a new build for a problem that was really an incomplete draft submission.

Layer that failedWhat it looks likeNext actionNew build?
App Store Connect metadataProduct exists but review information, pricing, or localization is incompleteFinish the item and confirm it sits inside the draft you intend to submitUsually no
Submission assemblyThe product is complete but was never added to the app version’s draftAdd it with the current Add for Review flow and recheck the item countUsually no
Binary or purchase codeWrong identifier, wrong purchase type, broken StoreKit call, or paywall bugCorrect the code, test the exact archive, upload a new buildYes
Reviewer accessSetup is correct but the reviewer never reached the paywall or purchaseRewrite App Review Notes with a literal, reproducible pathUsually no
Apple’s message vs your testThe rejection describes behaviour your own testing cannot reproduceAsk for precise clarification, citing build and product IDs, before changing anythingNo, until you find a real defect

Do not appeal a defect you can reproduce yourself. Do not ship a new binary because one item was missing from a draft you could still edit. Let the failed layer, not habit, choose the branch.

Failure patterns worth checking first

  • The product identifier in code differs from the one in App Store Connect by a character neither side notices casually.
  • The paywall was only ever exercised against a local StoreKit configuration file, never a real product record.
  • The submitted app version omitted one of the intended purchase items.
  • A reviewer who already holds an entitlement from a prior attempt never sees the paywall at all.
  • A product-fetch failure renders as a permanent spinner instead of a message and a retry.
  • A RevenueCat Offering with no attached, imported products returns empty even though App Store Connect looks fine, which is a RevenueCat-side gap covered in RevenueCat products not loading during App Review.

These come from the maintained AppRejectKit subscription corpus: recurring diagnostic shapes, not a rejection-rate statistic. Apple’s current documentation remains the actual policy source.

Write notes a reviewer can execute without guessing

Review Notes are not marketing copy and not a summary of your app; they are a script the reviewer follows literally. State the exact app version and build, the product identifiers involved, any demo credentials, the precise taps from launch to the paywall, and the result that should follow a purchase or a restore. If a rejection specifically concerns a subscription’s ongoing value rather than its plumbing, the reviewer needs to see the recurring benefit named in these same notes; see subscription lacks ongoing value for how to state that without inventing a roadmap.

Keep the note factual. Describe what you tested, not what you assume will hold for every account or every storefront, and never suggest that a screen recording is a substitute for a submission that actually works.

What not to touch before you know the cause

Recreating a product, rotating an identifier, or switching purchase types before you have identified the failing object multiplies your problem: you now have new metadata to complete and old entitlement mappings to reconcile, on top of whatever caused the original rejection. Restore Purchases deserves the same discipline. A visible control that silently does nothing is a common, avoidable failure covered on its own in restore purchases on iOS; do not add a second restore button to “fix” it before checking whether the first one is even wired to a StoreKit call.

Avoid copying an App Store Connect path from a tutorial with no date on it. If your app or its purchase links reach users outside the usual in-app path, treat that separately too: external payment links are governed differently by storefront and app category, and guessing at a global rule is how a US-specific allowance ends up shipped worldwide by accident, as detailed in external payment links on iOS.

Review the entitlement, not only the transaction

A successful payment is a single event; the product you actually sold is the entitlement that follows it. After purchase, confirm the app unlocks the promised feature, that unlock survives a relaunch, and the same account resolves correctly on a second device. If a server is involved, record which transaction or entitlement identifier it accepted, without writing secrets into a log file you might later share as evidence.

Test cancellation and expiration through Apple’s sandbox tools, not by waiting out a real billing cycle. Access should stop when the entitlement lapses, while any durable content your product promises to keep should still be there. That boundary is specific to your product, so write it down before a rejection forces you to improvise an answer under pressure.

Keep App Store metadata and the in-app offer honest

The App Store description, screenshots, subscription localization, in-app paywall, and Review Notes are all describing the same product to two different audiences. A renamed tier or a changed billing period can leave stale copy sitting in one of those surfaces while the others move on. Walk all of them during every release check and delete any claim the build you are shipping cannot actually deliver.

Never hardcode a price into editorial copy meant to travel across storefronts; display the localized store price inside the app instead. Keep public metadata from contradicting the live offer, which matters more than usual once introductory pricing or multiple durations are in play.

Maintain the chain after approval, not just before it

Approval ends the review, not the maintenance. New products, price changes, an SDK upgrade, a remote paywall edit, or a backend migration can each quietly break a chain that was fine on submission day. Keep the product identifier map, the review path, the restore test, and the date you last verified your sources alongside your release documentation, not in someone’s memory.

When Apple changes an App Store Connect workflow, update your internal steps to match rather than preserving a screenshot from a previous release. The one thing that does not change is the standard itself: every review item, and the binary that exposes it, has to be complete, testable, and deliberately submitted.

Keep a release manifest for every paid feature

A short release manifest prevents the handoff mistakes that cause most of the patterns above. List the app version, build number, bundle identifier, subscription groups, product identifiers, product types, and the paywall’s entry point, along with the status each item showed when you assembled the draft. This is an internal record, not something you publish.

Assign an owner to each surface. A developer can verify the binary and the StoreKit calls. Someone with App Store Connect access has to verify the product metadata, agreements, and the draft’s item list separately. If RevenueCat or another service sits in between, verify its app, products, Offering, and entitlement mapping as its own step rather than assuming it inherited correctness from Apple’s side.

Keep that manifest next to the exact archive you tested. When a rejection lands, compare Apple’s message against that frozen state before you edit anything, so you know immediately whether the missing piece lived in the binary, in Apple’s configuration, or in a third-party dashboard.

What this page will not do for you

This guide gives you the release model and the first diagnostic pass for the whole chain. It will not reproduce every App Store Connect field, every stack-specific audit branch, or a complete reply library for each of the nine failure modes above, because those details shift with the app, the purchase type, the SDK, and the exact wording Apple used. Each linked article in this cluster goes one layer deeper into a single one of those failures; use this page to decide which one you need, not as a substitute for it.

Before the final submission, put a name and a date next to every completed check. That short sign-off is what makes a later investigation fast: you know who verified the build, who checked the purchase records, and which sandbox account ran the transaction, and it stops an old test result from being reused after the binary or a remote paywall has since changed underneath it.

FAQ about iOS subscription App Store review

Which of the nine failure modes should I check first?

Start with the layer that produced the actual message you received. A vague “purchase could not be completed” points at the binary or paywall; a status stuck on a product or group points at App Store Connect; an empty product list points at RevenueCat or release configuration. The decision table above maps the message to the layer before you touch anything.

Does fixing a subscription rejection always require a new build?

No. Product metadata, submission assembly, and clearer Review Notes can all be fixed without a new binary. Anything involving the code, the UI, an identifier, or purchase logic needs one. The failed layer decides, not habit.

Can a clean sandbox run guarantee approval?

No. It proves one controlled purchase path worked on the build and account you tested. App Review also weighs product rules such as ongoing value, disclosures, metadata accuracy, and whether every intended item was actually submitted alongside the binary.

Do I need to read all nine linked articles before I submit?

No. Read the one that matches your symptom. The pillar exists so you do not have to guess which of the nine applies; once you know, that single article has the deeper checks.


Conclusion

Treat the binary, product record, subscription group, paywall, reviewer path, and sandbox result as one release. A green build alone does not prove the paid flow is ready, and a single rejection message rarely names the exact link that broke.

Identify the failed layer from the list above, take the smallest action it supports, and keep the evidence with your reply so the next review starts from what you actually tested rather than another guess.


Sources and references