Implement the Plugin Installation Flow
Bold 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 Extend 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:
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.
These steps are also shown in the oauth.js
file of the Checkout Example Plugin.
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.
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.
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.
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 Customer Success 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.
GET https://example-plugin.com/settings?platform={platform}&shop={shop}&token={token}
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:
Field | Allowed Types | Allowed Values | Description |
---|---|---|---|
settings['name'] | object | Any | The custom object name. |
settings['name'].text | string | Any | Text displayed to the user for this object. |
settings['name'].type | string | "stringShort" ,"string" ,"checkbox" ,"link" ,"horizontalRule" ,"header" ,"toggle" ,"number" | The type of object. |
settings['name'].tooltip | string | Any | A helpful hint for the user. |
settings['name'].placeholder | string , number | Any | A placeholder. |
settings['name'].value | string , number | Any | Used as the value for an input. |
settings['name'].validation_schema | object | Any | An object for validating user inputs. |
settings['name'] .validation_schema.required_if.target | string | Ref | Condition based on a selected target. |
settings['name'] .validation_schema.required_if.errorText | string | Any | An error text description. |
settings['name'] .validation_schema.min.value | number | Any | A minimum number required. |
settings['name'] .validation_schema.max.value | number | Any | A maximum number allowed. |
settings['name'] .validation_schema.min.errorText | string | Any | An error text description. |
settings['name'] .validation_schema.max.errorText | string | Any | An 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.
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
- Test that your installation flow implementation works by attempting to install the plugin on your development store through Checkout Marketplace.
- Implement the event-action loop to allow your plugin to receive events and respond with actions.