OverviewAnchorIcon

Recurring Payments are automated, scheduled transactions that charge a customer’s saved payment method at regular intervals—such as daily, weekly, monthly, or annually—without requiring manual authorization for each transaction.

Key Characteristics:AnchorIcon

Payment Method Storage: Requires the payment method to be securely vaulted (saved) first, either through:

  • "Checkout with Vault" flow (immediate payment + save method)
  • "Vaulted Payments" flow (save method without immediate charge)

Automated Processing: Once set up, payments are processed automatically according to the defined schedule Subscription Management: Typically involves creating and managing subscription objects that define:

  • Billing frequency and amount
  • Start and end dates
  • Trial periods (if applicable)
  • Payment method references

Use Cases:

  • Monthly software subscriptions
  • Gym memberships
  • Utility bills
  • Magazine subscriptions
  • Any service requiring regular, predictable payments

Create PayPal billing agreementAnchorIcon

In your server-side code, use the createPayPalBillingAgreement mutation, as shown in the following sample, to initiate a PayPal billing agreement. Pass the following input fields and their values:

  • returnUrl: The URL to which the payer is redirected after payer authentication, to approve the billing agreement.
  • cancelUrl: The URL to which the payer is redirected if they cancel the billing agreement.

On successful processing of createPayPalBillingAgreement, Braintree generates and sends an approval URL to your server. In your client-side code, use the approval URL to redirect the payer to PayPal to authenticate and authorize the billing agreement.

API Reference: createPayPalBillingAgreement

  1. Mutation
mutation CreatePayPalBillingAgreement(
  $input: CreatePayPalBillingAgreementInput!
) {
  createPayPalBillingAgreement(input: $input) {
    billingAgreementToken
    approvalUrl
  }
}
  1. Variables
{
  "input": {
    "merchantAccountId": "merchant_account_id",
    "returnUrl": "https://merchant_domain_name/paypal/returnURL",
    "cancelUrl": "https://merchant_domain_name/paypal/cancelURL"
  }
}

Create PayPal billing agreement for recurring paymentsAnchorIcon

To establish the terms of a recurring payment schedule, include the recurringBillingPlan parameter in the createPayPalBillingAgreement mutation. This allows you to define the billing cycle, frequency, and pricing. Pass the following input fields and their values:

  • recurringBillingPlan (optional): Enables recurring payments when included.
  • paypalExperienceProfile (optional): Allows customization of the payer's experience.

Variables (Recurring billing agreement with subscription plan)AnchorIcon

  1. Variables
{
  "input": {
    "merchantAccountId": "merchant_account_id",
    "returnUrl": "https://merchant_domain_name/paypal/returnURL",
    "cancelUrl": "https://merchant_domain_name/paypal/cancelURL",
    "recurringBillingPlan": {
      "planType": "SUBSCRIPTION",
      "planMetadata": {
        "currencyCode": "USD",
        "totalAmount": "1.00",
        "billingCycles": [
          {
            "trial": false,
            "billingCycleSequence": 1,
            "numberOfExecutions": 1,
            "frequencyInterval": {
              "billingFrequencyUnit": "MONTH",
              "billingFrequency": 1
            },
            "pricingScheme": {
              "pricingModel": "model",
              "price": "1.00"
            }
          }
        ]
      }
    }
  }
}

Variables (Experience profile)AnchorIcon

  1. Variables
{
  "input": {
    "merchantAccountId": "merchant_account_id",
    "returnUrl": "https://merchant_domain_name/paypal/returnURL",
    "cancelUrl": "https://merchant_domain_name/paypal/cancelURL",
    "paypalExperienceProfile": {
      "collectShippingAddress": true,
      "shippingAddressEditable": false,
      "brandName": "Empire Co.",
      "landingPageType": "DEFAULT",
      "locale": "en-US"
    }
  }
}
  1. Response
{
  "data": {
    "createPayPalBillingAgreement": {
      "billingAgreementToken": "BA-9BJ56481CY242831B",
      "approvalUrl": "https://www.paypal.com/agreements/approve?ba_token=BA-9BJ56481CY242831B"
    }
  }
}

Create transaction risk contextAnchorIcon

You can use the createTransactionRiskContext mutation to pass supplementary risk-related data to PayPal and create a transaction risk context that helps in risk management. On successful processing of createTransactionRiskContext, PayPal returns a clientMetadataId and a paypalRiskCorrelationId.

Pass the clientMetadataId in the chargePaymentMethod mutation riskData.deviceData.correlation_id.

  1. Mutation
mutation CreateTransactionRiskContext(
  $input: CreateTransactionRiskContextInput!
) {
  createTransactionRiskContext(input: $input) {
    clientMetadataId
    paypalRiskCorrelationId
  }
}
  1. Variables
{
  "input": {
    "riskContext": {
      "fields": [
        {
          "name": "sender_account_id",
          "value": "xyz123"
        },
        {
          "name": "txn_count_total",
          "value": "15987"
        }
      ]
    }
  }
}
  1. Response
{
  "data": {
    "createTransactionRiskContext": {
      "clientMetadataId": "01e59aa07d2187e13b1bf9cf42a45596",
      "paypalRiskCorrelationId": "01e59aa07d2187e13b1bf9cf42a45596"
    }
  }
}

Send payers to PayPal to approve billing agreementAnchorIcon

From your server-side code, send the approval URL returned in the createPayPalBillingAgreement response to your client-side code. In your client-side code, include the logic to redirect payers to the PayPal site where they can authorize the billing agreement. After the payer authorizes the billing agreement on the PayPal site:

  1. Payers are redirected to your returnUrl.
  2. payment ID, payer ID, and payment token values are sent to the onApprove callback function in your server-side code.

New Fields AddedAnchorIcon

We continue to use PayPalRecurringBillingPlanInput with the following new fields to support enhanced recurring billing functionality:

ItemTotal:Amount (Optional)

  • The total amount for all the line items, including charges from billing plan, before any discounts or taxes.

Shipping: Amount (Optional)

  • The total shipping charge for the transaction

Handling: Amount (Optional)

  • Additional handling or processing fees

TaxTotal: Amount (Optional)

  • The total tax amount applied to the transaction

Discount: Amount (Optional)

  • The total discount applied to the item subtotal

ShippingDiscount: Amount (Optional)

  • Discount specifically applied to shipping charges

Sample MutationAnchorIcon

Below is a complete example of implementing recurring billing with the new fields:

  1. Variables
mutation CreatePayPalOneTimePayment($input: CreatePayPalOneTimePaymentInput!) {
        createPayPalOneTimePayment(input: $input) {
          clientMutationId
          approvalUrl
          paymentId
        }
    }

{
  "input": {
    "amount": {
      "value": "20.00",
      "currencyCode": "USD"
    },
    "intent": "AUTHORIZE",
    "returnUrl": "https://your-site.com/return",
    "cancelUrl": "https://your-site.com/cancel",
    "paypalRiskCorrelationId": "risk_correlation_id",
    "shippingCallbackUrl": "https://your-site.com/shippingCallback",
    "recipientEmail": "recipient@example.com",
    "merchantAccountId": "your_merchant_account_id",
    "customerSessionId": "customerSessionId123",
    "offerPayLater": true,
    "requestBillingAgreement": false,
    "billingAgreementDescription": "Billing agreement details",
    "payerEmail": "customer@example.com",
    "shippingAddress": {
      "addressLine1": "123 Test St",
      "addressLine2": "Apt 4",
      "adminArea1": "CA",
      "adminArea2": "San Francisco",
      "countryCode": "US",
      "postalCode": "94107",
      "phone": {
        "countryPhoneCode": "1",
        "phoneNumber": "1234567890"
      }
    },
    "lineItems": [
      {
        "name": "Item 1",
        "description": "This is test item 1.",
        "quantity": 1,
        "unitAmount": "1.00",
        "type": "DEBIT",
        "productCode": "IM1",
        "unitTaxAmount": "0.01",
        "url": "https://example.com",
        "imageUrl": "https://example.com/image.jpeg",
        "upc": {
          "upcCode": "042100005264"
        }
      }
    ],
    "amountBreakDown": {
      "itemTotal": "10.00",
      "shipping": "2.00",
      "taxTotal": "3.00"
    },
    "recurringBillingPlan": {
      "planType": "SUBSCRIPTION",
      "planMetadata": {
        "currencyCode": "USD",
        "name": "Verizon Billing Plan",
        "totalAmount": "10",
        "oneTimeCharges": {
          "oneTimeFeeAmount": "10"
        },
        "product": {
          "quantity": 1,
          "description": "iPhone13"
        },
        "billingCycles": [
          {
            "trial": false,
            "billingCycleSequence": 1,
            "numberOfExecutions": 1,
            "startDate": "2025-06-06",
            "frequencyInterval": {
              "billingFrequencyUnit": "MONTH",
              "billingFrequency": 1
            },
            "pricingScheme": {
              "pricingModel": "FIXED",
              "price": "10"
            }
          }
        ]
      }
    },
    "appSwitchContext": {
      "nativeApp": {
        "osType": "ANDROID",
        "osVersion": "18.1",
        "appUrl": "https://example.com/app"
      },
      "mobileWeb": {
        "buyerUserAgent": "User Agent",
        "returnFlow": "AUTO"
      }
    },
    "paypalExperienceProfile": {
      "locale": "en_US",
      "landingPageType": "LOGIN",
      "userAction": "COMMIT",
      "contactPreference": "EMAIL"
    },
    "shippingOptions": [
      {
        "id": "option1",
        "label": "Standard Shipping",
        "amount": "5.00",
        "selected": true
      }
    ]
  }
}

TestingAnchorIcon

Use the sandbox environment to test your recurring billing implementation:

Pro Tip: Test various scenarios including failed payments, subscription modifications, and cancellations to ensure robust error handling.