Features
Everything on this page is in the current release. Work that has not shipped yet is on the roadmap.
Store channels
Each payment channel is a plugin with a declared set of capabilities. All of them produce the same transactions, subscriptions and events.
| Channel | Where | What Kasskeep handles |
|---|---|---|
| Apple App Store | iOS apps | StoreKit 2 JWS verification, App Store Server Notifications V2, subscription status, transaction history, refund consumption requests |
| Google Play | Android apps | Play Developer API verification, acknowledge and consume on your behalf, RTDN over Pub/Sub with OIDC checks, voided purchases |
| Stripe | Web and desktop | Hosted Checkout sessions, verified webhooks re-fetched from the API, refunds, chargebacks, hourly event reconciliation |
| Test store | Development | Purchases, renewals, grace periods, refunds, revocations, upgrades and time travel, all tagged environment: test |
One event model
Store signals are normalized into a fixed list of event types. A renewal looks the same whether it came from Apple, Google, Stripe or the test store.
purchasesubscription.startedsubscription.renewedsubscription.product_changedsubscription.canceledsubscription.uncanceledsubscription.billing_issuesubscription.grace_period_expiredsubscription.expiredsubscription.pausedrefundrefund.reversedrefund.consumption_requestedrevokedchargebackchargeback.closedad.rewardtest
Signed webhooks
- Each event is POSTed to your webhook URL with a Kasskeep-Signature header: an HMAC-SHA256 over the timestamp and the raw body.
- Failed deliveries retry after 1 minute, 5 minutes, 30 minutes, 2 hours, 12 hours, 24 hours and 24 hours.
- Event ids are derived from the store event itself, so the same renewal reported by a notification, a client submission and reconciliation has one id.
- GET /v1/events returns every event in order with a cursor, for backfills and recovery.
- A test endpoint sends a signed test event to your URL and shows the response.
Reconciliation
- Apple: Notification History is pulled every hour, with an hour of overlap.
- Google: Voided Purchases API every hour, plus targeted checks of subscriptions near expiry or in grace, hold or pause.
- Stripe: the events API is replayed through the same handler as webhooks.
- Google acknowledgements and consumptions that fail are retried with backoff, well inside Google's 3-day refund deadline.
Accounts, roles and audit
- Your account is a tenant. Every business record carries the tenant id and is protected by Postgres row-level security, so no query can reach another account's data.
- Store credentials and webhook secrets are encrypted with AES-256-GCM under a key derived for your account alone, and can never be read back.
- Owner, admin, developer and read-only roles for your team. Sign-in requires a password and TOTP.
- Every management action is written to an audit log with before and after values, secrets redacted.
- Per-account rate limits and fair job scheduling, so a busy neighbor never slows your webhooks down.
Rewarded ads
- Server-side reward callbacks from AdMob (SSV, ECDSA), AppLovin MAX (S2S event token) and Unity LevelPlay (signed S2S, timestamp window, optional IP allowlist).
- Each verified view becomes one ad.reward event, signed and delivered like a purchase event.
- Map your own ad unit names to network ad unit ids, one name for both iOS and Android.
- Callbacks for ad units you have not mapped are rejected by default and listed so you can fix the mapping.
- Test mode produces ad.reward events without loading a real ad.
Client SDKs
- React Native and Expo: configure, getProducts, purchase, restore, getCustomer, listeners, pending transaction sync, web checkout and rewarded ads.
- WebView bridge for web games inside a native shell, with an origin allowlist and method allowlist.
- kasskeep-web.js: a dependency-free browser module for the bridge, the test store and Stripe Checkout.
Operations
- Kasskeep runs the service, the database, store polling and webhook delivery for you.
- The database is archived continuously with point-in-time recovery, backed up daily with encryption to off-site storage, and restored automatically every week as a drill.
- The service connects to its database with a role that row-level security applies to, and refuses to start if it does not.
- API paths are versioned under /v1 and only change additively.