Overview
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:
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 agreement
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.
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
- Mutation
mutation CreatePayPalBillingAgreement(
$input: CreatePayPalBillingAgreementInput!
) {
createPayPalBillingAgreement(input: $input) {
billingAgreementToken
approvalUrl
}
}
- 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 payments
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)
- 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)
- 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"
}
}
}
- Response
{
"data": {
"createPayPalBillingAgreement": {
"billingAgreementToken": "BA-9BJ56481CY242831B",
"approvalUrl": "https://www.paypal.com/agreements/approve?ba_token=BA-9BJ56481CY242831B"
}
}
}
Create transaction risk context
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
.
- Mutation
mutation CreateTransactionRiskContext(
$input: CreateTransactionRiskContextInput!
) {
createTransactionRiskContext(input: $input) {
clientMetadataId
paypalRiskCorrelationId
}
}
- Variables
{
"input": {
"riskContext": {
"fields": [
{
"name": "sender_account_id",
"value": "xyz123"
},
{
"name": "txn_count_total",
"value": "15987"
}
]
}
}
}
- Response
{
"data": {
"createTransactionRiskContext": {
"clientMetadataId": "01e59aa07d2187e13b1bf9cf42a45596",
"paypalRiskCorrelationId": "01e59aa07d2187e13b1bf9cf42a45596"
}
}
}
Send payers to PayPal to approve billing agreement
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:
- Payers are redirected to your
returnUrl
. - payment ID, payer ID, and payment token values are sent to the
onApprove
callback function in your server-side code.
New Fields Added
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 Mutation
Below is a complete example of implementing recurring billing with the new fields:
- 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
}
]
}
}
Testing
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.