Skip to main content

Create and manage a product subscription app extension

Deprecated

Product subscription app extensions won't be supported as of December 3, 2025. You should migrate existing product subscription app extensions to purchase options extensions.

This tutorial explains how to create and manage a product subscription app extension. You'll use the Add, Create, Edit, and Remove extension modes to make requests to your app's backend server.


In this tutorial, you'll learn how to do the following tasks:

  • Set up requests to your app's backend server
  • Set up unit testing for your extension


Anchor to Step 1: Set up requests to your app’s backend serverStep 1: Set up requests to your app’s backend server

After you generate the product subscription app extension, you can set up requests to your app's backend server for each extension mode.

Anchor to Create a new purchase optionCreate a new purchase option

The Create mode enables users to create a new purchase option for the current product or one of its variants. The Create plan UI should display the plan title, the delivery frequency, and the discount percentage. The Create mode triggers the app overlay container.

The request to your backend server triggers the sellingPlanGroupsCreate mutation.

  1. In the payload, include the productId and variantId collected from the extension form.
  2. In the header, include the session token. If the response returns an OK status, then you can request done to re-render the modal and close to close it.

Input

interface CreatePayload {
productId: string;
variantId?: string;
}

onPrimaryAction in Create

const onPrimaryAction = useCallback(async () => {
const token = await getSessionToken();

// The product and variant IDs collected from the modal form
let payload = {
productId: data.productId,
variantId: data.variantId,
};

// Send the form data to your app server to create the new plan.
const response = await fetch('https://server-url-here', {
headers: {
'any-header-key': token || 'unknown token',
},
body: JSON.stringify(payload)
});

// If the server responds with an OK status, then refresh the UI and close the modal
if (response.ok) {
done();
} else {
console.log('Handle error.');
}

close();
}, [getSessionToken, done, close]);

Anchor to Add an existing purchase option to a product or variantAdd an existing purchase option to a product or variant

The Add mode enables users to add the current product to an existing purchase option. The Add plan UI should display a searchable list of purchase options on the shop. The purchase options that are already associated with the product either directly or through one of its variants should not be listed. The Add mode triggers the app modal container.

The request to your backend server triggers the productJoinSellingPlanGroups mutation, applying the selected SellingPlan objects to the current product.

  1. In the payload, include the productId and variantId collected from the extension form.
  2. In the header, include the session token. If the response returns an OK status, then you can request done to re-render the modal and close to close it.

Input

interface AddPayload {
productId: string;
variantId?: null;
}

primaryAction in Add

setPrimaryAction({
content: 'Add to plan',
onAction: async () => {
// Get a fresh session token before every request to your app server.
const token = await getSessionToken();

// The product and variant IDs collected from the modal form
let payload = {
productId: data.productId,
variantId: data.variantId,
};

// Here, send the form data to your app server to add the product to an existing plan.
const response = await fetch('https://server-url-here', {
headers: {
'any-header-key': token || 'unknown token',
},
body: JSON.stringify(payload)
});

// If the server responds with an OK status, then refresh the UI and close the modal
if (response.ok) {
done();
} else {
console.log('Handle error.');
}

close();
},
});

Anchor to Edit an existing purchase optionEdit an existing purchase option

The Edit mode enables users to edit a product's purchase option. The Edit plan UI should display the plan title, the delivery frequency, and the discount percentage. The Edit mode triggers the app overlay container.

The request to your backend service triggers the sellingPlanGroupUpdate mutation, applying the selected SellingPlan objects to the current product.

  1. In the payload, include the productId and variantId collected from the extension form and the sellingPlanGroupId.
  2. In the header, include the session token. If the response returns an OK status, then you can request done to re-render the modal and close to close it.

Input

interface EditPayload {
sellingPlanGroupId: string;
productId: string;
variantId?: string;
}

onPrimaryAction in Edit

const onPrimaryAction = useCallback(async () => {
// Get a fresh session token before every request to your app server.
const token = await getSessionToken();
// The product ID and variant ID collected from the modal form and the selling plan group ID
let payload = {
sellingPlanGroupId: data.sellingPlanGroupId,
productId: data.productId,
variantId: data.variantId,
};

// Here, send the form data to your app server to add the product to an existing plan.
const response = await fetch('https://server-url-here', {
headers: {
'any-header-key': token || 'unknown token',
},
body: JSON.stringify(payload)
});
// If the server responds with an OK status, then refresh the UI and close the modal
if (response.ok) {
done();
} else {
console.log('Handle error.');
}
close();
}, [getSessionToken, done, close]);

Anchor to Remove an existing purchase option from a product or variantRemove an existing purchase option from a product or variant

The Remove mode enables users to remove a product's purchase option. The Remove plan UI should display the plan and product titles. The Remove mode triggers the app modal container.

  • If the purchase option is associated at the product level (sellingPlanGroup.appliesToProduct is true), then the request to your backend server triggers the sellingPlanGroupRemoveProducts mutation.
  • If the purchase option is associated at the variant level (sellingPlanGroup.appliesToProductVariants is true), then the request to your backend server triggers the sellingPlanGroupRemoveProductVariants mutation.
  1. In the payload, include the productId, variantId, variantIds and the sellingPlanGroupId.
  2. In the header, include the session token. If the response returns an OK status, then you can request done to re-render the modal and close to close it.

Input

interface RemovePayload {
sellingPlanGroupId: string;
productId: string;
variantId?: string;
variantIds: string[];
}

primaryAction in Remove

setPrimaryAction({
content: 'Add to plan',
onAction: async () => {
// Get a fresh session token before every request to your app server.
const token = await getSessionToken();

// The product ID, variant ID, variant IDs, and the selling plan group ID
let payload = {
sellingPlanGroupId: data.sellingPlanGroupId,
productId: data.productId,
variantId: data.variantId,
variantIds: data.variantIds,
};

// Send the form data to your app server to add the product to an existing plan.
const response = await fetch('https://server-url-here', {
headers: {
'any-header-key': token || 'unknown token',
},
body: JSON.stringify(payload)
});

// If the server responds with an OK status, then refresh the UI and close the modal
if (response.ok) {
done();
} else {
console.log('Handle error.');
}

close();
},
});

Anchor to Step 2: Set up unit testingStep 2: Set up unit testing

To thoroughly test your extension, we recommend that you set up unit testing. You can use a testing framework that best suits your needs.



Was this page helpful?