This article describes how you can use the Velo Paid Plans API to customize how you offer pricing plans to your site's visitors. We're going to explain how we set up a sample site and the code we added to make it work.
Note. The Paid Plans API corresponds to the Pricing Plans app that you add to your site. The app uses the term "pricing plan" while some of the API parameters and properties are based on the term "paidPlan."
The customization in this sample includes:

Overview

In our site we added the following:
Then we added code to do the following:
  1. When a visitor clicks the See More button, the button's click event handler calls the
    to()
    function to open the dynamic page.
  2. When a visitor clicks the Buy Now button for a free plan, the button's click event handler calls the
    orderPlan()
    function to order the plan and opens a congratulations lightbox.
  3. When a visitor clicks the Buy Now button for a plan that costs money, the button's click event handler opens a confirmation lightbox.
  4. When a visitor clicks Yes, the button's event handler calls the
    orderPlan()
    function to order the plan.
  5. The function checks if the user is logged in, and if not, prompts for login.
  6. When the user is logged in, the function creates, and returns, an
    orderResult
    object.
  7. A payment procedure is initiated using the ID from the
    orderResult
    object, causing a payment window to appear.
  8. The visitor enters payment information and completes the transaction. This triggers the
    onPlanPurchased
    event, which returns a
    PlanPurchasedEvent
    object.
  9. An event is logged in a collection. The event is based on the
    PlanPurchasedEvent
    object.
Here is the Velo Sidebar with the resources we created for this example:
Note. This example demonstrates how, with Velo, we can customize the membership plan flow. We intentionally did not use the standard Plans & Pricing page that is automatically created when adding the Pricing Plans app.

Before You Start

Before you start working with Wix pricing plans in code, make sure you do the following:

Step 1: Set up Collections

For this example, we added the Pricing Plans app to set up this collection:
We manually created these collections:
Note. You may need to save/publish the site and refresh your browser to view collections in the Databases section of the Velo Sidebar.
The PaidPlans/Plans Collection
Adding the Wix Pricing Plans app to your site automatically creates the
PaidPlans/Plans collection. This collection contains the basic fields necessary to work with pricing plans, such as the plan title, its price, its duration, its benefits, and so on. The Plans collection is read-only.
This is what some of the data in our Plans collection looks like. 
The plan title is saved in the Name field. Then, a field called Slug is created with similar but unique values. We used the Slug field to link to other collections.
Additional Collections
You can create additional collections for additional plan details, such as testimonials and an image for each plan.
In our new Testimonials collection, we added a PlanName reference field that references the Slug field in our Plans collection. The reference field links the testimonials and plan images to the corresponding plan in the Plans collection.
This is what some of the data in our Testimonials collection looks like:
PlanEvents Collection
We created a collection to track successful purchases. We added a text field called Data to the collection.
We created code in an events.js page to insert the live data from the PlanPurchasedResult object into the Title and Data fields.
This is what some of the live data in our PlanEvents collection looks like, after we have made a few purchases.

Step 2: Set up the Collection & Repeater Page

We created a new page for displaying all the plans in our collection with a repeater.
Design the Page
On the Collection & Repeater page, we added:
Because the Testimonials collection has a reference field to our PaidPlans/Plans collection, all the data we need is accessible with this one dataset.
Note. When you display data from a collection in a repeater, you must first connect the repeater to the dataset, and then connect each element in the repeater to the dataset.
Add Event Handlers
Code the Page
We added the following code to let the visitor select and view a specific plan.
// For navigating to a dynamic page:
import wixLocation from 'wix-location';


$w.onReady(function () {
    
 // If the site visitor clicks a plan's See More button,
 // the browser relocates to that plan's dynamic page.
    
 $w("#button1").onClick((event, $w) => {
  let item = $w("#dataset1").getCurrentItem();
  let slug = item.planName.slug;
     
 // We customized the URL for the plan's page
 // when we made it dynamic. 
 wixLocation.to('/gamePlans/'+slug);
  
 })

})

Step 3: Customize the Purchase of a Plan

To demonstrate that we can customize the flow of a paid plan purchase, we will use the
orderPlan()
function instead of the
purchasePlan()
function.
As part of our customization, we added two lightboxes to our site (to be used in Step 5).
In this step, we kept it simple. However, this is the opportunity for you to really customize the process as you like.

Step 4: Set up an Event Handler in the Backend to Log Purchases

When a plan is successfully purchased or ordered, an onPlanPurchased event is triggered.
In our example, when this event is fired, we log the details about the purchase by inserting the information in our
PlanEvents
collection.
Here is sample backend code that we put in an
events.js
file.
/*****************************
 * Backend code in events.js *
 *****************************/

// For inserting data into a collection.
import wixData from 'wix-data';

// The onPlanPurchased() event is fired when a plan
// is purchased, or a free plan is ordered. 
// Get the order information
// from the event's order object.

export function wixPaidPlans_onPlanPurchased(event) {

    // The PlanEvents collection has a title field, 
    // in which we insert the type of transaction. 
    // The collection also has a data field, 
    // where we will insert information about the order
    // from the event's order object (json). 

 if (event.order.price.amount === 0) {
  let orderData = {
   "title": "Free plan purchased",
   "data": event.order
  };
  wixData.insert("PlanEvents", orderData);

 } else {
  let orderData = {
   "title": "Regular plan purchased",
   "data": event.order
  };
  wixData.insert("PlanEvents", orderData);
 }
}

Step 5: Customize your Dynamic Page

Next we created a new page for displaying each selected plan.
Design the Page
On this page, we added:
Add Event Handlers
Code the Page
The code on our dynamic page consists of five parts:
Let's take a look at the code one piece at a time.  At the end of this article, you can see the code in its entirety.
The Imports
We used the following APIs:
So our importing code looks like this:
import wixWindow from 'wix-window';
import wixPay from 'wix-pay';
import wixPaidPlans from 'wix-paid-plans';
import wixUsers from 'wix-users';
onReady()
Event Handler
In this example, there is no special setup we need to do for our elements. So we used the standard
onReady()
event handler.
$w.onReady( () => {
  ...
  ...
  //Insert code here.
  ...
  ...
} );
getCurrentItem()
Function
Next, we retrieved the current plan's data from the PaidPlans\Plans collection using the Wix Dataset getCurrentItem function with the dynamic dataset on the page. We stored the information in a
currentPlanObject
object variable. Now we have access to the information we need about the plan to continue processing the order or purchase.
If you copy the code snippet below, make sure to change the dataset name to match your own.
$w.onReady( () => {
  ...
  ...
  
  const currentPlanObject = $w("#dynamicDataset").getCurrentItem();
  const planId = currentPlanObject._id;
  const planPrice = currentPlanObject.price;
  ...
  ...
  //Insert more code here.
  ...
  ...
} );
onClick()
Event Handler
Most of the logic in our page is contained in the
onClick()
event handler of the
buyNow
button.
If you copy the code snippet below, make sure to change the button name to match your own.
$w.onReady( () => {
  ...
  ...
  
  const currentPlanObject = $w("#dynamicDataset").getCurrentItem();
  const planId = currentPlanObject._id;
  const planPrice = currentPlanObject.price;
  ...
  ...
  $w('#buyNow').onClick((event) => {

    ...
    //Insert code for handling the button click here.
    ...
    
  });
  ...
  ...
  //Insert more code here.
  ...
  ...
} );
Check if Logged In
We don't want to sell plans to users that are not logged in. So we used the
wixUsers.currentUser
and the
loggedIn
property to see if the user is logged in.
$w.onReady( () => {

  const currentPlanObject = $w("#dynamicDataset").getCurrentItem();
  const planId = currentPlanObject._id;
  const planPrice = currentPlanObject.price;

  $w('#buyNow').onClick((event) => {

    let user = wixUsers.currentUser;
    let isLoggedIn = user.loggedIn;
    if (!isLoggedIn) {
      wixUsers.promptLogin().then(() => {
          processPlan(planId, planPrice);
        })
    } else {
        processPlan(planId, planPrice);
    }   
  });
});
Process the Order
Now let's look at the function we created,
processPlan()
, to get payment for the plan.
We chose to use the
orderPlan()
function for processing because we wanted to control and customize the entire order/purchase flow. When
orderPlan()
is called, and a plan is successfully purchased or ordered, an
onPlanPurchased
event is triggered.
This is where you can enter your own code to customize your own order/purchase flow.
In our example, we customized the flow by:
The order details are contained in the
orderObject
object.
When copying this snippet, make sure to change the names of your lightboxes to match your own.
function processPlan(myId, myPrice) {

  if (myPrice > 0) {
    wixPaidPlans.orderPlan(myId).then(orderObject => {
      wixWindow.openLightbox("Confirm", orderObject)
       .then((goForIt) => {
       if (goForIt) {
         wixPay.startPayment(orderObject.wixPayOrderId);
       }
      });
    })
  } else {
    wixPaidPlans.orderPlan(myId).then(orderObject => {
      wixWindow.openLightbox("Congrats", orderObject);
    })
  }
}
All the Code
The code in its entirety looks like this:
import wixWindow from 'wix-window';
import wixPay from 'wix-pay';
import wixPaidPlans from 'wix-paid-plans';
import wixUsers from 'wix-users';

$w.onReady(function () {

  const currentPlanObject = $w("#dynamicDataset").getCurrentItem();
  const planId = currentPlanObject._id;
  const planPrice = currentPlanObject.price;

  $w('#buyNow').onClick((event) => {

    let user = wixUsers.currentUser;
    let isLoggedIn = user.loggedIn;
    if (!isLoggedIn) {
      wixUsers.promptLogin().then(() => {
        processPlan(planId, planPrice);
      })
    } else {
      processPlan(planId, planPrice);
    }
 });
});

function processPlan(myId, myPrice) {

  if (myPrice > 0) {
    wixPaidPlans.orderPlan(myId).then(orderObject => {
      wixWindow.openLightbox("Confirm", orderObject)
       .then((goForIt) => {
       if (goForIt) {
         wixPay.startPayment(orderObject.wixPayOrderId);
       }
      });
    })
  } else {
    wixPaidPlans.orderPlan(myId).then(orderObject => {
      wixWindow.openLightbox("Congrats", orderObject);
    })
  }
}
Tip: Want to use the standard, "out of the box" Wix flow for letting visitors purchase a plan?

API List

The following APIs are used in the code in this article. To learn more, see the API Reference.