Braintree → PayPal decline analysis
Source: braintree.csv — 429 transaction attempts, 429 unique transaction IDs.
Headline
| Metric | Value |
|---|---|
| Attempts | 429 |
| Settled | 344 (80.2%) |
| Processor declined | 85 (19.8%) |
| Gateway rejected | 0 |
Every failure came back from PayPal. Braintree's own risk layer — AVS, CVV, duplicate, fraud rules — rejected nothing, and gateway_rejection_reason is blank on all 429 rows. Every successful row is 1000 / Approved, so there is no partial-success or soft-decline middle ground in this data.
The failures are all PayPal funding-path codes
| Code | Meaning | Count | % of failures |
|---|---|---|---|
| 2070 | PayPal Buyer Revoked Pre-Approved Payment Authorization | 38 | 44.7% |
| 2046 | Declined (generic) | 26 | 30.6% |
| 2074 | Funding instrument in the PayPal account was declined by the processor or bank | 11 | 12.9% |
| 2076 | Payer cannot pay for this transaction with PayPal | 10 | 11.8% |
Not one card-network code (2000 insufficient funds, 2001 limit exceeded, 2004 expired card). That matters: this is not "customers ran out of money." Every decline is about the authorization relationship between the buyer's PayPal account and the merchant, or about PayPal's ability to fund the charge at all.
2070 is the migration signature. A revoked pre-approved payment authorization means the billing agreement backing the vaulted PayPal token is no longer valid for this merchant. The Braintree vault token still resolves and still gets submitted — which is why these surface as processor declines rather than gateway rejections — but the consent behind it is gone. A billing agreement is scoped to the merchant identity the buyer originally approved; anything that changes that identity, or that re-vaults a token without re-obtaining consent, invalidates it wholesale. Buyers also revoke manually when a charge shows up under a payee name they don't recognize.
2046 is unresolved. Braintree's generic decline maps to several PayPal-side conditions and the text carries no detail. See the retry section — its distribution is not random.
2074 and 2076 are buyer-side and genuinely recoverable: 2074 is the card or bank inside the PayPal wallet failing, 2076 is an account limitation, currency, or country eligibility problem. Together they are 21 of 85 failures (24.7%).
Subscription status is nearly deterministic
| Status | Settled | Declined | Decline rate |
|---|---|---|---|
| Active | 330 | 1 | 0.3% |
| Past Due | 0 | 63 | 100% |
| Canceled | 14 | 21 | 60.0% |
Past Due has zero successful attempts in the entire file — the status is a restatement of the failure, not an independent variable. The 34 of 63 Past Due rows carrying code 2070 are the population that will never self-heal, because retrying a revoked authorization cannot recover it.
The 14 settled Canceled rows are charges that succeeded before or at cancellation, which is ordinary. The single declined Active row is noise.
Retries do not work
| Attempt | Attempts | Settled | Declined | Decline codes |
|---|---|---|---|---|
| 1 | 414 | 343 | 71 | 2070×38, 2046×12, 2074×11, 2076×10 |
| 2 | 9 | 1 | 8 | 2046×8 |
| 3 | 4 | 0 | 4 | 2046×4 |
| 4 | 2 | 0 | 2 | 2046×2 |
Fifteen retry attempts produced one success — a 6.7% recovery rate against an 82.9% first-attempt success rate.
The sharper finding is the code collapse. On attempt 1, 2046 is 17% of failures. On attempts 2 through 4, it is 100% of failures, 14 for 14. Retrying a dead PayPal authorization returns a generic decline rather than the specific reason, so the retry ladder actively destroys the diagnostic signal that would tell you which subscriptions are recoverable. Some share of the 26 total 2046s are almost certainly 2070s wearing a different hat.
There is also a dunning gap: 71 first-attempt failures but only 9 second attempts. Either retries are configured for a narrow subset of decline codes, or most failures are being abandoned after one try.
What this data cannot tell you
You've said the rejection rate is climbing on migrated subscriptions specifically. This file cannot confirm that, and I want to be direct about it rather than dress up a correlation. It has no migration flag, no timestamps, no subscription or customer identifier, and no merchant account ID. So:
- Migrated and unmigrated cohorts can't be separated, so the 19.8% can't be attributed.
- Attempts can't be chained to a subscription, so it's impossible to prove that the 2046 retries follow 2070 first attempts — which is the single most valuable thing to establish here.
- There's no time axis, so "increased with volume" can't be tested, and it can't be distinguished from a step change at a specific migration batch.
To close this out, re-export with: subscription_id, created_at, migrated (bool) or migration_batch, merchant_account_id, payment_method_token, payment_instrument_type, and PayPal's raw correlation ID or processor_response_code detail where Braintree exposes it.
What I'd do next
- Split 2070 by cohort. Group decline rate by
migratedand by migration batch date. If 2070 concentrates in migrated subscriptions, the billing agreements are not surviving the move and the failure is systemic, not customer behavior. - Check the payee name buyers see. A merchant descriptor or PayPal account name that changed during migration drives manual revocations directly, and it's cheap to verify.
- Stop retrying 2070. It is unrecoverable by definition and each retry rewrites the code to 2046, corrupting your own telemetry. Route it to re-consent — a fresh PayPal checkout flow that mints a new billing agreement — instead of the dunning ladder.
- Keep retrying 2074 only. It's the one code here where the underlying condition can change on its own.
- Preserve the first-attempt code on the subscription record so the retry ladder can't overwrite it.
If the 2070 concentration in migrated subscriptions holds up, the working theory is that migration is carrying vault tokens across without carrying the buyer authorizations that make them chargeable — and every migrated subscription is then a scheduled failure waiting for its next billing date, whether or not it has failed yet.