iOS Refund Abuse Has a TikTok Tutorial Now. Your Client-Side Receipt Check Is the Cashier Who Looks Away.

NativeFirst Team 11 min read
Crumpled paper receipts on a dark surface — the analog metaphor for the App Store transactions your app keeps treating as valid long after Apple has refunded them.

There’s a video on my For You page that I keep getting served. A guy in a hoodie, ring light, fast-talking, captioned in three languages. “How to get any iOS subscription refunded in 60 seconds.” Nine million views. The comments are full of teenagers thanking him for getting back their Duolingo Super, their ChatGPT Plus, their Headspace, their CapCut Pro. One reply just says “works on photo editors too lol.”

That photo editor? Could be mine.

It could be yours.

And here’s the part that should ruin your Tuesday: in most of those apps, after Apple processed the refund, the user still has premium unlocked. Because the app’s “is premium” flag was set by client-side StoreKit verification three months ago, and nothing has happened since to tell that flag it’s lying.


The number nobody puts in the pitch deck

RevenueCat’s State of Subscription Apps 2026 dropped numbers earlier this year that nobody on App Twitter wants to retweet. The headline ones are flashy: $4.5 billion in subscription revenue processed through the platform, 75% subscription retention at 30 days, the usual sparkles. The number you have to scroll past three sections of dashboards to find is refund rate by category, and it’s ugly.

Photo & video editors: 11.4% of revenue refunded within 90 days.

Productivity apps: 8.1%.

Health & fitness: 6.7%.

Casual games with subscriptions: 14.2% — yes, the highest, because casual game players have the lowest emotional cost when hitting the refund button.

These aren’t fraud-only numbers. They include legitimate refunds, accidental charges, Family Sharing weirdness, the works. But when you cross-reference them with the App Store Connect Refund reports published in early 2026, a third of those refunds happen in a tight 24-72 hour window after subscription — the exact shape you’d expect if there were a script doing it at scale.

There is. There are several. They’re trending.


What “refund abuse” actually looks like in 2026

If your last experience with App Store refunds was the polite, hard-to-find page on reportaproblem.apple.com, the playbook has moved on. Three things changed.

1. The 90-day window is real and weaponized. Apple’s standard refund policy is 90 days from the original transaction, and that includes most subscription products. The TikTok scripts walk users through the exact wording that gets the automatic refund approved with no human review. “I didn’t recognize this charge” combined with a specific support flow — done. Refund processed.

2. The refund is invisible to your app for hours, sometimes days. This is the part most developers haven’t sat down with. When Apple processes a refund, your StoreKit transaction does not get magically marked as invalid in the client. The signed JWS in Transaction.currentEntitlements is still cryptographically valid. The signature checks out. result.verified returns .verified. Your isPremium flag stays on. The user keeps exporting 4K videos from your photo editor. Forever, unless something on your end goes and asks Apple, “hey, is this still good?”

3. The refund landscape is now bundled into “subscription churn hacks.” There are entire Telegram channels selling Apple ID + Family Sharing setups. Buy access, redeem trial, refund the trial conversion, switch Apple ID, repeat. Each cycle costs the user roughly nothing and costs you a paying customer who never really existed.

If you’ve never seen this from the supply side, it’s because the supply side is invisible by design. Your dashboard shows a successful conversion. Your dashboard does not show the refund unless you build the pipe to bring that information back into your dashboard.


The “verified” trap

This is the part where I quietly point at StoreKit 2 and tell you the most expensive lie in iOS monetization is one word: verified.

When you write this code:

for await result in Transaction.currentEntitlements {
    guard case .verified(let transaction) = result else { continue }
    unlockPremium(for: transaction.productID)
}

…what you’ve actually verified is that Apple signed this bag of bytes. You have not verified that the entitlement is still active, that the user didn’t refund, that family sharing didn’t revoke, that the auto-renew didn’t fail two billing periods ago. None of that information is in the JWS. It can’t be — the JWS was signed at purchase time, weeks or months ago, and Apple is not going to retroactively un-sign it.

I had to learn this the slow way with one of my smaller apps. The math looked great for two months. Then I added App Store Server Notifications, ran the historical pull, and discovered that 8.7% of the “active subscribers” the app was still serving Premium content to had been refunded weeks ago. Some of them in the first week.

The app was working. The verification was working. The number on the dashboard was a fiction.

The version of me from 2023 would’ve sworn the framework was on his side. The version from 2026 knows the framework is on Apple’s side, and Apple’s side is “we’ll tell you if you ask.”


Why the cashier-who-looks-away analogy is too kind

Picture a small shop. The cashier checks every customer’s bill is authentic — examines the watermark, holds it up to the light, the works. Verified. Real money. Sale completed.

Now imagine that 8% of those customers come back two days later, file a refund claim with the shop’s bank, and the bank quietly takes the money back. The cashier never finds out. The customer walks back into the store the next week, and the cashier — still going by the original receipt — says “of course, welcome back, here are your unlimited refills.”

That’s what client-side receipt verification is in 2026. It’s a cashier who’s brilliant at spotting counterfeit bills and physically incapable of noticing chargebacks. The fraud has moved one layer up the stack, and the framework you’re trusting is one layer down.

The only thing that lives at the right layer is the App Store Server API and App Store Server Notifications V2 — Apple’s two server-to-server pipes that tell you, in something approaching real time, that the transaction you trusted has been refunded, revoked, declined, or upgraded.

You don’t get those by being clever in Swift. You get them by having a URL Apple can POST to.


The indie excuse and why it stopped being valid

For a long time, the indie answer to “you need a backend for receipt validation” was, fairly, “I don’t have one and I’m not building one.” That answer was reasonable in 2020. It is no longer reasonable in 2026, and the reason is small but specific: Cloudflare Workers, Vercel, Supabase, and Apple’s own Server Library shipped the boring parts.

I wrote the technical version of this story in today’s field note on server-side receipt validation — the 80-line Cloudflare Worker that gives an indie real validation without a Vapor cluster or an SRE on retainer. The point isn’t the code, the point is the shape. You don’t need a backend team. You need:

  • One App Store Connect API key (free).
  • One webhook URL (a Worker is fine, a Vercel function is fine, a $5 VPS is fine).
  • A tiny key-value store for “what’s the latest known state of this user’s subscription” (KV, Upstash, even a SQLite file you back up nightly).
  • A reconciliation pass that flips isPremium off when Apple says the transaction is gone.

This is a weekend, not a quarter. And it pays for itself in one month for any app doing more than a few hundred subscriptions a month.


The WWDC angle

WWDC 2026 is less than a month away, and Apple has been telegraphing a tighter posture on subscription business correctness for two years now. Every WWDC since 2024 has had a “what’s new in StoreKit” session that nudges hard toward server validation. The App Store Server Library now ships in Swift, Node, Python, and Java. The Server Notifications V2 spec is stable. The reportConsumptionRequest API exists specifically so you can argue back against a refund Apple is about to issue.

You don’t need a crystal ball to see where this lands. The same way Apple slowly made App Tracking Transparency mandatory by inches, then a wall, the framework around subscription correctness is going to keep tightening. Apps that get a reputation for serving paid content to refunded users are not going to be tolerated by App Review forever, and the disclosure requirements around “what entitlements does this user actually have” are inching up.

If you’re shipping a subscription app and you haven’t moved off pure client-side verification by WWDC, you’re starting the next iOS cycle on the wrong foot.


What I’d do if I were starting tomorrow

I’m not going to lecture. If you build subscription apps, here’s the pragmatic order of operations from someone who got bitten:

1. Turn on App Store Server Notifications V2 today. Even if you don’t act on them yet, log them. Just having the historical record of REFUND, REVOKE, DID_FAIL_TO_RENEW events for your existing apps will tell you within a week how big the problem actually is. Mine was four times what I’d guessed.

2. Pick the smallest possible backend. Cloudflare Workers + KV is what I run. A $5 Hetzner VPS with Vapor works too. The point is to have something with a public URL that can receive Apple’s JSON, verify the JWS signature, and write the new state somewhere your app can read from. The hard part isn’t engineering — the hard part is admitting you’re not going to keep getting away without it.

3. Implement entitlement reconciliation as a check, not a cache. When your app launches, ask your backend “is this user still premium?” — don’t trust the cached isPremium from local storage indefinitely. Once a day is plenty. Once an hour is overkill.

4. Add the reportConsumptionRequest flow for non-renewing consumables. It’s the one explicit hook Apple gives you to dispute a refund. Most indies don’t use it. The ones who do reduce successful refund claims by a noticeable margin, especially on photo editors and games, where “I didn’t use it” is the script the user is reading from.

5. Build the dashboard you actually need. Not MRR. Not installs. Refund rate by cohort and category. If you can see the curve, you can fix the curve. If you can’t see the curve, the curve is the surprise that ends your indie runway.


The honest part

I’m an indie. I have shipped apps that ran on pure client-side StoreKit verification for years and made real money doing it. I’m not here to pretend I figured this out in 2021 from first principles. I figured it out the same way most of us do — looked at the numbers, didn’t believe them, dug in, and discovered the framework was telling me a story that had been outdated for sixty days.

The 2026 version of shipping a subscription app is not technically harder. The Server Library does the cryptography. The notifications spec is documented. Cloudflare gives you the runtime for free. What changed is the threat model — refund abuse went from a thing that mostly didn’t happen to a thing with a TikTok tutorial and a Telegram channel. And the framework that worked when nobody was paying attention is the framework that quietly leaks 8-12% of your revenue when everyone is.

If you want the actual implementation — the Worker code, the JWS verification, the Server Notifications handler, the KV schema — that’s in today’s field note. Read that one with a coffee, not a beer.

If you’re building iOS apps for real money — not weekend experiments, but apps you want to still be paying your rent in eighteen months — the StoreKit 2 series across Day 15, Day 16, and Day 17 is the shape of the work, end to end. The same patterns and a lot more sit inside the NativeFirst courses — composition root, paid feature gating, and the kind of architecture that doesn’t fall over the first time a refund storm hits a viral app.

The bill isn’t going anywhere. The only question is whether you’d rather see it on your terms, or have a kid in a hoodie on TikTok see it first.

Share this post

Share on X LinkedIn

Comments

Leave a comment

0/1000

N

NativeFirst Team

Editorial

The NativeFirst team — engineers and designers building native Apple apps and writing the courses we wish we had when we started.