kasskeep

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.

ChannelWhereWhat Kasskeep handles
Apple App StoreiOS appsStoreKit 2 JWS verification, App Store Server Notifications V2, subscription status, transaction history, refund consumption requests
Google PlayAndroid appsPlay Developer API verification, acknowledge and consume on your behalf, RTDN over Pub/Sub with OIDC checks, voided purchases
StripeWeb and desktopHosted Checkout sessions, verified webhooks re-fetched from the API, refunds, chargebacks, hourly event reconciliation
Test storeDevelopmentPurchases, 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.

  • purchase
  • subscription.started
  • subscription.renewed
  • subscription.product_changed
  • subscription.canceled
  • subscription.uncanceled
  • subscription.billing_issue
  • subscription.grace_period_expired
  • subscription.expired
  • subscription.paused
  • refund
  • refund.reversed
  • refund.consumption_requested
  • revoked
  • chargeback
  • chargeback.closed
  • ad.reward
  • test

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.

Read the docs