Sync Shopify Orders to Salesforce Opportunities with Opportunity Products

14 min setup
No coding required
Runs automatically

Streamline sales tracking by automatically sending Shopify orders to Salesforce as Opportunities with associated Opportunity Products. This MESA workflow template transfers order details to Salesforce whenever a new Shopify order is created, allowing you to monitor potential upsell opportunities without manual data entry. Before using this template, ensure you have set up the following templates: “Sync Shopify Customer to Salesforce Account” and “Sync Shopify Product to Salesforce Product and Pricebook Entry.”

Shopify logo icon
Order Created
Query Single Account
Custom: Get Order Variant IDs
Query Multiple Product
Mapping to Salesforce Create Opportunity
Create Opportunity
Custom: Append Salesforce Product ID to line items
Loop: Process Each Line Item
Mapping: Create Opportunity Product
salesforce logo icon
Create Opportunity Product

You're in good company

"MESA has been a game changer for us. And, if you ever get stuck, their support team is always super helpful."

  • Ico star
  • Ico star
  • Ico star
  • Ico star
  • Ico star
PetFriendly

"It's like Zapier but exactly designed for Shopify. I have been able to complete all the workflows that I've needed."

  • Ico star
  • Ico star
  • Ico star
  • Ico star
  • Ico star
Zailys

"The MESA team has been amazing at helping us set up our automations. We would highly recommend this app!"

  • Ico star
  • Ico star
  • Ico star
  • Ico star
  • Ico star
Rothy's

How it works

10 steps to start syncing Shopify orders to Salesforce opportunities

Shopify logo icon

Order Created

App connector: Shopify • Time to complete: 0 minutes (Auto-configured)
Why this matters: This trigger monitors your Shopify store for completed orders and kicks off the Salesforce sync workflow. Without this automation, your sales team would need to manually create opportunities in Salesforce for every ecommerce order, leading to incomplete pipeline data and reporting gaps.

When any order is created in Shopify—whether from your online store, draft orders converted to paid, or any other order source—this trigger captures the complete order details including customer ID, line items, pricing, discounts, and order notes. The trigger watches your store continuously and passes the order data to the next step immediately after the order is placed.

Query Single Account

App connector: Salesforce • Time to complete: 0 minutes (Auto-configured)
Why this matters: To create a Salesforce opportunity, you need to link it to the customer's Account record in Salesforce. This step searches Salesforce for the Account that matches the Shopify customer who placed the order, ensuring the opportunity gets associated with the correct company or person.

The step queries Salesforce's Account object searching for a record where the custom field "Shopify_Customer_ID__c" matches the customer ID from the Shopify order. This custom field gets populated by the dependency workflow that syncs Shopify customers to Salesforce Accounts. The query returns the Account ID and Name, which get used in the opportunity creation step to properly link the records. If no matching Account is found, this workflow will fail—which is why the customer sync dependency workflow must be running first.

Custom: Get Order Variant IDs

App connector: Code • Time to complete: 0 minutes (Auto-configured)
Why this matters: Salesforce needs to match each product in the order to its corresponding Product record in Salesforce. This custom code extracts all the variant IDs from the order line items and formats them for a Salesforce query, enabling bulk product lookup in the next step rather than querying one at a time.

The code iterates through all line items in the Shopify order, extracts each product variant ID, and creates a comma-separated list formatted for Salesforce's SQL-style query syntax. For example, if an order contains three products, this step outputs something like '123456789','987654321','456789123' which the next step uses in a WHERE clause to find all matching products in one query. Here's the code:

const Mesa = require('vendor/Mesa.js');

module.exports = new class {
  script = (payload, context) => {
    const lineItems = context.steps['shopify-order-created'].line_items;

    let variantIds = lineItems.map(lineItem => {
      return `'${lineItem.variant_id}'`;
    });

    payload.variant_ids = variantIds;
    payload.variant_ids_csv = variantIds.join();

    Mesa.output.next(payload);
  }
}

Query Multiple Product

App connector: Salesforce • Time to complete: 0 minutes (Auto-configured)
Why this matters: Before creating opportunity products, you need the Salesforce Product IDs that correspond to each item in the Shopify order. This step searches Salesforce for all products that match the variant IDs from the order, enabling proper linking of line items to the Salesforce product catalog.

The step queries Salesforce's Product2 object searching for records where the custom field "Shopify_Variant_Id__c" matches any of the variant IDs from Step 3. This custom field gets populated by the product sync dependency workflow. The query returns multiple Product records in one API call—one for each unique product in the order—including their Salesforce IDs and Shopify variant IDs. These IDs get used later to create OpportunityLineItem records that link products to the opportunity.

Mapping to Salesforce Create Opportunity

App connector: Transform • Time to complete: 5 minutes
Why this matters: Shopify order data has different field names and formats than Salesforce Opportunity fields. This transformation step maps Shopify order values to the correct Salesforce Opportunity fields, ensuring data lands in the right places when the opportunity is created.

The transform maps several key fields:

  • AccountId: Uses the Salesforce Account ID from Step 2 to link the opportunity
  • Amount: Uses the Shopify order total price
  • CloseDate: Uses the order creation date
  • Description: Uses the Shopify order notes
  • StageName: Hard-coded to "Closed Won" since the order already completed
  • Pricebook2Id: You must manually enter your Salesforce Price Book ID here (see configuration instructions below)
  • Name: Combines the Account name and Shopify order name (like "Acme Corp - #1234")

Critical Configuration: You must enter your Salesforce Price Book ID in the "Pricebook2Id" field. To find this: log into Salesforce, go to Price Books, click your desired price book, and copy the ID from the URL between r/ and /view. For example, in https://ab11.force.com/lightning/r/01s2E000002pddCQAQ/view, the ID is 01s2E000002pddCQAQ.

Create Opportunity

App connector: Salesforce • Time to complete: 0 minutes (Auto-configured)
Why this matters: This is where the Shopify order actually becomes a Salesforce opportunity. The step creates a new Opportunity record with all the mapped data from the previous step, making the ecommerce sale visible in your Salesforce sales pipeline and reporting.

The step sends a POST request to Salesforce's Opportunity API endpoint with the transformed data from Step 5. Salesforce creates a new Opportunity record linked to the customer's Account, sets the stage to "Closed Won," records the order total as the opportunity amount, and uses the order date as the close date. The newly created Opportunity ID gets returned and is used in subsequent steps to create the associated product line items.

Custom: Append Salesforce Product ID to line items

App connector: Code • Time to complete: 1 minute
Why this matters: To create opportunity products in the loop, each Shopify line item needs to know its corresponding Salesforce Product ID. This code matches each line item to the Salesforce products retrieved in Step 4 and appends the Salesforce Product ID to each line item for use in the loop.

The code takes the line items from the Shopify order and the Salesforce products from Step 4, then matches them by comparing Shopify variant IDs. For each line item, it finds the matching Salesforce product and adds a new field called "salesforce_product_id" to that line item. This enriched line item data gets passed to the loop so each iteration has both the Shopify product details and the Salesforce Product ID needed to create the OpportunityLineItem. Here's the code:

const Mesa = require('vendor/Mesa.js');

module.exports = new (class {
  script = (payload, context) => {
    const salesforceProducts =
      context.steps['salesforce-query-multiple-product'];

    let lineItems = context.steps['shopify-order-created'].line_items;

    lineItems.forEach((lineItem, key) => {
      let salesforceProduct = salesforceProducts.filter(
        product =>
        product.Shopify_Variant_ID__c == lineItem.variant_id
      );

      if (salesforceProduct && salesforceProduct.length > 0) {
        lineItems[key]['salesforce_product_id'] = salesforceProduct[0].Id;
      }
    });

    const newPayload = {};
    newPayload.line_items = lineItems;

    Mesa.output.next(newPayload);
  };
})();

Loop: Process Each Line Item

App connector: Loop • Time to complete: 0 minutes (Auto-configured)
Why this matters: Orders typically contain multiple products, and each product needs to become a separate OpportunityLineItem record in Salesforce. This loop processes one line item at a time, creating individual opportunity product records that show exactly what was purchased.

The loop iterates through all line items from Step 7 (which now include the Salesforce Product IDs), processing one product at a time through the remaining workflow steps. For example, if an order contains a t-shirt, a hat, and a mug, the loop runs three times—once for each item—creating three separate OpportunityLineItem records linked to the same Opportunity. This structure allows orders of any size to sync completely to Salesforce.

Mapping: Create Opportunity Product

App connector: Transform • Time to complete: 0 minutes (Auto-configured)
Why this matters: Each line item needs to be transformed into the format Salesforce expects for OpportunityLineItem records. This transformation maps Shopify line item data to Salesforce fields and includes custom logic to calculate discount percentages, ensuring accurate product-level data in your CRM.

The transform maps:

  • OpportunityId: Uses the Opportunity ID created in Step 6
  • UnitPrice: Uses the line item price from Shopify
  • Quantity: Uses the line item quantity
  • Product2Id: Uses the Salesforce Product ID appended in Step 7

Additionally, the custom transform code calculates discount percentages if any discounts were applied to the line item. It takes the discount amount, divides it by the total line item price (unit price × quantity), and converts it to a percentage. Here's the transform code:

const Mesa = require('vendor/Mesa.js');
const Transform = require('vendor/Transform.js');

module.exports = new class {
  script = (payload, context) => {
    const currentItem = context.steps.loop;

    const output = Transform.convert(context, payload);

    // Add discounts
    let totalDiscounts = parseFloat(currentItem.total_discount_set.shop_money.amount);

    if (currentItem.discount_allocations && currentItem.discount_allocations) {
      totalDiscounts = currentItem.discount_allocations.reduce((a, {amount}) => a + parseFloat(amount), 0);
    }

    if (totalDiscounts && totalDiscounts > 0) {
      // Get total price for line item (quantity * unit price, then divide by discount to get percentage)
      output['Discount'] = parseFloat(totalDiscounts / (output.UnitPrice * output.Quantity) * 100);
    }

    Mesa.output.next(output);
  }
}
salesforce logo icon

Create Opportunity Product

App connector: Salesforce • Time to complete: 0 minutes (Auto-configured)
Why this matters: This is where each line item actually becomes an OpportunityLineItem record in Salesforce. The step creates individual product records linked to the opportunity, giving your sales team complete visibility into what products were purchased, not just order totals.

The step sends a POST request to Salesforce's OpportunityLineItem API endpoint with the transformed data from Step 9. Salesforce creates a new OpportunityLineItem record for the current line item in the loop, linking it to the Opportunity created in Step 6 and the Product from your Salesforce catalog. This includes quantity, unit price, and any calculated discounts. The loop continues until all line items have been processed and added to the opportunity.

*Required: The following must be used with this workflow.

Ready to set this up? It only takes 14 minutes.

Our support team will even help you personalize this workflow for free.

Get started →

Make it your own!

Customize this workflow even further:

Add order tags as opportunity fields
After creating the opportunity, add a step to update custom Salesforce fields with Shopify order tags, enabling sales reporting segmented by fulfillment status, marketing campaigns, or customer segments tracked through your tagging system.
Sync order status changes back to Salesforce
Create a companion workflow that triggers when Shopify order status changes (fulfilled, cancelled, refunded) and updates the Salesforce Opportunity stage accordingly, keeping your sales pipeline accurate even when orders change after initial sync.
Route high-value opportunities to specific sales reps
Add a filter after opportunity creation that checks the Amount field, then uses Salesforce assignment rules or direct owner updates to automatically assign opportunities over a certain threshold to your senior account executives.
Include shipping and tax as separate line items
Modify the line item loop to add additional OpportunityLineItem records for shipping charges and tax amounts, giving finance teams complete revenue breakdown for reporting and commission calculations.

Common questions

What happens if a customer or product doesn't exist in Salesforce yet?

Can I modify the opportunity stage instead of always using "Closed Won"?

Will this create duplicate opportunities if I manually replay the workflow?

Ready to start syncing Shopify orders to Salesforce opportunities?

7-day free trial • 14 min setup • Cancel anytime

Need help? Our automation experts will help you personalize this workflow for free. Contact support