Last Week
Last week, the iOS review process had narrowed to a single blocker: Apple’s reviewer still objected to Shokken’s one-day and three-day paid access options. Android is already live on Google Play, and the current iOS development work for this submission is done, but production App Store access is still held up by the way short-duration access is represented.
At that point, I still wanted to defend the product model. The short passes are meant to be non-renewing access for businesses that only need Shokken for a specific event, weekend, or busy service window. They are not meant to be auto-renewing subscriptions. I responded to Apple with that distinction and pointed back to the relevant App Store language.
This week, Apple answered more directly. They called me.
The Policy Fight Is Over
The surprising part of the week is that App Review picked up the phone.
An Apple reviewer called a couple of days ago and talked through the issue with me. That part was genuinely useful. The reviewer was polite, had looked into the policy, and explained Apple’s review position clearly: for this submission, they are treating even the non-renewing short-duration products as needing to be at least seven days long.
I still think that is a strange interpretation.
Apple’s App Review Guidelines place the seven-day minimum inside the auto-renewable subscription section. Apple’s App Store Connect reference also distinguishes between consumables, auto-renewable subscriptions, and non-renewing subscriptions. On top of that, the App Store Connect tooling itself allows short non-renewing products to be created, while enforcing the seven-day minimum for auto-renewable subscriptions.
That combination is confusing. The written guideline, the product taxonomy, and the tooling all make it look like short non-renewing access should be possible. But the reviewer is telling me that the app will not pass review with those products configured that way.
At this point, continuing to argue is not worth it.
This is the third rejection for the same underlying issue. Even if I believe the review team is applying the policy more broadly than the text suggests, I cannot keep spending weeks trying to win an interpretation dispute. Shokken needs to ship on iOS.
The reviewer did offer a practical path: convert the one-, two-, and three-day passes from non-renewing subscriptions into consumable in-app purchases. That is now the plan.
What does it mean in English?
Apple does not want Shokken’s short access passes represented as non-renewing subscriptions.
Instead of fighting that decision again, I am changing how the short passes are sold. A consumable purchase is normally something a user buys, uses up, and can buy again. In Shokken’s case, the app can treat a consumable purchase as a short access pass: buy the one-day pass, get one day of paid access; buy the three-day pass, get three days.
From a customer point of view, the goal is the same. A restaurant or event operator can still buy a bounded amount of access without committing to a monthly plan.
From an implementation point of view, it is not the same at all. The product type changes, the revenue integration changes, the paywall changes, the app code changes, and the backend has to record and enforce the access window correctly.
So this is not a label edit. It is a small product decision with a surprisingly large technical footprint.
Nerdy Details
The call helped, even though the answer did not
The phone call changed the shape of the problem.
Before the call, I was still in documentation mode. I had the text of the guidelines, the product definitions, and the behavior of App Store Connect’s product creation tools. All of those seemed to support the idea that a short non-renewing subscription should be valid.
After the call, the situation is clearer: App Review does not want this version of the product model.
That does not fully resolve the policy ambiguity, but it does resolve the operational question. The app has already been rejected three times for the same issue. A fourth attempt with a slightly different explanation would be gambling more calendar time on a reviewer changing course.
That is not a good use of time anymore.
The useful thing about the call is that it moved the discussion from abstract disagreement to an actionable workaround. The reviewer suggested consumables. I may still find the product taxonomy odd, but if consumables are the path App Review is willing to accept, then that is the path I need to implement.
Why the original model made sense
The original model was non-renewing short access.
That fit the product naturally. Shokken is not only for restaurants that need waitlist tooling every day. It can also support temporary operating windows:
- a single special event
- a weekend rush
- a pop-up
- a food truck service
- a festival booth
- a seasonal crowd spike
For those cases, a recurring monthly subscription is not the right shape. The customer does not need a month. They need a few hours or a few days of reliable guest communication and queue management.
That is why the short passes exist. A limited-duration purchase lets a business pay for the actual window where Shokken is useful. It avoids making a temporary user buy a full recurring plan, and it avoids building the business around cancellation friction.
That model still matters. The implementation mechanism is changing, but the product reason is not.
What changes when a pass becomes consumable
A non-renewing subscription and a consumable purchase can both be used to sell temporary access, but the system responsibilities are different.
With a non-renewing subscription, the product type itself describes a limited-duration service. The store purchase history and subscription category line up with the idea of access for a period of time.
With a consumable, the store sees a product that is bought, used, and can be bought again. That means Shokken has to be more explicit about what “used” means.
For a one-day pass, “used” does not mean the customer tapped one button and the purchase disappeared. It means the purchase created an access grant that lasts until a specific expiration timestamp. The app and backend both need to understand that timestamp. The backend needs to know which tenant received the grant, which product created it, how long it lasts, and whether it is currently active.
That changes the responsibilities:
- App Store Connect needs consumable products for the short passes.
- RevenueCat needs updated products, offerings, and package mappings.
- The paywall needs to present the products as passes, not subscriptions.
- The mobile app needs to purchase consumables and show the resulting access window.
- The backend needs to persist the access grant.
- Server-side checks need to enforce expiration.
- Review notes need to explain the new model clearly.
The biggest conceptual shift is that the access grant becomes Shokken’s responsibility. The store sells the item. Shokken decides what that item unlocks and for how long.
The backend cannot treat this as a UI-only change
It would be dangerous to implement this only in the app.
If the client buys a consumable and locally decides “this restaurant has access for three days,” that state is too easy to lose, duplicate, or disagree with. A restaurant could use multiple devices. A host might reinstall the app. A purchase callback might succeed while a network request fails. A transaction might be replayed by accident during retry handling.
The backend needs to be the source of truth.
The safer model is:
- The app completes a purchase through the store and RevenueCat.
- The app sends the relevant purchase/customer state to the backend or the backend receives it through the revenue integration.
- A server-side function validates the event and maps it to a tenant.
- The backend creates or extends an access grant.
- The app asks the backend what the tenant can currently use.
That flow gives me a place to make the operation idempotent. If the same purchase event arrives twice, it should not grant double access. If the backend has already processed a transaction identifier, it should return the existing result instead of extending the pass again.
It also gives me a clean expiration model. The database can store the active paid-until timestamp, and the backend can decide whether messaging-heavy paid features are currently available. The app can display that state, but it should not invent it.
RevenueCat still sits in the middle
RevenueCat is part of the blast radius because it is the revenue layer between the app and the stores.
The current offering configuration is built around the existing product types. Moving the short passes to consumables means updating the catalog and making sure the app requests the correct offerings. Product identifiers need to be stable and clear enough that the app, backend, and review notes are all talking about the same things.
The entitlement model also needs attention. Recurring plans still behave like recurring plans. Short consumable passes behave more like one-time purchases that create a limited access window. Those two shapes may both unlock paid Shokken functionality, but they should not be modeled so loosely that expiration bugs become likely.
The app needs to answer questions like:
- Does this customer have an active monthly or quarterly plan?
- Did this customer buy a short pass?
- Has that short pass been recorded on the backend?
- When does the access window expire?
- What should the paywall show if access is currently active?
- What happens when the access window ends?
Those questions are not purely visual. They affect which actions are available and whether Shokken should allow paid communication features for a tenant.
The database and functions need a small access ledger
The database change is probably the most important part of doing this safely.
I need a durable record of short-pass purchases and the access grants they create. That does not have to become a giant billing subsystem, but it does need a clean enough shape to survive retries, device changes, and support questions.
At minimum, the backend needs to know:
- tenant or account receiving access
- store platform
- product identifier
- transaction or purchase identifier
- purchased duration
- grant start time
- grant expiration time
- processing status
The transaction identifier matters because it lets the backend avoid double-processing the same purchase. The product identifier matters because it maps the purchase to a duration. The expiration time matters because the app should not keep paid features active after the pass has ended.
The edge functions or RPC paths that currently check paid access also need to recognize the new grant type. A monthly subscription, a quarterly subscription, and a consumable three-day pass are different billing objects, but they may all answer the same product question: does this tenant have paid access right now?
That is the abstraction I need to preserve.
Testing has to cover the awkward cases
The happy path is easy to imagine: buy pass, access turns on, expiration appears, everything works.
The real test cases are the awkward ones:
- buying a pass while already on a recurring plan
- buying another pass before the current pass expires
- purchase succeeds but backend recording fails
- backend receives the same transaction twice
- app is reinstalled during an active pass
- pass expires while the app is open
- Android keeps working with its existing purchase model
- App Review can find and understand the new product flow
Those cases determine whether this is a real billing implementation or just a UI workaround.
For example, if a user buys another one-day pass before the current one expires, should that extend the current expiration or start a separate access window? Extending is probably the least surprising behavior, but it needs to be explicit. If the backend receives duplicate transaction events, it must not extend twice.
The App Review test case is its own category. The reviewer needs to see that the products are consumables, that the paywall language no longer looks like a sub-seven-day subscription, and that the app clearly grants access after purchase. The review notes need to be written for that exact path.
Shipping beats winning the interpretation dispute
The lesson this week is not that the original product idea was wrong.
The lesson is that platform review is part of the product constraint. If App Review will not accept a model, then the practical question becomes how much time I am willing to spend proving a point before adapting.
I am past that line.
I still want customers to have short access options. I still think those options fit the business problem. I still think they are more honest than forcing every temporary user into a recurring monthly plan. But I do not need the App Store product type to match my preferred taxonomy if another acceptable type can support the same customer experience.
So the next implementation step is clear: rebuild the short passes as consumables, adjust the app and backend around that model, and resubmit.
It is more work than I wanted. But it is concrete work, and concrete work is better than another week of waiting for App Review to agree with me.
Next Week
Next week is about implementing the consumable-pass model.
I need to create the new short-pass products, update RevenueCat, adjust the paywall, change the app purchase handling, update the backend access model, and test the end-to-end purchase and expiration flow. I do not expect to finish all of that until I am back on dry land, but the direction is no longer ambiguous.
The goal is simple: preserve the short-term access product, remove the App Review blocker, and get the iOS submission moving again.