stubkit

Apple IAP

Apple receipt validation, done server-side.

Verify App Store receipts and JWS-signed transactions against Apple's authoritative endpoints, with sandbox/prod routing, retries, idempotency, and certificate pinning — all handled by Stubkit.

The problem with rolling your own Apple receipt validation

  • Apple's verifyReceipt endpoint is deprecated for new flows — the current API is the App Store Server API with JWS-signed responses that must be verified against a pinned certificate chain.
  • Sandbox and production receipts hit different endpoints. If you get the routing wrong, legitimate purchases fail silently.
  • Shared secrets rotate. Apple's App Store Server Notifications V2 must be verified against WWDR intermediate certificates that periodically rotate.
  • Network flakiness, rate limits, and duplicate notifications mean every team eventually builds their own retry queue and deduplication table — badly.

What Stubkit handles for you

  • App Store Server API + App Store Server Notifications V2 with full JWS verification and WWDR certificate pinning.
  • Automatic sandbox/production routing — no conditional code in your app.
  • Idempotent event processing keyed on Apple's transaction_id, so duplicate notifications never double-count.
  • Retry policy with exponential backoff on transient Apple failures, backed by a durable queue.
  • Normalised transaction stream that also includes Google Play and Stripe, so your app only reads one API.

See it in action

Ship the integration in minutes with the Stubkit SDK — the receipt flow, retries, and idempotency are handled server-side.

// Check a user's entitlement anywhere in your iOS / web / backend code.
// The actual receipt / JWS verification, sandbox-vs-prod routing, shared-secret
// rotation, and retry policy all live on the Stubkit side.

import { Stubkit } from '@stubkit/js';

const stubkit = new Stubkit({ apiKey: process.env.STUBKIT_PUBLISHABLE_KEY });

const entitlement = await stubkit.getEntitlement({
  appId: 'my-app',
  userId: currentUser.id,
});

if (entitlement.active) {
  // User has an active subscription — unlock premium features
} else {
  // Show the paywall (Stubkit-hosted or your own)
}

Common questions

What happens to the legacy verifyReceipt flow?+

Apple's legacy /verifyReceipt endpoint is still supported for older receipts, but new apps are expected to use the App Store Server API and App Store Server Notifications V2 — both of which return JWS-signed payloads. Stubkit implements both paths and normalises the result into a single transaction stream.

Do I need to handle the sandbox environment separately?+

No. Stubkit detects sandbox vs production transactions automatically — it tries production first, falls back to sandbox on the documented 21007 status code, and writes the result to your app's sandbox or live event stream so analytics stay clean.

How are Apple's JWS signatures verified?+

Stubkit verifies the JWS signature against Apple's root certificate chain (including WWDR intermediate pinning) on every inbound notification. Unsigned or tampered payloads are rejected before they ever reach your entitlement state.

Is this receipt flow idempotent?+

Yes. Every transaction_id is stored with a unique constraint, so duplicate Apple notifications or client-side restores are de-duplicated server-side. Your app will never see the same entitlement event twice.

Can I keep raw receipts for audit purposes?+

Stubkit retains the verified transaction records in your account indefinitely, accessible through the REST API and admin dashboard. Raw Apple-signed payloads are retained for 180 days for audit; contact support for longer retention on Business plans.

What's required on the Apple side?+

A single App Store Server Notifications V2 URL pointing at Stubkit, plus an App Store Connect API key for on-demand receipt lookups. The dashboard walks you through both in under 10 minutes.

Ship the integration, not the infrastructure.

Free forever on the starter tier. Full SDK support for iOS, Android, web, and server environments.

Start free

Already integrated? See pricing