RORK LABJP
TOOLING — Rork's developer repos keep moving: rork-xcode was updated on July 16, rork-device on July 15, and rork-plist on July 13OPUS46 — Claude Opus 4.6 is live in Rork, and Rork Max is built to assemble apps on top of Claude CodeSIM — A cloud iOS simulator runs in the browser, with one click to install on a device and two clicks to publish to the App StoreMAX — Rork Max emits pure Swift rather than React Native, reaching iPhone, iPad, Apple Watch, Apple TV, Vision Pro, and even iMessageNATIVE — That opens up HealthKit, ARKit and LiDAR, NFC, Dynamic Island, Live Activities, 3D through Metal, and on-device inference with Core MLSEED — Rork raised a $15M seed led by Left Lane Capital, with Peak XV and a16z Speedrun joining the roundTOOLING — Rork's developer repos keep moving: rork-xcode was updated on July 16, rork-device on July 15, and rork-plist on July 13OPUS46 — Claude Opus 4.6 is live in Rork, and Rork Max is built to assemble apps on top of Claude CodeSIM — A cloud iOS simulator runs in the browser, with one click to install on a device and two clicks to publish to the App StoreMAX — Rork Max emits pure Swift rather than React Native, reaching iPhone, iPad, Apple Watch, Apple TV, Vision Pro, and even iMessageNATIVE — That opens up HealthKit, ARKit and LiDAR, NFC, Dynamic Island, Live Activities, 3D through Metal, and on-device inference with Core MLSEED — Rork raised a $15M seed led by Left Lane Capital, with Peak XV and a16z Speedrun joining the round
Articles/Dev Tools
Dev Tools/2026-04-25Advanced

Outgrowing RevenueCat: A Self-Hosted Guide to App Store Server Notifications V2 for Rork Apps

A complete implementation guide for receiving App Store Server Notifications V2 in Cloudflare Workers without RevenueCat — covering JWS verification, idempotent state updates, user binding, and production testing for Rork apps.

StoreKit 216App Store Server API4Cloudflare Workers24Subscriptions15JWS3

Premium Article

If you've been running RevenueCat for a year or so, there's a good chance you've quietly started wondering whether the monthly fee will become a problem as MRR keeps climbing. I had the exact same feeling once revenue from three Rork-built apps started to compound. RevenueCat is genuinely a great service and I'd recommend it for the first subscription app you ship. But once the business has matured, it's also natural — perhaps inevitable — to want the verification logic living inside your own codebase.

This guide walks you through that "graduation" at the implementation level. Specifically, we'll build a minimal but production-ready setup: a Rork iOS app that completes purchases through StoreKit 2, a Cloudflare Workers endpoint that receives App Store Server Notifications V2 (ASSN V2 from here on), JWS verification of those payloads, and idempotent state writes to Cloudflare KV. Everything below is based on a configuration I'm running in production right now, including the missteps I made along the way.

Why Go Self-Hosted — This Isn't an Anti-RevenueCat Pitch

Before we dive in, let me say this clearly: I'm not trying to talk anyone off RevenueCat. For your very first subscription app, I'd actively recommend it. Building an in-house verification flow takes one or two weeks at minimum, and testing server-to-server notifications is much messier than it looks on paper. Burning that time before you've validated the product is almost always the wrong trade.

That said, the moment a few of these conditions hold, self-hosting starts being worth a serious look:

  • Monthly Tracked Revenue has crossed a threshold where RevenueCat's pricing tier visibly affects your margins
  • You want fine-grained billing logic per user — region-specific pricing, internal coupons, one-off offers — that doesn't quite map to what RevenueCat exposes through its dashboard
  • Audit or privacy requirements have started limiting where payment-related state can live, and "anywhere outside your servers" is no longer comfortable
  • You've started writing custom analytics on top of RevenueCat's webhooks and find yourself fighting their data model more than using it

If any of those resonate, self-hosting is genuinely worth the engineering investment. On the other hand, if MRR hasn't really lifted off yet and the only motivator is "the cost feels uncomfortable," I'd hold off. A single verification bug can stop a day of revenue, and that lost day will almost always cost more than a year of RevenueCat fees. The way I've come to think about it: leave RevenueCat the moment its abstraction stops compressing your work, and not a moment earlier.

The Big Picture: StoreKit 2 → ASSN V2 → Cloudflare Workers → KV

Before any code, let's pin down the data flow:

  1. The user purchases a subscription inside the Rork app — StoreKit 2 handles the transaction
  2. After completion, Apple's servers send a JWS-signed notification (ASSN V2) to a URL you've registered
  3. Cloudflare Workers receives the notification and verifies the JWS against Apple's root certificate chain
  4. From the verified payload we extract originalTransactionId and notificationType, then write idempotently to Cloudflare KV
  5. On app launch, the client asks the server for its current entitlement instead of relying purely on local state

The key idea is that the source of truth lives along the Apple → Workers → KV path. Trusting Transaction.currentEntitlements on the client alone leaves you exposed to clock manipulation and receipt tampering, and — just as importantly — your server has no idea who currently has an active subscription, which kills any downstream operation like targeted email or churn-prediction work.

There's also a more subtle benefit to this layout. Because the client's role shrinks to "trigger the purchase, then ask the server what's true," you stop accumulating fragile state on devices. Lost devices, restored backups, switched Apple IDs — all of these become server-side reconciliation problems instead of client-side bugs. That alignment with the server is, to me, the single biggest reason this architecture pays off in the long run. It also turns out to be how you sleep well at night: when something does go wrong, you can answer it from inside your own code, with logs you wrote and data you control, instead of refreshing someone else's status page and hoping their team is awake.

Thank you for reading this far.

Continue Reading

What follows includes implementation code, benchmarks, and practical content we hope you'll find useful. This site runs without ads — server and development costs are supported entirely by members like you. If it's been helpful, we'd be truly grateful for your support.

WHAT YOU'LL LEARN
Indie developers who feel RevenueCat's monthly fee is starting to weigh on their margins can now move to a self-hosted Cloudflare Workers receiver for App Store Server Notifications V2
You'll learn how to verify JWS signatures, handle replay-safe status transitions, and update subscription state idempotently — with working code that runs in a Rork project
By switching to a self-hosted setup you can drive fixed costs close to zero and keep full control over the verification logic that powers your subscription business
Secure payment via Stripe · Cancel anytime

Unlock This Article

Get full access to the rest of this article. Buy once, read anytime. This site is ad-free — your support goes directly toward keeping it running.

or
Unlock all articles with Membership →
Share

Thank You for Reading

Rork Lab is ad-free, supported entirely by members like you. We publish practical guides daily with implementation code, benchmarks, and production-ready patterns. If you've found it useful, we'd love to have you on board.

  • Copy-paste ready implementation code
  • New advanced guides published daily
  • $5/mo or $10 for lifetime access
View Membership →

Related Articles

Dev Tools2026-06-30
Answering a Refund Request Within 12 Hours: Handling CONSUMPTION_REQUEST in Cloudflare Workers
How to receive the App Store CONSUMPTION_REQUEST notification for your Rork subscription app in Cloudflare Workers and respond to the Send Consumption Information API within 12 hours — with field-by-field mapping and the operational judgment behind it.
Dev Tools2026-05-20
Rork × StoreKit 2 × App Store Server API — A Three-Layer Subscription Architecture for Indie Apps
How to combine StoreKit 2 and Apple's App Store Server API to protect subscription revenue in Rork iOS apps with three coordinated layers: client verification, server-side JWS validation, and notification reconciliation.
Dev Tools2026-07-11
Verifying StoreKit 2 Signed Transactions in a Cloudflare Worker
If you trust whatever the device says about its purchase state, a tampered entitlement walks right through. This walks through verifying StoreKit 2 signed transactions (JWS) in a Cloudflare Worker so you grant entitlements without trusting the client, with working code.
📚RECOMMENDED BOOKS
Build a Large Language Model (From Scratch)
Sebastian Raschka
LLM Dev
Prompt Engineering for LLMs
Berryman & Ziegler
Prompting
AI Engineering
Chip Huyen
AI Eng
* Contains affiliate links
See all →