ProdVerdict
Stripe EntitlementsMigration verifierDeterministic

Migrating to Stripe Entitlements? Verify your migration is complete.

Stripe Entitlements makes Stripe the source of truth for feature access. The migration is the risky part — you have N users with has_paid_access=true in your DB and need to grant each of them the corresponding Entitlements feature in Stripe. Miss one, and a paying customer loses access. ProdVerdict catches both directions of drift.

Full migration guide — six steps from DB flags to Entitlements as source of truth.

The wedge

Stripe won't build this. We did.

Stripe's interest is adoption — they want you to use Entitlements. They don't want to build a tool that tells you your migration is incomplete. That's ProdVerdict's job. The entitlements-migration contract is a deterministic check that catches four classes of drift during migration.

Check 1

Migration gap

User has has_paid_access=true but no active Entitlements grant in Stripe. High severity. The user paid but Stripe doesn't know.

Check 2

Stale grant

Stripe has an active Entitlements grant but your DB says has_paid_access=false. Medium severity. Either flip the DB flag or revoke the grant.

Check 3

Duplicate grants

Same customer has the same feature granted twice — usually a manual-grant plus subscription-grant collision. Medium severity.

Check 4

Missing customer id

User has has_paid_access=true but no stripe_customer_id. Blocks migration — needs backfill. High severity.

Migration playbook

Six steps from DB flags to Entitlements

Step 1

Define Entitlements products and features in Stripe

Set lookup_key on each feature to match your plan slug (pro, starter). Attach features to products.

Step 2

Add the entitlements-migration contract to prodverdict.yml

Point it at your users table and your Stripe key. One block of YAML.

Step 3

Run the contract to find migration gaps

Every user your DB says is paid but Stripe doesn't know about surfaces as a high-severity finding.

Step 4

Backfill using the JSON output

Pipe --format json into a script that grants entitlements in Stripe for each flagged user.

Step 5

Re-run until it passes

Iterate until zero findings. Then flip your app to read from the Entitlements API.

Step 6

Switch the Access contract to stripe_entitlements source

Verify the steady state on a schedule. Remove the migration contract when you're confident.

Try it

See the engine work on a fixture first

No credentials, no git clone. The bundled demo runs the Access contract against a revenue-leak fixture and shows you what a FAIL looks like.

npx prodverdict@0.13.0 demo

Then read the migration guide or the Phase 6 design doc.