Create billing agreements

You can use a billing agreement to create subscriptions for customers. Before you can create a billing agreement, you must create and activate a plan. You then create an agreement that you base off the plan.

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 billing agreement for a PayPal payment or a credit card payment. If PayPal is the payment method, the customer is redirected to PayPal to confirm the billing agreement. If credit card is the payment method, no redirect is needed.
3. To start the subscription, execute billing agreement.

Create billing agreement attribute object

The billing object defines a payment method (PayPal / credit card), create a reference back to subscription information in a billing plan, and define any alternate information needed, 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)

If a credit card is being used as the payment method, skip to the next section, create billing agreement (credit card).

With the billing agreement attribute object set, the next step is to 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.

Create billing agreement (credit card)

If a PayPal payment is being used as the payment method, go to the previous section, create billing agreement (PayPal).

If a credit card is being used instead of PayPal as the payment method, then instead of redirecting the user to PayPal to initiate the agreement, make a direct call to process the agreement. Set the billing agreement attribute object with the credit card information under payer, then make a request to create the agreement.

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: 'credit_card',
    funding_instruments: [{
      payment_card: {
        type: 'visa',
        number: '4417119669820331',
        expire_month: '11',
        expire_year: '2018',
        cvv2: '874',
        first_name: 'Joe',
        last_name: 'Shopper',
        billing_country: 'US',
        billing_address: {
          line1: '52 N Main ST',
          city: 'Johnstown',
          state: 'OH',
          postal_code: '43210',
          country_code: 'US' }}}]
  },
  shipping_address: {
    line1: 'W 34th St',
    city: 'New York',
    state: 'NY',
    postal_code: '10001',
    country_code: 'US'
  }
};

paypal.billingAgreement.create(billingAgreementAttributes);
//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);

// Create credit card object and set funding instrument
$card = new CreditCard();
$card->setType("visa")
  ->setNumber("4669424246660779")
  ->setExpireMonth("11")
  ->setExpireYear("2019")
  ->setCvv2("012")
  ->setFirstName("Joe")
  ->setLastName("Shopper");

$fi = new FundingInstrument();
$fi->setCreditCard($card);

// Set payer to process credit card
$payer = new Payer();
$payer->setPaymentMethod("credit_card")
  ->setFundingInstruments(array($fi));
$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);

$agreement = $agreement->create($apiContext);
billing_agreement = BillingAgreement({
  "name": "Fast Speed Agreement",
  "description": "Agreement for Fast Speed Plan",
  "start_date": "2015-02-19T00:37:04Z",
  "plan": {
    "id": "P-0NJ10521L3680291SOAQIVTQ"
  },
  "payer": {
    "payment_method": "credit_card",
    "funding_instruments": [{
      "credit_card": {
        "type": "visa",
        "number": "4417119669820331",
        "expire_month": "11",
        "expire_year": "2018",
        "cvv2": "874",
        "first_name": "Joe",
        "last_name": "Shopper",
        "billing_address": {
          "line1": "52 N Main ST",
          "city": "Johnstown",
          "state": "OH",
          "postal_code": "43210",
          "country_code": "US"
        }
      }
    }]
  },
  "shipping_address": {
    "line1": "StayBr111idge Suites",
    "line2": "Cro12ok Street",
    "city": "San Jose",
    "state": "CA",
    "postal_code": "95112",
    "country_code": "US"
  }
})

billing_agreement.create()
# Billing plan ID
plan_id = 'P-0PF042751U677521EQRKKUPI';
  
# 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 => 'credit_card',
    :funding_instruments => [{
      :credit_card => {
        :type => 'visa',
        :number => '4417119669820331',
        :expire_month => '11',
        :expire_year => '2018',
        :cvv2 => '874',
        :first_name => 'Joe',
        :last_name => 'Shopper',
        :billing_address => {
          :line1 => '52 N Main ST',
          :city => 'Johnstown',
          :state => 'OH',
          :postal_code => '43210',
          :country_code => 'US' 
        }
      }
    }]
  },
  :shipping_address => {
    :line1 => 'W 34th St',
    :city => 'New York',
    :state => 'NY',
    :postal_code => '10001',
    :country_code => 'US'
  }
})

if agreement.create
  # TOKEN AVAILABLE IN token agreement.token
else
  logger.error agreement.error.inspect
end
// 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-0NJ10521L3680291SOAQIVTQ");
agreement.setPlan(plan);

// Set address info
Address billingAddress = new Address();
billingAddress.setCity("Johnstown");
billingAddress.setCountryCode("US");
billingAddress.setLine1("52 N Main ST");
billingAddress.setPostalCode("43210");
billingAddress.setState("OH");

// Credit card info
CreditCard creditCard = new CreditCard();
creditCard.setBillingAddress(billingAddress);
creditCard.setExpireMonth(11);
creditCard.setExpireYear(2018);
creditCard.setFirstName("Joe");
creditCard.setLastName("Shopper");
creditCard.setNumber("4669424246660779");
creditCard.setType("visa");

// Set funding instrument
FundingInstrument fundingInstrument = new FundingInstrument();
fundingInstrument.setCreditCard(creditCard);

ListFundingInstrument fundingInstrumentList = new ArrayListFundingInstrument();
fundingInstrumentList.add(fundingInstrument);

// Add payer details
Payer payer = new Payer();
payer.setFundingInstruments(fundingInstrumentList);
payer.setPaymentMethod("credit_card");
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);

// Create agreement
try {
  agreement = agreement.create(apiContext);
  // AGREEMENT TOKEN AVAILABLE IN agreement.getToken()
} catch (PayPalRESTException e) {
  System.err.println(e.getDetails());
} catch (MalformedURLException e) {
  e.printStackTrace();
} catch (UnsupportedEncodingException e) {
  e.printStackTrace();
}
var payer = new Payer
{
  payment_method = "credit_card",
  funding_instruments = new List
  {
    new FundingInstrument
    {
      credit_card = new CreditCard
      {
        billing_address = new Address
        {
          city = "Johnstown",
          country_code = "US",
          line1 = "52 N Main ST",
          postal_code = "43210",
          state = "OH"
        },
        cvv2 = "874",
        expire_month = 11,
        expire_year = 2018,
        first_name = "Joe",
        last_name = "Shopper",
        number = "4877274905927862",
        type = "visa"
      }
    }
  }
};

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
};

var createdAgreement = agreement.Create(apiContext);

Execute billing agreement

Once the billing agreement is created, token will be provided in the response object (for credit card payment types) or in the query string parameters (following 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