PayPal

Vaulted payments

You can set up vaulted payments to:

  1. Save the payer’s PayPal payment method credentials for future transactions without processing an immediate payment.
  2. Set up recurring payments.

This guide explains how to use the Braintree GraphQL APIs to integrate PayPal vaulted payments into your application. Use this integration to:

  • Provide faster payment processing for returning customers.
  • Set up payment processing for subscriptions.
  • Set up recurring billing (for example, automatic top-up or usage-based charges).

WorkflowAnchorIcon

The following diagram illustrates the process to create PayPal vaulted payments flow.

pwpp-GraphQL-APIonly-Vaulted

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.

Tokenize PayPal billing agreementAnchorIcon

In your server-side code's onApprove callback function, use the tokenizePayPalBillingAgreement mutation to convert the billing agreement into a tokenized payment method. Use the payment ID, payer ID, and payment token values received in the input payload of tokenizePayPalBillingAgreement.

On successful processing of tokenizePayPalBillingAgreement, Braintree/PayPal returns a paymentMethod.id that represents the tokenized payment method.

API Reference: tokenizePayPalBillingAgreement

  1. Mutation
mutation TokenizePayPalBillingAgreement(
  $input: TokenizePayPalBillingAgreementInput!
) {
  tokenizePayPalBillingAgreement(input: $input) {
    paymentMethod {
      id
      details {
        payerId
        selectedFinancingOption {
          term
          monthlyPayment {
            currencyCode
            value
          }
        }
      }
    }
  }
}
  1. Variables
{ "input": { "merchantAccountId": "merchant_account_id", "billingAgreement": { "billingAgreementToken": "BA-9BJ56481CY242831B" } } }
  1. Response
{ "data": { "tokenizePayPalBillingAgreement": { "paymentMethod": { "id": "tokencc_bj_hfqww2_rtyn7b_ggmjvs_6c9gd6_k9z", "details": { "payerId": "payer-id", "selectedFinancingOption": { "term": 12, "monthlyPayment": { "currencyCode": "GBP", "value": "10.0" } } } } } } }

Vault payment methodAnchorIcon

After tokenization, the payment method can be stored in the vault. Vaulting the payment method creates a persistent record of the payer's PayPal account, allowing you to initiate transactions without the payer's direct involvement.

Note
To use the vaultPaymentMethod mutation, pass the paymentMethodId in the input object. The paymentMethodId is obtained from the tokenizePayPalBillingAgreement or tokenizePayPalOneTimePayment mutation.

API Reference: vaultPaymentMethod.

  1. Mutation
mutation VaultPaymentMethod($input: VaultPaymentMethodInput!) {
  vaultPaymentMethod(input: $input) {
    paymentMethod {
      id
      customer {
        id
      }
    }
    verification {
      id
      status
    }
  }
}
  1. Variables
{ "input": { "paymentMethodId": "tokencc_bj_hfqww2_rtyn7b_ggmjvs_6c9gd6_k9z" } }
  1. Response
{ "data": { "vaultPaymentMethod": { "paymentMethod": { "id": "cGF5bWVudG1ldGhvZF9jY182dnB3a20y", "customer": { "id": "Y3VzdG9tZXJfNjc3MDI1NzI1" } }, "verification": { "id": "dmVyaWZpY2F0aW9uXzliMHBhc2E3", "status": "VERIFIED" } } } }

Charge payment methodAnchorIcon

This final step uses the vaulted payment method to initiate a payment. In your server-side code, use the chargePaymentMethod mutation, referencing the vaulted payment method's ID and providing the transaction details.

Note
Pass the clientMetadataId returned from the createTransactionRiskContext mutation in the chargePaymentMethod mutation > riskData.deviceData.correlation_id.

API Reference: chargePaymentMethod

  1. Mutation
mutation ChargePaymentMethod($input: ChargePaymentMethodInput!) {
  chargePaymentMethod(input: $input) {
    transaction {
      id
      status
    }
  }
}
  1. Variables
{ "input": { "paymentMethodId": "cGF5bWVudG1ldGhvZF9jY182dnB3a20y", "transaction": { "amount": "10.00", "merchantAccountId": "canvaAU-AUD", "paymentInitiator": "RECURRING", "riskData": { "deviceData": "{\"correlation_id\": \"01e59aa07d2187e13b1bf9cf42a45596\"}" } } } }
  1. Response
{ "data": { "chargePaymentMethod": { "transaction": { "id": "dHJhbnNhY3Rpb25fZzVmNDY2djE", "status": "SETTLING" } } } }