# Integrate subscriptions (/platforms/subscriptions/integrate)

Discover how to integrate PayPal subscriptions for recurring billing. Set up and manage subscription payments with PayPal's subscription API.



Integrate subscriptions to bill customers at regular intervals.

## Know before you code [#know-before-you-code]

> **Info:** ### You need the following to use this integration: [#you-need-the-following-to-use-this-integration]
>
> * This integration is available to select partners only.
> * Complete [Onboarding](/platforms/seller-onboarding/).
> * Follow the instructions in [Get started](/platforms/get-started/) to get your access token.
> * You'll need your build notation (BN) code. If you don't have it, contact your PayPal account manager.
> * Indian Rupees (INR) are not supported in subscriptions.
>
> [Onboard sellers](/platforms/seller-onboarding/)
>
> [Read the guide](/platforms/get-started/)

> **Info:** ### You'll need both client side and server side tools [#youll-need-both-client-side-and-server-side-tools]
>
> This client-side and server-side integration uses the following:
>
> * [Catalog Products REST API](/api/catalog-products/v1/): Creates goods or services for customers to subscribe to.
> * [Subscriptions REST API](/api/subscriptions/v1/): Creates a recurring payment plan.
> * [PayPal JavaScript SDK](/sdk/js/configuration/): Creates a payment button.

> **Info:** ### Explore PayPal APIs with Postman [#explore-paypal-apis-with-postman]
>
> Use Postman to explore and test PayPal APIs. Learn more in our [Postman guide](/api/rest/postman/)

## 1. Generate PayPal-Auth-Assertion header [#1-generate-paypal-auth-assertion-header]

Pass the [`PayPal-Auth-Assertion`](/api/rest/requests/#paypal-auth-assertion) header with the standard `Content-Type`, `Authorization`, and `PayPal-Request-ID`headers. The value of the `PayPal-Auth-Assertion` header can be generated as follows:

```text lineNumbers
// client-side JavaScript

function encodeObjectToBase64(object) {
  const objectString = JSON.stringify(object);
  return window.btoa(objectString);
}

const clientId = "CLIENT-ID";
const sellerPayerId = "SELLER-PAYER-ID"; // preferred
// const sellerEmail = "SELLER-ACCOUNT-EMAIL"; // use instead of payer-id if required

const header = {
  alg: "none"
};
const encodedHeader = encodeObjectToBase64(header);

const payload = {
  iss: clientId,
  payer_id: sellerPayerId
  // email: sellerEmail
};
const encodedPayload = encodeObjectToBase64(payload);

const jwt =`${encodedHeader}.${encodedPayload}.`; // json web token
console.log(`Paypal-Auth-Assertion=${jwt}`);
```

> **Info:** **Note:** The token contains two period (`.`) characters, which are required according to the JSON web token structure.

### Modify the code [#modify-the-code]

* Use the client ID of the platform or marketplace from the PayPal Developer dashboard for `clientID`.
* The `sellerPayerId` is the payer ID of the receiving seller's PayPal account. You can also use `email` instead of `payer_id`and supply the email address of the seller's PayPal account.

Example functions to generate the `PayPal-Auth-Assertion` header in other programming environments:

#### Node.js [#nodejs]

```text lineNumbers
// Node.js

function encodeObjectToBase64(object) {
  const objectString = JSON.stringify(object);
  return Buffer
    .from(objectString)
    .toString("base64");
}

const clientId = "CLIENT-ID";
const sellerPayerId = "SELLER-PAYER-ID"; // preferred
// const sellerEmail = "SELLER-ACCOUNT-EMAIL"; // use instead if payer-id unknown\n
const header = {
  alg: "none"
};
const encodedHeader = encodeObjectToBase64(header);

const payload = {
  iss: clientId,
  payer_id: sellerPayerId
  // email: sellerEmail
};
const encodedPayload = encodeObjectToBase64(payload);

const jwt = `${encodedHeader}.${encodedPayload}.`; // json web token
console.log(`Paypal-Auth-Assertion=${jwt}`);
```

#### Java [#java]

```text lineNumbers
// Java

import org.apache.commons.codec.binary.Base64;

public class Base64Encode {

  public static void main(String[] args) {
    String clientId = "CLIENT-ID";
    String sellerPayerId = "SELLER-PAYER-ID"; // preferred
    // String sellerEmail = "SELLER-ACCOUNT-EMAIL"; // use instead if payer-id unknown\n
    String header = "{\\"alg\\":\\"none\\"}";
    String payload =
      "{\\"iss\\":\\"" + clientId + "\\",\\"payer_id\\":\\"" + sellerPayerId + "\\"}";
    // "{\"iss\":\"" + clientId + "\",\"email\":\"" + sellerEmail + "\"}";\n
    byte[] encodedHeader = Base64.encodeBase64(header.getBytes());
    byte[] encodedPayload = Base64.encodeBase64(payload.getBytes());\n
    String jwt = new String(encodedHeader) +
      "." +
      new String(encodedPayload) +
      "."; // json web token
    System.out.println("Paypal-Auth-Assertion=" + jwt);
  }
}
```

For more information about request headers, see [HTTP request headers](/api/rest/requests/#paypal-auth-assertion).

## 2. Create product [#2-create-product]

To create a product for your subscription plan, copy and modify the following code:

### Sample request [#sample-request]

**API endpoint used:** [Create product](/api/catalog-products/v1/products-create)

```text lineNumbers
curl -v -X POST https://api-m.sandbox.paypal.com/v1/catalogs/products -H "Content-Type: application/json" -H "Authorization: Bearer ACCESS-TOKEN" -H "PayPal-Request-Id: REQUEST-ID" -H "PayPal-Auth-Assertion: AUTH-ASSERTION" -d '{
      "name": "Video Streaming Service",
      "description": "A video streaming service",
      "type": "SERVICE",
      "category": "SOFTWARE",
      "image_url": "https://example.com/streaming.jpg",
      "home_url": "https://example.com/home"
    }'
```

### Modify the code [#modify-the-code-1]

After you copy the code in the sample request, modify the following:

* Change `ACCESS-TOKEN` to your access token.
* Replace `REQUEST-ID` with a unique ID that you generate. This ID helps prevent duplicate requests if the API call is disrupted.

* Change the `AUTH-ASSERTION` header to your JSON Web Token (JWT) assertion that identifies your seller. For more information on how to create a JWT, see [`PayPal-Auth-Assertion`](/api/rest/requests/#paypal-auth-assertion).

* Optional: Change parameters such as the `name` and `description` to represent your product.

### Step result [#step-result]

A successful request results in the following:

* The HTTP status code `201 Created`.

* A JSON response body that contains an `id` for the product. Use this ID to complete other actions through the REST API, such as creating a subscription plan.

#### Sample response [#sample-response]

```text lineNumbers
{
    "id": "PROD-5FD60555F23244316",
    "name": "Video Streaming Service",
    "description": "A video streaming service",
    "create_time": "2020-01-21T16:04:39Z",
    "links": [
        {
            "href": "https://api-m.sandbox.paypal.com/v1/catalogs/products/PROD-5FD60555F23244316",
            "rel": "self",
            "method": "GET"
        },
        {
            "href": "https://api-m.sandbox.paypal.com/v1/catalogs/products/PROD-5FD60555F23244316",
            "rel": "edit",
            "method": "PATCH"
        }
    ]
}
```

## 3. Create subscription plan [#3-create-subscription-plan]

The following sample request is an example of a subscription plan. Modify the code to fit your subscription model.

Review the following topics to help understand how to modify the code for your use case:

* [Customize subscriptions](/subscriptions/customize)
* [Create plan REST API endpoint](/api/subscriptions/v1/plans-create)

### Sample request [#sample-request-1]

This sample request creates a subscription plan that:

* Has a 1-month free trial and continues as a 12-month, fixed-price subscription
* Includes a $10 USD setup fee
* Bills any outstanding balance at the next billing cycle
* Allows the subscription to continue if the initial payment for the setup fails
* Suspends the subscription after 3 consecutive payment failures
* Includes a 10% tax in the billing amount

> **Warning:** **Important:** Only one `currency_code` is allowed per subscription plan. Make a new subscription plan to offer a subscription in another currency.

**API endpoint used:** [Create plan](/api/subscriptions/v1/plans-create)

```text lineNumbers
curl -v -k -X POST https://api-m.sandbox.paypal.com/v1/billing/plans   -H "Accept: application/json"   -H "Authorization: Bearer <Access-Token>"   -H "PayPal-Request-Id: 123e4567-e89b-12d3-a456-426655440020"   -H "PayPal-Auth-Assertion: eyJhbGciOiJub25lIn0.eyJpc3MiOiJjbGllbnRfaWQiLCJlbWFpbCI6Im15LWVtYWlsQGV4YW1wbGUuY29tIn0."   -d '{
      "product_id": "PROD-5FD60555F23244316",
      "name": "Basic Plan",
      "description": "Basic plan",
      "billing_cycles": [
        {
          "frequency": {
            "interval_unit": "MONTH",
            "interval_count": 1
          },
          "tenure_type": "TRIAL",
          "sequence": 1,
          "total_cycles": 1
        },
        {
          "frequency": {
            "interval_unit": "MONTH",
            "interval_count": 1
          },
          "tenure_type": "REGULAR",
          "sequence": 2,
          "total_cycles": 12,
          "pricing_scheme": {
            "fixed_price": {
              "value": "10",
              "currency_code": "USD"
            }
          }
        }
      ],
      "payment_preferences": {
        "auto_bill_outstanding": true,
        "setup_fee": {
          "value": "10",
          "currency_code": "USD"
        },
        "setup_fee_failure_action": "CONTINUE",
        "payment_failure_threshold": 3
      },
      "taxes": {
        "percentage": "10",
        "inclusive": false
      }
    }'
```

### Modify the code [#modify-the-code-2]

After you copy the code in the sample request, modify the following:

* Change `ACCESS-TOKEN` to your access token.
* Replace `REQUEST-ID` with a unique ID that you generate. This ID helps prevent duplicate requests if the API call is disrupted.

* Change the `AUTH-ASSERTION` header to your JSON Web Token (JWT) assertion that identifies your seller. For more information on how to create a JWT, see [`PayPal-Auth-Assertion`](/api/rest/requests/#paypal-auth-assertion).

* Change the value of the `product_id` parameter to the ID returned when you created the product.
* (Optional) Change or add parameters in the [Create plan request body](/api/subscriptions/v1#plans-create-request-body) to create a plan that meets your business needs. Some examples:
  * Fixed pricing plans
  * User or seat-based pricing plans
  * Free or discounted trials

### Step result [#step-result-1]

A successful request results in the following:

* The HTTP status code `201 Created`.

* A JSON response body containing an `id` for the subscription plan. Use the subscription plan ID to complete other actions through the REST API, such as editing or deactivating the plan.
* A subscription plan in the seller's PayPal account in the `On` status.

#### Sample response [#sample-response-1]

To see how the result of this API call looks in the seller's account, use your sandbox business account credentials to log in to [https://www.sandbox.paypal.com/billing/plans](https://www.sandbox.paypal.com/billing/plans). The subscription plan reflects the plan nu

```text lineNumbers
{
    "id": "P-17M15335A8501272JLXLLNKI",
    "product_id": "PROD-5FD60555F23244316",
    "name": "Basic Plan",
    "status": "ACTIVE",
    "description": "Basic plan",
    "create_time": "2020-01-21T16:09:13Z",
    "links": [
        {
            "href": "https://api-m.sandbox.paypal.com/v1/billing/plans/P-17M15335A8501272JLXLLNKI",
            "rel": "self",
            "method": "GET"
        },
        {
            "href": "https://api-m.sandbox.paypal.com/v1/billing/plans/P-17M15335A8501272JLXLLNKI",
            "rel": "edit",
            "method": "PATCH"
        },
        {
            "href": "https://api-m.sandbox.paypal.com/v1/billing/plans/P-17M15335A8501272JLXLLNKI/deactivate",
            "rel": "self",
            "method": "POST"
        }
    ]
}
```

## 4. Create subscription [#4-create-subscription]

Create a subscription for your plan.

**API endpoint used:** [Create subscription](/api/subscriptions/v1/subscriptions-create)

```text lineNumbers
curl -v -X POST https://api-m.sandbox.paypal.com/v1/billing/subscriptions \
    -H "Content-Type: application/json" \
    -H "Authorization: Bearer <Access-Token>" \
    -H "PayPal-Partner-Attribution-Id: Example_Marketplace" \
    -H "PayPal-Request-Id: 123e4567-e89b-12d3-a456-426655440020" \
    -H "PayPal-Auth-Assertion: eyJhbGciOiJub25lIn0.eyJpc3MiOiJjbGllbnRfaWQiLCJlbWFpbCI6Im15LWVtYWlsQGV4YW1wbGUuY29tIn0." \
    -d '{
      "plan_id": "P-17M15335A8501272JLXLLNKI",
      "start_time": "2020-01-22T00:00:00Z",
      "quantity": "20",
      "shipping_amount": {
        "currency_code": "USD",
        "value": "10.00"
      },
      "subscriber": {
        "name": {
          "given_name": "John",
          "surname": "Doe"
        },
        "email_address": "customer@example.com",
        "shipping_address": {
          "name": {
            "full_name": "John Doe"
          },
          "address": {
            "address_line_1": "2211 N First Street",
            "address_line_2": "Building 17",
            "admin_area_2": "San Jose",
            "admin_area_1": "CA",
            "postal_code": "95131",
            "country_code": "US"
          }
        }
      },
      "application_context": {
        "brand_name": "example-retail",
        "locale": "en-US",
        "shipping_preference": "SET_PROVIDED_ADDRESS",
        "user_action": "SUBSCRIBE_NOW",
        "payment_method": {
          "payer_selected": "PAYPAL",
          "payee_preferred": "IMMEDIATE_PAYMENT_REQUIRED"
        },
        "return_url": "https://example.com/returnUrl",
        "cancel_url": "https://example.com/cancelUrl"
      }
    }'
```

### Modify the code [#modify-the-code-3]

After you copy the code in the sample request, modify the following:

* Change `Access-Token` to your access token.
* Replace the value for the `PayPal-Partner-Attribution-Id` to your BN code.
* Replace the sample ID for `PayPal-Request-Id` with a unique ID you generate. This ID helps prevent creating duplicate products in the event that the API call is disrupted. See also: [API Idempotency](/reference/guidelines/idempotency/).
* Replace the `PayPal-Auth-Assertion` header with your own JSON Web Token (JWT) assertion that identifies your seller. For more information on how to create a JWT, see [`PayPal-Auth-Assertion`](/api/rest/requests/#paypal-auth-assertion).
* Determine the value for `subscriber/shipping_address`:
  * If you don't need to ship your services, set `application_context/shipping_preference` to `NO_SHIPPING`. This hides shipping information fields on the PayPal Review page.
  * If the buyer entered a shipping address on the seller's site, pass the shipping address to PayPal here.
  * If the buyer didn't enter a shipping address on the seller's site, you can edit the shipping address on the PayPal Review page. Leave `application_context/shipping preference` blank or set it to `GET_FROM_FILE`.
* (Optional) Use the `application_context/user_action` field to automatically activate subscriptions. Set the field to `SUBSCRIBE_NOW` or send it empty. The default value is `SUBSCRIBE_NOW`. Otherwise, you need to make a [`POST v1/billing/subscriptions/{ID}/activate`](/api/subscriptions/v1/subscriptions-activate) call to activate the subscription.

#### Sample response [#sample-response-2]

```text lineNumbers
{
  "id": "I-BW452GLLEP1G",
  "status": "APPROVAL_PENDING",
  "status_update_time": "2018-12-10T21:20:49Z",
  "plan_id": "P-17M15335A8501272JLXLLNKI",
  "start_time": "2020-01-22T00:00:00Z",
  "quantity": "20",
  "shipping_amount": {
    "currency_code": "USD",
    "value": "10.00"
  },
  "subscriber": {
    "name": {
      "given_name": "John",
      "surname": "Doe"
    },
    "email_address": "customer@example.com",
    "payer_id": "2J6QB8YJQSJRJ",
    "shipping_address": {
      "name": {
        "full_name": "John Doe"
      },
      "address": {
        "address_line_1": "2211 N First Street",
        "address_line_2": "Building 17",
        "admin_area_2": "San Jose",
        "admin_area_1": "CA",
        "postal_code": "95131",
        "country_code": "US"
      }
    }
  },
  "create_time": "2018-12-10T21:20:49Z",
  "links": [
    {
      "href": "https://www.paypal.com/webapps/billing/subscriptions?ba_token=BA-2M539689T3856352J",
      "rel": "approve",
      "method": "GET"
    },
    {
      "href": "https://api-m.paypal.com/v1/billing/subscriptions/I-BW452GLLEP1G",
      "rel": "edit",
      "method": "PATCH"
    },
    {
      "href": "https://api-m.paypal.com/v1/billing/subscriptions/I-BW452GLLEP1G",
      "rel": "self",
      "method": "GET"
    }
  ]
}
```

### Step result [#step-result-2]

* A return status code of HTTP `201 Created`.
* A JSON response body that contains an ID for the subscription. You can use this ID to complete other actions through the REST API, such as updating the subscription.
* Save the Subscription ID returned in the `id` field of the API response.
* (Optional) Change or add other parameters to customize the subscription plan. Refer to [Capabilities](/platforms/subscriptions/customize/) to learn more about how you can customize the plan.

## 5. Create button [#5-create-button]

To start a subscription from your website, add the PayPal JavaScript SDK code and modify it. This code adds buttons to your website so your buyers can use PayPal or a debit or credit card.

### Add and modify the code [#add-and-modify-the-code]

1. Copy and paste this code into webpage to create the buttons. When your buyer selects a button, they are directed to PayPal to complete subscription agreement and payment.

```text lineNumbers
<!DOCTYPE html>
<head>
   <meta name="viewport" content="width=device-width, initial-scale=1"> <!-- Ensures optimal rendering on mobile devices. -->
</head>
<body>
  <script src="https://www.paypal.com/sdk/js?client-id=YOUR_CLIENT_ID&vault=true&intent=subscription">
  </script> // Add your client_id
     <div id="paypal-button-container"></div>
      <script>
       paypal.Buttons({
        createSubscription: function(data, actions) {
          return actions.subscription.create({
           'plan_id': 'YOUR_PLAN_ID' // Creates the subscription
           });
         },
         onApprove: function(data, actions) {
           alert('You have successfully subscribed to ' + data.subscriptionID); // Optional message given to subscriber
         }
       }).render('#paypal-button-container'); // Renders the PayPal button
      </script>
  </body>
</html>
```

2. Modify the code as follows:

* Change `YOUR_CLIENT_ID` to your client ID.
* Change `YOUR_PLAN_ID` to the plan ID returned from the Create Plan API call.

3. Load the webpage to see the payment buttons:

<img src="https://www.paypalobjects.com/ppdevdocs/img/docs/ppcp-b/configure-payments/subscriptions/subscription.png" alt="Subscription,Configuration" />

> **Tip:** **Tip:** To render more than one button on a single webpage, see [Multiple subscribe buttons for your website](/subscriptions/multiple-buttons).

## 6. Test flow [#6-test-flow]

Test a transaction to see the subscription created in the merchant account:

### Test the transaction as a buyer [#test-the-transaction-as-a-buyer]

1. Select the PayPal button on the page.
2. Use the sandbox personal login information from the Developer Dashboard to log in and simulate the buyer making a purchase.
3. In the Checkout window, make a note of the purchase amount in the upper right corner. USD is the default currency. You can customize the JavaScript SDK by adding a different [currency code](/sdk/js/configuration/#currency)

   > **Note:** **Availability**: The JavaScript SDK onShippingChange, onShippingAddressChange, and onShippingOptionsChange functions are not compatible with Subscriptions.
4. Select the arrow next to the purchase amount to view the subscription details:

   <img src="https://www.paypalobjects.com/ppdevdocs/img/docs/ppcp-b/configure-payments/subscriptions/subscription_details.png" alt="The,subscription,details,popup,,which,shows,a,breakdown,of,the,subscription,cost,,when,the,subscription,starts,,and,the,total,amount,due." />
5. Select the test credit card as the payment method and select **Continue**.
6. Select **Agree & Subscribe** to agree to the terms of the subscription.

### Confirm the movement of funds from the buyer account [#confirm-the-movement-of-funds-from-the-buyer-account]

1. Use the sandbox personal account you used to complete the purchase to log in to [https://www.sandbox.paypal.com/myaccount/autopay/connect/](https://www.sandbox.paypal.com/myaccount/autopay/connect/).
2. Confirm the subscription appears in the active automatic payment list. Select the active automatic payment to see the details of the subscription.
3. Log out of the account.

### Confirm the movement of funds to the merchant account [#confirm-the-movement-of-funds-to-the-merchant-account]

1. Use the sandbox business account information from the Developer Dashboard to log in to[https://www.sandbox.paypal.com/billing/subscriptions](https://www.sandbox.paypal.com/billing/subscriptions).
2. Confirm the subscription made by the test buyer appears on the **Subscriptions** tab. Select the subscription to see the details of the subscription.
3. Log out of the account.

## Next steps & customizations [#next-steps--customizations]

> **Info:** Customize your subscription integration
>
> Use the Subscriptions API capabilities to customize your integrations.

> **Info:** ### Test and go live with your subscription integration [#test-and-go-live-with-your-subscription-integration]
>
> You can run negative tests on your integration to manage the responses you give to your customers.
>
> [Go live](/subscriptions/test-go-live)

## See also [#see-also]

* [Catalog Products REST API](/api/catalog-products/v1/) and [Subscriptions REST API](/api/subscriptions/v1) - Use these APIs to add actions to your integration, such as updating the product description, editing the plan or subscription, deactivating the plan or subscription, and more.
* [Subscriptions webhook events](/api/rest/webhooks/event-names/#subscriptions) - Use webhooks to handle tasks triggered by subscription actions.
