Fresh Stripe testing matrix

Fresh Stripe testing matrix

Run a structured Stripe test pass that covers supported migrations, blockers, reruns, and audit outputs before using RevBridge on a real acquisition.

Updated Jul 5, 2026

Use this matrix when restarting end-to-end testing from scratch. Each scenario should be tested with two Stripe test accounts: a seller/source account and a buyer/destination account.

Baseline setup

Before each scenario:

  • Create a fresh RevBridge project.
  • Use same-mode Stripe keys from two different accounts.
  • Use normal Stripe test-mode subscriptions for this matrix, not Stripe Test Clock subscriptions. Stripe's subscription list API omits Test Clock subscriptions unless filtered by a specific test clock or customer, and RevBridge v1 does not ask for a Test Clock ID.
  • Copy customers from source to destination with Stripe Customer Data Copy, then upload the unmodified mapping CSV.
  • Include every source customer that has a billing-relevant source subscription in the uploaded mapping. RevBridge ignores terminal canceled and incomplete_expired subscriptions, but active, trialing, incomplete, past-due, unpaid, and paused subscriptions must be represented so dry-run can either migrate or block them.
  • Run dry-run, review blockers and warnings, then execute only when the expected outcome below says the scenario should be executable.
  • After execution, verify destination subscription state, source cancel_at_period_end, CSV audit, and PDF audit.

Supported migration scenarios

ScenarioStripe setupExpected dry-runExpected execution
Monthly paid subscriptionSource customer with one active monthly licensed subscription and one card.Clean CREATE_SUBSCRIPTION; maybe price/product clone actions.Destination subscription is active, period end matches source item current_period_end, source is set to cancel at period end.
Annual paid subscriptionSame as monthly, but annual recurring price.Clean CREATE_SUBSCRIPTION.Destination period end remains the annual renewal date; no immediate renewal shift.
Quarterly or weekly subscriptionSame as monthly, but a price with interval=month, interval_count=3 or interval=week.Clean CREATE_SUBSCRIPTION with the source interval.Destination period end matches the source renewal; later renewals follow the same cadence.
Multi-item subscriptionSource subscription with two licensed items on the same interval and period end (one shared destination price, one missing).Clean CREATE_SUBSCRIPTION with one items entry per item; CLONE_PRICE only for the missing price.Destination has one item per source item with matching quantities; source is set to cancel at period end.
Inclusive tax_behavior priceSource price has tax_behavior=inclusive.Clean CREATE_SUBSCRIPTION.Cloned destination price preserves tax_behavior; renewal amount matches source; destination automatic tax stays disabled.
Mid-window repeating couponAttach a 3-month repeating percent coupon, let one discounted invoice finalize, then migrate.Clean coupon clone action carrying the remaining whole months.Destination discounts exactly the remaining discounted renewals; compare source and destination upcoming-invoice previews.
Expiring repeating couponRepeating window ends before the subscription's next renewal.Warning REPEATING_COUPON_EXPIRES_BEFORE_RENEWAL; no destination coupon planned.Destination renews at the undiscounted amount, same as the source would.
Scheduled custom cancel_atSource subscription has cancel_at set beyond the next renewal (not via cancel_at_period_end).Warning SOURCE_CANCEL_AT_PERIOD_END_MIRRORED describing the mirrored timestamp.Destination subscription carries the exact cancel_at; source is set to cancel at period end.
Non-collecting recurring subscriptionSource customer with one active licensed subscription (any documented interval) whose recurring amount is provably zero: fixed price 0, quantity 0, or a supported subscription-level forever coupon that fully discounts the subtotal. The source and destination customer may have no cards.Clean CREATE_SUBSCRIPTION with requiresPaymentMethod=false.Destination subscription is active, period end matches source item current_period_end, and no payment method is bound.
Existing source cancellationSet the source subscription to cancel at period end before dry-run.Warning SOURCE_CANCEL_AT_PERIOD_END_MIRRORED.Destination subscription also has cancel_at_period_end=true; source remains canceling.
Forever percent couponAttach a subscription-level forever percent coupon.Clean clone/reuse coupon action.Destination subscription discount matches source discount.
Forever amount couponAttach a subscription-level forever amount-off coupon with currency.Clean clone/reuse coupon action.Destination amount-off discount matches source.
Unconsumed once couponAttach a subscription-level once coupon before it has been applied to a finalized/open/paid invoice.Clean coupon action while the latest source invoice has not consumed the coupon.Destination receives the once coupon exactly once.
Visible full once coupon without cardsAttach a subscription-level once coupon that fully discounts the next invoice, then remove all source/destination card instruments.SOURCE_CUSTOMER_NO_PAYMENT_METHOD or DESTINATION_CUSTOMER_NO_PAYMENT_METHOD.Do not execute; a once coupon can still lead to non-zero future renewals.
Consumed once couponLet the once coupon apply to a finalized/open/paid invoice. Test both when Stripe removes it from the subscription and when it remains visible on the subscription.Warning ONCE_COUPON_ALREADY_CONSUMED; no destination coupon should be planned.Destination renews at normal future amount.
Voided once-coupon invoiceLet a once coupon appear on a latest invoice, then void that invoice.Blocker VOIDED_ONCE_COUPON_UNSUPPORTED.Resolve manually; RevBridge cannot infer whether the once coupon should be consumed or still pending.
Active trial with cardSource subscription is trialing with future trial_end and a card.Clean action with trial_exact_end; warning if trial is near its end.Destination preserves trial end when Stripe accepts it; near-term fallback preserves next charge timing.
Active trial without source cardSource trial has no source payment instrument; destination customer has at least one copied card.Warning TRIAL_WITHOUT_PAYMENT_METHOD.Destination trial is preserved; operator must verify the buyer-side customer has the intended card before renewal.
Customer default fallbackSubscription has no default payment method, but source customer has invoice_settings.default_payment_method.Warning SOURCE_CUSTOMER_DEFAULT_PAYMENT_METHOD_USED; destination card match required.Destination subscription is explicitly bound to matched buyer pm_....
Oldest card fallbackNo subscription or customer default; source customer has cards.Warning SOURCE_CUSTOMER_OLDEST_PAYMENT_METHOD_USED or SOURCE_CUSTOMER_OLDEST_SOURCE_USED.Destination subscription is explicitly bound to the matched oldest card.
Latest invoice evidence fallbackNo current defaults; latest invoice has PaymentIntent, PaymentMethod, or Charge card evidence.Warning SOURCE_LATEST_INVOICE_PAYMENT_METHOD_USED or SOURCE_LATEST_INVOICE_SOURCE_USED.Destination subscription is bound using the matched card fingerprint.
Already migrated rerunExecute once successfully, then create a new project with the same mapping and keys.Warning SUBSCRIPTION_ALREADY_MIGRATED_SKIPPED; no duplicate create action for the migrated subscription.Execute is disabled if every subscription is already safely recovered.

Blocker scenarios

ScenarioStripe setupExpected blocker
Missing mapping rowLeave one active/trialing source customer out of the mapping CSV.MISSING_CUSTOMER_MAPPING
Destination customer has no cardCopy/map a destination customer with no attached card instruments for a subscription that can collect a future non-zero invoice.DESTINATION_CUSTOMER_NO_PAYMENT_METHOD
Ambiguous destination cardAttach two buyer cards with the same brand, last4, expiry as the selected source card.SUBSCRIPTION_PAYMENT_METHOD_MAPPING_AMBIGUOUS
Existing buyer subscriptionAdd a non-terminal subscription to the mapped destination customer before dry-run. Terminal canceled and incomplete_expired buyer-side subscriptions are ignored.DESTINATION_CUSTOMER_HAS_EXISTING_SUBSCRIPTION unless it is a safe RevBridge recovery match.
Metered priceAny source subscription item uses a metered recurring price.METERED_PRICE
Mixed item intervalsSource subscription has two items billing on different intervals (for example monthly plus annual).MIXED_ITEM_INTERVALS
Divergent item period endsSource subscription items report different current_period_end timestamps.ITEM_PERIOD_END_MISMATCH
Subscription scheduleSource subscription is controlled by a subscription schedule or billing schedule.SUBSCRIPTION_SCHEDULE
Paused subscriptionSource subscription is paused.PAUSED_SUBSCRIPTION
Unsupported statusSource subscription is incomplete, past_due, unpaid, paused, or malformed trialing. Terminal canceled and incomplete_expired subscriptions are ignored.UNSUPPORTED_SUBSCRIPTION_STATUS, PAUSED_SUBSCRIPTION, or MISSING_TRIAL_END
Unsupported trial settingsSource trial has an unknown trial_settings.end_behavior.missing_payment_method value or another non-empty unsupported trial setting.TRIAL_SETTINGS_UNSUPPORTED
Trial OfferSource subscription item has a Stripe Trial Offer / current_trial.trial_offer.TRIAL_OFFER_UNSUPPORTED
Presentment detailsSource subscription has non-empty presentment_details / adaptive presentment currency state.PRESENTMENT_DETAILS_UNSUPPORTED
Manual collectionSource subscription uses collection_method=send_invoice.MANUAL_COLLECTION_UNSUPPORTED
Custom cancel timestamp before renewalSource subscription has cancel_at earlier than its next renewal.CUSTOM_CANCEL_AT_UNSUPPORTED (a cancel_at at or beyond the next renewal is supported and mirrored instead)
Billing thresholdsSubscription or item has billing thresholds.BILLING_THRESHOLDS_UNSUPPORTED
Pending updateSource has a pending update or pending invoice item interval. A pending_setup_intent alone (for example on a no-card trial or zero-amount subscription) must NOT block.PENDING_SUBSCRIPTION_CHANGE_UNSUPPORTED
Pending invoice itemCreate a pending invoice item for the source customer or source subscription, without attaching it to an invoice.PENDING_INVOICE_ITEM_UNSUPPORTED
Destination pending invoice itemCreate a pending invoice item for the mapped destination customer, without attaching it to an invoice.DESTINATION_PENDING_INVOICE_ITEM_UNSUPPORTED
Billing anchor configSource subscription uses billing_cycle_anchor_config, such as end-of-month billing rules.BILLING_CYCLE_ANCHOR_CONFIG_UNSUPPORTED
Outstanding latest invoiceSource subscription latest invoice has amount_remaining greater than zero.OUTSTANDING_INVOICE_UNSUPPORTED
Source customer outstanding invoiceCreate or leave a non-zero draft, open, or uncollectible invoice on the source customer.CUSTOMER_OUTSTANDING_INVOICE_UNSUPPORTED
Destination customer outstanding invoiceCreate or leave a non-zero draft, open, or uncollectible invoice on the mapped destination customer.DESTINATION_CUSTOMER_OUTSTANDING_INVOICE_UNSUPPORTED
Unknown billing modeSource billing mode is neither classic nor flexible, or flexible configuration carries unknown fields. Plain flexible subscriptions must NOT block; the destination must mirror the mode and proration_discounts.FLEXIBLE_BILLING_MODE_UNSUPPORTED
Tax settingsStripe Tax, customer tax settings/IDs, default tax rates, or item tax rates are enabled. Explicit price tax_behavior alone is supported and must not block.TAX_UNSUPPORTED, CUSTOMER_TAX_UNSUPPORTED, or DESTINATION_CUSTOMER_TAX_UNSUPPORTED
Customer invoice settingsSource or destination customer has invoice custom fields, footer, or rendering options.CUSTOMER_INVOICE_SETTINGS_UNSUPPORTED or DESTINATION_CUSTOMER_INVOICE_SETTINGS_UNSUPPORTED
Promotion code discountSource subscription discount is promotion-code backed.PROMOTION_CODE_UNSUPPORTED
Item-level discountDiscount is attached to the subscription item.ITEM_DISCOUNT_UNSUPPORTED
Customer-level discountSource or destination customer has a customer-level discount.CUSTOMER_DISCOUNT_UNSUPPORTED or DESTINATION_CUSTOMER_DISCOUNT_UNSUPPORTED
Customer balance or creditSource or destination customer has non-zero customer balance, invoice credit balance, or cash balance.CUSTOMER_BALANCE_UNSUPPORTED or DESTINATION_CUSTOMER_BALANCE_UNSUPPORTED
Multiple subscription discountsSource subscription has more than one discount.MULTIPLE_DISCOUNTS_UNSUPPORTED
Product-scoped couponCoupon applies only to selected products.PRODUCT_SCOPED_COUPON
Unmatchable repeating coupon windowRepeating coupon on a weekly or daily subscription where no whole-month clone duration discounts the same renewals.REPEATING_COUPON_UNSUPPORTED (repeating coupons with matchable windows are carried instead)
Unsupported price shapeTiered billing, transform quantity, custom unit amount, multi-currency currency_options, an undocumented interval value, or missing recurring data.UNSUPPORTED_PRICE_STRUCTURE, UNSUPPORTED_INTERVAL, or NO_RECURRING_PRICE

Failure and rerun scenarios

ScenarioHow to create itExpected behavior
Bad CSV headersUpload headers outside the supported pairs.API returns a readable 400 validation error, not a 500.
Duplicate CSV mappingRepeat a source or destination customer ID.API returns a readable 400 validation error before Redis is updated.
Wrong key mode/accountUse mixed test/live keys or the same Stripe account for both sides.Key setup returns a readable validation error.
Missing read scopeRemove a required source or destination read permission.Key setup names the failed Stripe read operation.
Destination price retrieve permission failureUse a destination key that cannot retrieve prices.Dry-run fails with the real Stripe error; RevBridge must not treat it as a missing price clone.
Destination coupon retrieve permission failureUse a destination key that cannot retrieve coupons.Dry-run fails with the real Stripe error; RevBridge must not treat it as a missing coupon clone.
Source drift after dry-runChange source price, quantity, coupon, discount shape, cancellation flag, scheduled cancel_at, trial behavior, or renewal timestamp after dry-run — including adding, removing, or changing a single item on a multi-item subscription.Worker stops before buyer-side subscription creation and tells the operator to rerun dry-run.
Rerun more than 24 hours after a failureFail a run mid-batch, wait past Stripe's idempotency window, re-save keys, rerun dry-run, and execute.Previously cloned products, prices, and coupons are found by revbridge_source_* lineage metadata and reused; no duplicate buyer-side catalog objects are created.
Retry after destination createSimulate worker retry after destination subscription creation.Same idempotency key is reused and no duplicate destination subscription is created.
Unexpected destination initial invoiceSimulate or force a post-create destination subscription_create invoice with a non-zero amount that is not void, including a paid invoice.Worker writes a failed CREATE_SUBSCRIPTION audit row with the destination subscription ID and does not cancel the source subscription. A paid initial invoice means Stripe charged earlier than RevBridge expected and needs manual reconciliation.
Source cancellation failureRemove source subscription update permission after destination creation.Destination remains created; source is not falsely reported as canceled; audit contains failed CANCEL_SOURCE.
Preflight destination write failureRemove destination product write permission.Worker fails before subscription execution, marks planned subscriptions failed, and writes failed verification audit.
Audit exportRun any success and any failure scenario.CSV and PDF include non-PII source/destination subscription, customer, price, coupon, idempotency, action, status, and message details.

Post-run verification

For every successful execution:

  • Source subscription is scheduled to cancel at period end, not immediately canceled.
  • Destination subscription status is active or trialing.
  • Destination item period end equals the source renewal timestamp from dry-run.
  • Destination subscription has the expected explicit default_payment_method or default_source when a card was resolved.
  • Destination discount state matches the supported source discount state. For repeating coupons, the destination discount's end date must discount exactly the same set of future renewals as the source window.
  • Destination items match the source items one-to-one: same quantities and matching prices via ID or revbridge_source_price_id lineage.
  • Destination subscription description matches the source subscription description when the source had one.
  • No unexpected destination subscriptions were created.
  • Audit CSV and PDF tell the same story as the Stripe dashboards.

For every blocker or failure:

  • The UI shows a readable error or blocker message.
  • The project status matches the outcome.
  • No source subscription is canceled unless a safe destination subscription was created or reused first.
  • The audit export explains what happened without storing names, emails, card numbers, or raw CSV rows.