Skip to main content

Implement the Plugin Installation Flow

caution

Bold Commerce encourages developers to use integrations in order to extend Bold Checkout, instead of plugins. There are two types of integrations: private and public. For more information, refer to Extending Bold Checkout.

Merchants install public plugins via the Checkout Marketplace, which is found in the Bold Checkout app. The following gif shows the typical process for installing a plugin:

Gif that shows someone navigating to the Checkout marketplace, clicking Install on an example plugin, accepting the scopes, and returning to the Checkout Marketplace

There are several stages of communication between Bold and the plugin to enable this installation flow. The following steps explain how to set up this exchange.

note

These steps are also shown in the oauth.js file of the Checkout Example Plugin.

Prerequisites

  1. Follow the steps in Getting Started with Plugins.

Identify and request required scopes

When a merchant clicks Install, Checkout Marketplace displays the scopes that the plugin requires. Each scope describes the operation the plugin would like to perform. For more information, refer to the scopes section of the Plugins page.

The following steps explain how to configure your plugin to display the appropriate scopes when prompted.

note

Refer to these lines in the Checkout Example Plugin for a sample implementation of these steps.

Define the scopes your plugin requires

Each action requires a certain scope. The full list of actions and their associated scopes can be found in the Plugin Action Reference — use this page to determine which scopes your plugin needs.

note

If you decide that your plugin requires different scopes than it originally requested, the merchant must uninstall and reinstall the plugin to use those scopes on that store.

Bold calls the Install Redirect URL

When a merchant clicks Install, Bold Checkout calls your plugin's Install Redirect URL (which you provided to Bold in the Plugin Intake Form) with information about the merchant's store.

The following code snippet shows the call Bold makes to your plugin. In this call,

  • platform is the platform of the store.
  • shop is the platform-specific identifier of the store.
GET https://examplestore.myplatform.com/install?platform={platform}&shop={shop}

Plugin replies with scopes

Your plugin must accept this call, create a list of scopes, and respond to Bold with a redirect.

The following code snippet shows an example of this redirect. In this response,

  • platform is the platform of the store.
  • shop is the platform-specific identifier of the store.
  • client_id is the publicly-available identifier for your plugin.
  • scope is the space-delimited list of scopes that your plugin requires.
res.redirect(
`https://cashier.boldcommerce.com/api/v1/${platform}/${shop}/oauth/authorize?client_id=${client_id}&scope=${scope}&response_type=code`
);

When Bold receives this redirect from the plugin, Checkout Marketplace displays the scopes requested and prompts the merchant to accept or deny them.

Authorize the plugin

After examining the scopes that the plugin requests, a merchant can click Allow or Cancel.

The following steps explain how to authorize an installation of the plugin on the store if the merchant clicks Allow.

note

Refer to these lines in the Checkout Example Plugin for a sample implementation of these steps.

Bold calls the Authorize Redirect URL

After a merchant clicks Allow, Bold calls your plugin's Authorize Redirect URL (which you provided to Bold in the Plugin Intake Form).

The following code snippet shows the call Bold makes to your plugin. In this call,

  • platform is the platform of the store.
  • shop is the platform-specific identifier of the store.
  • code is a temporary authorization code generated by Bold.
GET https://example-plugin.com/authorize?platform={platform}&shop={shop}&code={code}

This call notifies the plugin that someone would like to install it.

Exchange temporary code for an access token

In order for the plugin to make calls to Bold on behalf of a certain merchant, it needs an API access token. The plugin must request that API access token for every store it is installed on.

The following snippet shows an example of this call from the plugin to Bold. In this call,

  • client_id is the publicly-available identifier for your plugin.
  • client_secret is the string provided by Bold to ensure secure communication between the plugin and Bold.
  • code is the code provided when Bold called your Authorize Redirect URL.
  • grant_type is the type of authorization the plug requests.
POST https://cashier.boldcommerce.com/api/v1/{platform}/{shop}/oauth/access_token
--data {
"client_id": "d5cb40ab-05af-4168-b1e0-a37660824779",
"client_secret": "kjjcEyJdRzn1dusPU5aAChHZC1s3DWHS0ZdRKgxxIUbEPf6wqPRZTpJjUPmUj116",
"code": "mnU8xUaGr1ACMDl793tnJEN7gBmT9SN8YLFcmRh7q72hIsy61HeYfHRUyjW0SxSL",
"grant_type": "authorization_code"
}

In response to this call, Bold sends a response with information about the store and the API access token. The following snippet shows an example:

{
"shop": "examplestore.myplatform.com",
"platform": "shopify",
"access_token": "yPdckrPdqOHkyBkx0spIgNhXLi5jI8uXaNxXvJqOJ7g0N2ljAvJqBGpgEsclsfkt",
"scope": "add_tags provide_discounts",
"token_type": "bearer"
}

The access_token represents an installation of the plugin on one store. The plugin must store each access_token in a database. Use the access token in future calls made on behalf of the store.

Redirect the merchant

After obtaining the access_token, the plugin must redirect the merchant to a desired site. While you can redirect the merchant anywhere, most plugins redirect either to an external landing page or back to the Checkout Marketplace page.

The following snippet shows how to redirect a user back to the Checkout Marketplace page:

res.redirect(`https://cashier.boldcommerce.com/admin/{platform}/{shop}/marketplace`);

(Optional) Allow the merchant to configure the plugin

If your plugin requires it, you can also allow the merchant to configure certain settings via a Configure button that appears in the Actions column of the Checkout Marketplace after the plugin is installed.

To enable this button to appear, you must provide a Marketplace Settings URL via the Plugin Intake Form. Reach out to the API Support Team if you already submitted this form without this URL.

You have two options for creating a plugin configuration page:

  • (Recommended) Redirect to your own hosted settings page.
  • Create a basic settings page that is embedded in the Bold Checkout admin.

The following steps outline the process for creating a simple settings page embedded in Bold Checkout.

Bold calls the Marketplace Settings URL

When a merchant clicks Configure on the Checkout Marketplace page, Bold makes a GET request to your Marketplace Settings URL with information about the store.

The following code snippet shows the call Bold makes to your plugin. In this call,

  • platform is the platform of the store.
  • shop is the platform-specific identifier of the store.
  • token is used in the response to communicate back to Bold Commerce.
GET https://example-plugin.com/settings?platform={platform}&shop={shop}&token={token}
note

If you want to redirect the merchant to your own hosted settings page, perform that routing when you receive this call. You can skip the remaining steps.

Define settings

In response to this call, the plugin is expected to respond with an array of settings objects that can be configured by the merchant. The following table shows the possible fields — all optional — of a settings object:

FieldAllowed TypesAllowed ValuesDescription
settings['name']objectAnyThe custom object name.
settings['name'].textstringAnyText displayed to the user for this object.
settings['name'].typestring"stringShort",
"string",
"checkbox",
"link",
"horizontalRule",
"header",
"toggle",
"number"
The type of object.
settings['name'].tooltipstringAnyA helpful hint for the user.
settings['name'].placeholderstring, numberAnyA placeholder.
settings['name'].valuestring, numberAnyUsed as the value for an input.
settings['name'].validation_schemaobjectAnyAn object for validating user inputs.
settings['name']
.validation_schema.required_if.target
stringRefCondition based on a selected target.
settings['name']
.validation_schema.required_if.errorText
stringAnyAn error text description.
settings['name']
.validation_schema.min.value
numberAnyA minimum number required.
settings['name']
.validation_schema.max.value
numberAnyA maximum number allowed.
settings['name']
.validation_schema.min.errorText
stringAnyAn error text description.
settings['name']
.validation_schema.max.errorText
stringAnyAn error text description.

In response to Bold's call to the Plugin Marketplace URL, you must respond with the token and the settings you want to display to the user. The following snippet shows a sample JSON response:

Expand to see example.
{
"token": "b72c9cda667f7481c673f4a1da093f1c8d8fb49e",
"settings": {
"shortString1": {
"text": "This is a short string field",
"type": "stringShort",
"tooltip": "Short string tooltip",
"placeholder": "Short string placeholder",
"value": "",
"validation_schema": {}
},
"regularString1": {
"text": "This is a regular string field ",
"type": "string",
"tooltip": "Regular string tooltip",
"placeholder": "Regular string placeholder",
"value": "",
"validation_schema": {}
},
"number1": {
"text": "This is a number field",
"type": "number",
"tooltip": "number tooltip",
"placeholder": "Number placeholder",
"value": "",
"validation_schema": {}
},
"checkbox1": {
"text": "This is a checkbox",
"type": "checkbox",
"tooltip": "checkbox tooltip",
"value": "",
"validation_schema": {}
},

"link1": {
"text": "This is a link",
"type": "link",
"value": "https://www.google.ca",
"validation_schema": {}
},
"horizontalRule1": {
"type": "horizontalRule",
"validation_schema": {}
},
"header1": {
"text": "This is a header",
"type": "header",
"tooltip": "This is a header tooltip",
"validation_schema": {}
},
"toggle1": {
"text": "This is a toggle",
"type": "toggle",
"tooltip": "toggle tooltip",
"value": 1,
"validation_schema": {}
},
"validationExampleNumber1": {
"text": "This is required when the toggle is checked",
"type": "number",
"tooltip": "Turn off toggle to not require this field",
"placeholder": "Number placeholder",
"value": "",
"validation_schema": {
"required_if": {
"target": "toggle1",
"errorText": "Required when toggle is on"
},
"min": {
"value": 5,
"errorText": "Must be greater than 5"
},
"max": {
"value": 1000,
"errorText": "Must be less than 1000"
}
}
}
}
}}

Bold sends selected settings

Bold displays the settings to the merchant within the Checkout Marketplace.

When a merchant makes their selections and clicks Save, Bold Checkout makes a POST request to your plugin's Marketplace Settings URL with query parameters and a body.

The following code snippet shows the call Bold makes to your plugin. In this call,

  • platform is the platform of the store.
  • shop is the platform-specific identifier of the store.
  • token is used in the response to communicate back to Bold Commerce.
POST https://example-plugin.com/settings?platform={platform}&shop={shop}&token={token}
--data {
shortString1: {
text: 'This is a short string field',
type: 'stringShort',
tooltip: 'Short string tooltip',
placeholder: 'Short string placeholder',
value: 'Hello World!',
validation_schema: {},
}
}

Persist store settings

Bold recommends that you store the merchant's input values in your database. This will allow the merchant to view their saved settings.

The following code snippet shows an example using TypeScript, Node.js & Mongo DB to allow you to save and persist custom settings data:

Expand to see example.
class Settings {
private db = db;

deafaultPlatformSettings() {
return {
thirdPartyAccessToken: {
text: 'Access Token',
type: 'stringShort',
tooltip: 'Example Thrid Party Integration Access Token',
value: '',
validation_schema: {},
},
};
}

async getPluginSettings(shop_domain: string) {
let dbName = shop_domain.replace(/\./g, '');
let pluginSettings = await this.db.client
.db(dbName)
.collection('settings');
let currentSettings = await pluginSettings.findOne({});
if (!currentSettings) {
return this.deafaultPlatformSettings();
} else {
return currentSettings.marketplace;
}
}

async updatePluginSettings(
shop_domain: string,
settings: any,
) {
try {
let dbName = shop_domain.replace(/\./g, '');
let pluginSettings = await this.db.client
.db(dbName)
.collection('settings');
let currentSettings = await pluginSettings.findOne({});
if (currentSettings?._id) {
await pluginSettings.findOneAndUpdate(
{ _id: currentSettings?._id },
{ $set: { marketplace: settings } },
{
new: true,
upsert: true,
} as any,
);
} else {
await pluginSettings.findOneAndUpdate(
{},
{
$set: { marketplace: settings },
},
{
new: true,
upsert: true,
} as any,
);
}

return currentSettings;
} catch (error) {
return error;
}
}
}

export default Settings;

Next steps

  1. Test that your installation flow implementation works by attempting to install the plugin on your development store through Checkout Marketplace.
  2. Implement the event-action loop to allow your plugin to receive events and respond with actions.