Integration guide

Recovering failed Braintree payments

Braintree gives you unusually detailed decline information — processor response codes, gateway rejection reasons and its own retry settings. Most teams never use it, because the follow-up lives in a separate marketing tool that only knows the payment failed. RRLabs keeps that detail attached to the outreach.

Quick answer

Braintree recovery is driven by subscription and dispute webhook notifications plus gateway rejection reasons, letting you separate soft declines worth retrying from hard declines that need a new payment method.

Events that matter

subscription_charged_unsuccessfully
A recurring charge was declined.
subscription_charged_successfully
The charge cleared — close the attempt.
subscription_went_past_due
Braintree exhausted its own retries.
dispute_opened
Stop outreach and route the case to support.

Setting it up

  1. 1

    Register the destination

    Add your RRLabs endpoint as a Braintree webhook destination and enable the subscription and dispute notifications.

  2. 2

    Parse with the SDK

    Braintree signs each notification; the payload is parsed with the SDK before anything is queued.

  3. 3

    Use the decline detail

    Processor response codes and gateway rejection reasons decide whether to retry quietly or ask for a new card.

  4. 4

    Suppress on disputes

    An open dispute halts recovery messaging for that customer immediately.

Parse a Braintree webhook notification

// Braintree → Settings → Webhooks (destination URL)
const notification = await gateway.webhookNotification.parse(bt_signature, bt_payload);

if (notification.kind === "subscription_charged_unsuccessfully") {
  const sub = notification.subscription;
  const tx = sub.transactions?.[0];
  await rrlabs.enqueueRecovery({
    provider: "braintree",
    externalId: sub.id,
    amountCents: Math.round(Number(sub.price) * 100),
    currency: "USD",
    declineCode: tx?.processorResponseCode ?? tx?.gatewayRejectionReason ?? null,
  });
}

if (notification.kind === "subscription_charged_successfully") {
  await rrlabs.closeRecovery({ provider: "braintree", externalId: notification.subscription.id });
}

Manual recovery vs. automated recovery

CapabilityBraintree aloneWith RRLabs
Decline handlingRetry settings applied uniformlyResponse-code-aware plan per failure
ChannelsWhatever your ESP sendsEmail, WhatsApp and SMS where consented
Dispute safetyManual suppressionAutomatic hold when a dispute opens
AttributionGateway totalsRecovered charges linked to the outreach that preceded them
Source of truthBraintreeBraintree — vaulted payment methods never leave it

Frequently asked questions

Does RRLabs touch vaulted payment methods?

No. Payment methods stay in the Braintree vault; RRLabs works from notification metadata and customer contact details.

Can I keep Braintree's own retry schedule?

Yes. Braintree keeps retrying the charge while RRLabs handles the customer-facing sequence around those attempts.

What about PayPal-funded subscriptions?

PayPal failures arrive through the same subscription notifications, so they enter the same recovery queue with their own reason code.

Other platforms

Estimate your recoverable revenue

Calculate now