Create billing agreements

You use billing plans and billing agreements to create an agreement for a recurring PayPal payment for goods or services. An agreement is also known as a subscription.

To create an agreement, you reference an active billing plan from which the agreement inherits information. You also supply customer and payment information and, optionally, can override the referenced plan's merchant preferences and shipping fee and tax information.

For more information, see Billing Plans and Agreements.

To create a billing agreement, complete these steps:

1. Create billing agreement attribute object to define the payment method, billing plan to be used, and any associated shipping information.
2. Create a billing agreement for a PayPal payment. The customer is redirected to PayPal to confirm the billing agreement.
3. To start the subscription, execute billing agreement.

Create billing agreement attribute object

The billing object defines a payment method, a reference to subscription information in a billing plan, and any alternate information, such as shipping details. To start a billing agreement, create the billing agreement attribute object.

var billingPlan = "1234567890";
var billingAgreementAttributes;
var isoDate = new Date();

isoDate.setSeconds(isoDate.getSeconds() + 4);
isoDate.toISOString().slice(0, 19) + 'Z';

billingAgreementAttributes = {
  name: 'Standard Membership',
  description: 'Food of the World Club Standard Membership',
  start_date: isoDate,
  plan: {
    id: billingPlan
  },
  payer: {
    payment_method: 'paypal'
  },
  shipping_address: {
    line1: 'W 34th St',
    city: 'New York',
    state: 'NY',
    postal_code: '10001',
    country_code: 'US'
  }
};
use PayPal\Api\Agreement;
use PayPal\Api\Payer;
use PayPal\Api\Plan;
use PayPal\Api\ShippingAddress;

// Create new agreement
$agreement = new Agreement();
$agreement->setName('Base Agreement')
  ->setDescription('Basic Agreement')
  ->setStartDate('2019-06-17T9:45:04Z');

// Set plan id
$plan = new Plan();
$plan->setId('P-1WJ68935LL406420PUTENA2I');
$agreement->setPlan($plan);

// Add payer type
$payer = new Payer();
$payer->setPaymentMethod('paypal');
$agreement->setPayer($payer);

// Adding shipping details
$shippingAddress = new ShippingAddress();
$shippingAddress->setLine1('111 First Street')
  ->setCity('Saratoga')
  ->setState('CA')
  ->setPostalCode('95070')
  ->setCountryCode('US');
$agreement->setShippingAddress($shippingAddress);
from paypalrestsdk import BillingAgreement
from paypalrestsdk import Payment

billing_agreement = BillingAgreement({
  "name": "Fast Speed Agreement",
  "description": "Agreement for Fast Speed Plan",
  "start_date": "2017-02-19T00:37:04Z",
  "plan": {
    "id": "P-0PK90852BK763535UTMSTGMQ"
  },
  "payer": {
    "payment_method": "paypal"
  },
  "shipping_address": {
    "line1": "StayBr111idge Suites",
    "line2": "Cro12ok Street",
    "city": "San Jose",
    "state": "CA",
    "postal_code": "95112",
    "country_code": "US"
  }
})
# Billing plan ID
plan_id = 'P-0PK90852BK763535UTMSTGMQ';

# Agreement definition
agreement = Agreement.new({
  :name => 'Standard Membership',
  :description => 'Food of the World Club Standard Membership',
  :start_date => '2019-06-17T9:45:04Z',
  :plan => {
    :id => plan_id
  },
  :payer => {
    :payment_method => 'paypal'
  },
  :shipping_address => {
    :line1 => 'W 34th St',
    :city => 'New York',
    :state => 'NY',
    :postal_code => '10001',
    :country_code => 'US'
  }
})
import com.paypal.base.rest.APIContext;
import com.paypal.base.rest.PayPalRESTException;

import java.io.UnsupportedEncodingException;
import java.net.MalformedURLException;
import java.net.URL;

import com.paypal.api.payments.Agreement;
import com.paypal.api.payments.Links;
import com.paypal.api.payments.Payer;
import com.paypal.api.payments.Plan;
import com.paypal.api.payments.ShippingAddress;

// Create new agreement
Agreement agreement = new Agreement();
agreement.setName("Base Agreement");
agreement.setDescription("Basic Agreement");
agreement.setStartDate("2019-06-17T9:45:04Z");

// Set plan ID
Plan plan = new Plan();
plan.setId("P-0PK90852BK763535UTMSTGMQ");
agreement.setPlan(plan);

// Add payer details
Payer payer = new Payer();
payer.setPaymentMethod("paypal");
agreement.setPayer(payer);

// Set shipping address information
ShippingAddress shipping = new ShippingAddress();
shipping.setLine1("111 First Street");
shipping.setCity("Saratoga");
shipping.setState("CA");
shipping.setPostalCode("95070");
shipping.setCountryCode("US");
agreement.setShippingAddress(shipping);
var payer = new Payer() { payment_method = "paypal" };

var shippingAddress = new ShippingAddress()
{
  line1 = "111 First Street",
  city = "Saratoga",
  state = "CA",
  postal_code = "95070",
  country_code = "US"
};

var agreement = new Agreement()
{
  name = "T-Shirt of the Month Club",
  description = "Agreement for T-Shirt of the Month Club",
  start_date = "2015-02-19T00:37:04Z",
  payer = payer,
  plan = new Plan() { id = createdPlan.id },
  shipping_address = shippingAddress
};

Create billing agreement (PayPal)

Create the agreement and redirect the user to PayPal to confirm the subscription information.

var links = {};

// Use activated billing plan to create agreement
paypal.billingAgreement.create(billingAgreementAttributes, function (error, billingAgreement){
  if (error){
    console.error(JSON.stringify(error));
    throw error;
  } else {
    // Capture HATEOAS links
    billingAgreement.links.forEach(function(linkObj){
      links[linkObj.rel] = {
        href: linkObj.href,
        method: linkObj.method
      };
    })

    // If redirect url present, redirect user
    if (links.hasOwnProperty('approval_url')){
      //REDIRECT USER TO links['approval_url'].href
    } else {
      console.error('no redirect URI present');
    }
  }
});
try {
  // Create agreement
  $agreement = $agreement->create($apiContext);

  // Extract approval URL to redirect user
  $approvalUrl = $agreement->getApprovalLink();
} catch (PayPal\Exception\PayPalConnectionException $ex) {
  echo $ex->getCode();
  echo $ex->getData();
  die($ex);
} catch (Exception $ex) {
  die($ex);
}
if billing_agreement.create():
  # Extract redirect url
  for link in billing_agreement.links:
    if link.method == "REDIRECT":
      # Capture redirect url
      redirect_url = str(link.href)

      # REDIRECT USER TO redirect_url
else:
  print(billing_agreement.error)
if agreement.create
  redirect = agreement.links.find{|v| v.rel == "approval_url" }.href
  
  # REDIRECT USER TO redirect
else
  logger.error agreement.error.inspect
end
// Create agreement
try {
  agreement = agreement.create(apiContext);

  for (Links links : agreement.getLinks()) {
    if ("approval_url".equals(links.getRel())) {
      URL url = new URL(links.getHref());
      
      //REDIRECT USER TO url
      
      break;
    }
  }
} catch (PayPalRESTException e) {
  System.err.println(e.getDetails());
} catch (MalformedURLException e) {
  e.printStackTrace();
} catch (UnsupportedEncodingException e) {
  e.printStackTrace();
}
var createdAgreement = agreement.Create(apiContext);

var links = createdAgreement.links.GetEnumerator();
while (links.MoveNext())
{
  var link = links.Current;
  if (link.rel.ToLower().Trim().Equals("approval_url"))
  {
    this.flow.RecordRedirectUrl("Redirect to PayPal to approve billing agreement...", link.href);
  }
}

A call is made to create the billing agreement, passing in the previously created billing agreement attributes object. If successful, the response object will contain the URL that the user will need to be redirected to on PayPal. The URL, approval_url is extracted, and the user should now be redirected to that location.

Execute billing agreement

After you create the billing agreement, the API provides a token in query string parameters following the redirect for PayPal payment types.

After you extract the token, call the billing agreement execute method to complete the billing agreement, signing up the user for the associated subscription purchase.

var token = req.query.token;

paypal.billingAgreement.execute(token, {}, function (error, billingAgreement){
  if (error){
    console.error(JSON.stringify(error));
    throw error;
  } else {
    console.log(JSON.stringify(billingAgreement));
    console.log('Billing Agreement Created Successfully');
  }
});
if (isset($_GET['success']) && $_GET['success'] == 'true') {
  $token = $_GET['token'];
  $agreement = new \PayPal\Api\Agreement();

  try {
    // Execute agreement
    $agreement->execute($token, $apiContext);
  } catch (PayPal\Exception\PayPalConnectionException $ex) {
    echo $ex->getCode();
    echo $ex->getData();
    die($ex);
  } catch (Exception $ex) {
    die($ex);
  }
} else {
    echo "user canceled agreement";
}
# Token obtained when creating the agreement (following redirect)
token = "EC-8GY76409P74839940"

billing_agreement_response = BillingAgreement.execute(token)
print("BillingAgreement[%s] executed successfully" % (billing_agreement_response.id))
# Token obtained when creating the agreement (following redirect)
agreement = Agreement.new()
agreement.token = token

# Execute agreement
if agreement.execute
  puts("billing agreement created with ID [#{agreement.id}]")
else
  logger.error agreement.error.inspect
end
//token obtained when creating the agreement (following redirect)
Agreement agreement =  new Agreement();
agreement.setToken(token);

try {
  Agreement activeAgreement = agreement.execute(apiContext, agreement.getToken());
  System.out.println("Agreement created with ID " + activeAgreement.getId());
} catch (PayPalRESTException e) {
  System.err.println(e.getDetails());
}
var agreement = new Agreement() { token = token };
var executedAgreement = agreement.Execute(apiContext);

Additional information