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.
Note
Ensure that returnUrl and cancelUrl use an approved hostname (such as, *.braintreegateway.com) and are HTTPS URLs.

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.