Omnichannel Entitlement Sync: Cross-Platform Subscription Access
How to build a reliable entitlement synchronization layer that keeps subscription access consistent across web, iOS, and Android using EventBridge, webhooks, and idempotent processing.
Abstract
When a product sells subscriptions across web, iOS, and Android, each platform emits its own subscription events with its own schema, lifecycle, and delivery delay. An entitlement synchronization layer is the piece that turns those heterogeneous events into a single consistent answer to "what can this user access right now?". A naive per-platform handler drifts out of sync within hours; the underlying problem is distributed state, not webhook plumbing.
This post shows how to design that layer on AWS EventBridge. It covers event normalization across Stripe, App Store Server Notifications v2, and Google Play RTDN; idempotent webhook handlers; a DynamoDB entitlement store; and the edge cases (refunds, family sharing, grace periods) that break cross-platform subscriptions in production.
The Cross-Platform Entitlement Problem
When your product accepts payments from multiple sources -- Stripe for web, Apple App Store for iOS, Google Play for Android -- each platform sends subscription events in its own format, at its own pace, with its own lifecycle model.
The challenge is not receiving these events. The challenge is turning them into a single, consistent answer to: "What can this user access right now?"
Each payment provider has different event names for similar concepts. Apple calls it DID_RENEW. Stripe calls it invoice.payment_succeeded. Google calls it SUBSCRIPTION_RENEWED. A renewal on Apple might arrive minutes after it happens, while Stripe fires almost immediately.
Without an entitlement layer, your application code ends up with platform-specific checks scattered everywhere. That approach breaks the moment you add a fourth payment source or change your subscription tiers.
Designing the Entitlement Layer
The entitlement layer sits between your payment providers and your application logic. It answers one question: given a user ID, what features and access levels are currently active?
Source of Truth Principle
The entitlement store -- not the payment provider -- is the source of truth for access decisions. Payment providers are the source of truth for billing state, but your entitlement store is the source of truth for what the user can do.
This distinction matters. A payment provider might report a subscription as "past_due" while the user still has access during a grace period. Your entitlement layer defines those rules, not the provider.
Entitlement Table Design
Entitlements are not simple booleans. A subscription can be active, in a grace period, paused, or in billing retry -- and each state maps to different access levels.
The source field tracks which platform created this entitlement. This becomes critical when handling conflicts -- if the same user subscribes on both Apple and Stripe, you need to know which entitlement takes priority.
Feature Mapping
Map subscription plans to concrete features rather than relying on plan names. This decouples your access logic from your pricing structure.
When checking access, query features rather than plan names:
Cross-Platform Sync Strategies
There are three approaches to keeping clients in sync with your entitlement store.
Polling
The client periodically calls your entitlement API. Simple to implement, but adds latency -- a user might wait up to the polling interval before seeing their access update.
Best for: applications where real-time access updates are not critical. Typical polling interval: 30-60 seconds for active sessions, 5 minutes for background.
Push (WebSocket / Push Notifications)
The server pushes entitlement changes to connected clients via WebSocket or mobile push notifications. Provides near-instant updates but adds infrastructure complexity.
Best for: applications where immediate access changes matter (collaboration tools, streaming services).
Hybrid (Recommended)
Combine server-side webhook processing with client-side smart polling. The server processes webhooks and updates the entitlement store immediately. Clients poll on a regular interval, but also refresh on specific triggers.
The key triggers for a forced refresh:
- App returns to foreground
- User completes a purchase flow
- Push notification received about subscription changes
- User navigates to a premium feature
Webhook Reliability
Webhooks are the backbone of server-side entitlement updates. But webhooks are unreliable by nature -- they can arrive out of order, be duplicated, or fail silently. Building a reliable webhook pipeline requires four patterns.
1. Queue-First Processing
Return HTTP 200 immediately upon receiving the webhook. Then process it asynchronously. This prevents timeouts and ensures the payment provider does not retry unnecessarily.
2. Event Normalization
Each provider sends different payloads. Normalize them into a common schema before further processing.
3. Idempotent Processing
Webhooks are delivered at-least-once. The same event can arrive multiple times. Use the event ID as an idempotency key with DynamoDB conditional writes.
The key insight: use both Powertools idempotency (for Lambda-level deduplication) and timestamp comparison (for handling out-of-order events). An event that arrives late should not overwrite a newer state.
4. Dead Letter Queue
Events that fail processing after all retries need somewhere to go. A DLQ captures these for investigation and replay.
EventBridge Entitlement Architecture
EventBridge is a natural fit for entitlement synchronization because it provides content-based routing, built-in retry, and native Lambda integration. Here is the full pipeline.
Event Bus and Rules
Create a dedicated event bus for entitlement events. Use rules to route events to the right processing targets.
Event Schema
Use a consistent event schema that carries all the context needed for entitlement decisions.
EventBridge provides built-in retry with exponential backoff -- up to 185 retries over 24 hours. Combined with the DLQ, this gives you multiple layers of failure protection.
Handling Multi-Platform Conflicts
The trickiest edge case: a user subscribes to your premium plan on both iOS (through Apple) and web (through Stripe). Now you have two active entitlements for the same feature set from different sources.
Conflict Resolution Strategy
Define a platform priority hierarchy. When conflicts arise, the higher-priority source wins for access decisions, but both entitlements remain tracked.
Warning: Do not automatically cancel the lower-priority subscription. Notify the user that they have duplicate subscriptions and let them choose which to keep. Automatic cancellation causes support tickets and chargebacks.
Grace Period Differences
Each platform handles grace periods differently:
- Apple: Configurable billing grace period of 3, 16, or 28 days (6 days for weekly subscriptions), followed by a 60-day billing retry window where Apple attempts to recover payment
- Google: Configurable grace period (up to 7 or 30 days), followed by an account hold period calculated as 60 days minus the grace period duration
- Stripe: Configurable retry schedule via Smart Retries with customizable dunning behavior
Your entitlement layer needs to map these platform-specific states to your own grace period logic. The safest approach: maintain access during any active grace period and let the entitlement expire only after all retry windows close.
Reconciliation
Even with idempotent processing and DLQs, drift happens. A scheduled reconciliation job compares your entitlement store against each payment provider's subscription API and fixes discrepancies.
Run reconciliation frequently enough to catch drift but not so frequently that you hit provider API rate limits. Every 4-6 hours works well for most products. Always log reconciliation fixes -- if you see many, your webhook pipeline has a gap.
Key Takeaways
-
Separate billing state from access state. Payment providers own billing. Your entitlement store owns access. This separation lets you handle grace periods, conflicts, and promotions without touching payment logic.
-
Normalize events early. Convert provider-specific webhooks to a common schema at the ingress point. Everything downstream works with one format.
-
Build for at-least-once delivery. Webhooks can duplicate. EventBridge retries. Use idempotency keys and timestamp comparisons to handle this safely.
-
Add reconciliation from day one. Webhook pipelines drift over time. A periodic reconciliation job catches issues before users notice.
-
Never auto-cancel duplicate subscriptions. When a user has subscriptions on multiple platforms, notify them and let them decide. The support cost of accidental cancellations far exceeds the engineering cost of handling duplicates.
If you are building a subscription product, the entitlement layer is one of the first cross-cutting concerns worth getting right. It touches every platform, every feature gate, and every user session. Investing in a clean event-driven architecture here pays compound returns as your product grows.
For the payment provider selection that feeds into this architecture, see Payment Providers and Compliance. For mobile-specific receipt validation that produces the Apple and Google events consumed here, see Mobile IAP and Paywall Strategies. For the subscription lifecycle management that triggers these entitlement changes, see Subscription Lifecycle Management.
References
- AWS EventBridge Documentation - Official guide for EventBridge event buses, rules, and targets
- AWS Lambda Powertools for TypeScript - Idempotency - Idempotency utility for Lambda functions with DynamoDB persistence
- RevenueCat: Cross-Platform Subscriptions - Engineering deep dive on cross-platform subscription challenges
- RevenueCat: Entitlements Documentation - Entitlement concepts and access levels for subscription apps
- Hookdeck: Implementing Webhook Idempotency - Patterns for making webhook processing idempotent
- Hookdeck: Webhooks at Scale - Production lessons on reliable webhook infrastructure
- Stripe Webhook Best Practices - Official Stripe guidance on webhook reliability and security
- Apple App Store Server Notifications V2 - Apple subscription lifecycle notification reference
- Google Play Real-time Developer Notifications - Google Play subscription event notification reference
- AWS EventBridge Pricing - Pricing details including free same-account delivery
- Qonversion: Cross-Platform Subscription Management Guide - Practical guide to managing subscribers across iOS, Android, and web