Subscriptions

Create subscriptions so your sellers can bill their buyers at regular intervals.

On this page

Know before you code

How it works

How subscriptions work

  1. Create a product to represent your goods or services.
  2. Create a plan to represent the payment cycles for your subscription.
  3. Create a subscription button. When the buyer selects the button, the subscription experience begins.
  4. The buyer agrees and subscribes.
  5. The button calls the PayPal Subscriptions API to create the subscription.
  6. The buyer sees the subscription confirmation.

Step 1: Create a product

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

Sample request

API endpoint used: Create product

curl -v -X POST https://api.sandbox.paypal.com/v1/catalogs/products \
-H "Content-Type: application/json" \
-H "Authorization: Bearer Access-Token" \
-H "PayPal-Request-Id: 123e4567-e89b-12d3-a456-426655440020" \
-H "PayPal-Auth-Assertion: eyJhbGciOiJub25lIn0.eyJpc3MiOiJjbGllbnRfaWQiLCJlbWFpbCI6Im15LWVtYWlsQGV4YW1wbGUuY29tIn0." \
-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

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

  • Change Access-Token to your access token.
  • 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.
  • 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.
  • Optional: Change the name, description, and more to represent your actual product.

Step result

A successful request results in the following:

  • A return status code of HTTP 201 Created.
  • A JSON response body that contains an ID for the product. You can use this ID to complete other actions through the REST API, such as creating a subscription plan.

Sample response

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

Step 2: Create a plan

Because PayPal's Subscriptions API is flexible, you can create a highly customized subscription plan to fit your business' needs. The following sample request is only one example of a subscription plan. You will have to modify the code to fit your subscription's model.

Copy the code and try it out, but also review the subscription capabilities and the Create plan endpoint to determine how you might want to adjust this code for your use case.

Sample request

This sample request creates a subscription plan that:

  • Has a one-month free trial and continues as a 12-month, fixed-price subscription
  • Includes a $10 USD set up 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 three consecutive payment failures
  • Includes a 10% tax in the billing amount

API endpoint used: Create plan

curl -v -k -X POST https://api.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

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

  • Change Access-Token to your access token.
  • Change the value of the product_id parameter to the ID returned when you created the product.
  • Replace the sample ID for PayPal-Request-Id with a unique ID you generate. This ID helps prevent creating duplicate plans in the event that the API call is disrupted. See also: API 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.
  • (Optional) Change or add parameters in the Create plan request body to create a plan that meets your business needs. Some examples:
    • Fixed vs. quantity (user or seat) pricing plans
    • Free or discounted trials

Step result

A successful request results in the following:

  • A return status code of HTTP 201 Created.
  • A JSON response body containing a plan ID. Use the plan ID to complete other actions through the REST API, such as editing or deactivating the plan and creating a subscription.
  • A subscription plan in the seller's PayPal account in the On status.

Sample response

{
    "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.sandbox.paypal.com/v1/billing/plans/P-17M15335A8501272JLXLLNKI",
            "rel": "self",
            "method": "GET"
        },
        {
            "href": "https://api.sandbox.paypal.com/v1/billing/plans/P-17M15335A8501272JLXLLNKI",
            "rel": "edit",
            "method": "PATCH"
        },
        {
            "href": "https://api.sandbox.paypal.com/v1/billing/plans/P-17M15335A8501272JLXLLNKI/deactivate",
            "rel": "self",
            "method": "POST"
        }
    ]
}

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. The subscription plan reflects the plan number from the REST API call you made:

Plan in business account

Step 3: Create a subscription

Create a subscription for your plan.

API endpoint used: Create subscription

curl -v -X POST https://api.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

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.
  • 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.
  • 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 call to activate the subscription.

Sample response

{
  "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.paypal.com/v1/billing/subscriptions/I-BW452GLLEP1G",
      "rel": "edit",
      "method": "PATCH"
    },
    {
      "href": "https://api.paypal.com/v1/billing/subscriptions/I-BW452GLLEP1G",
      "rel": "self",
      "method": "GET"
    }
  ]
}

Step result

  • 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 to learn more about how you can customize the plan.

Step 4: Create a button

Create a subscription button and add it to your seller's site. The design of the button is up to you.

When the button is selected, use the approve HATEOS link returned in the Create subscription response. This redirects the buyer to a PayPal-hosted payment page. From there, they can choose to pay through PayPal, a credit card, or a debit card.

Next steps

Test and go live with this subscription integration.

See also