DEV Community

guardlabs_team
guardlabs_team

Posted on • Originally published at guardlabs.online

Integrating Shopify with a CRM via API: Orders and Customers Sync

Integrating Shopify with a CRM via API: Orders and Customers Sync

To sync customers and orders from Shopify to a CRM (such as HubSpot, Salesforce, or Zoho) without relying on third-party middleware, you must build a custom integration. This guide outlines how to configure Shopify API credentials, set up secure real-time webhooks, and process payloads to sync data to your CRM.

Step 1: Generate Shopify API Credentials

To read data from Shopify, you need an Admin API Access Token from a custom app inside your Shopify admin panel.

  • Navigate to Settings > Apps and sales channels > Develop apps.
  • Click Create an app and name it (e.g., "CRM Integration").
  • Under Configuration, select Admin API integration.
  • Enable the following API scopes:

    read_customers / write_customers

    • read_orders / write_orders
  • Click Save and then Install App.

  • Copy the Admin API access token. Store it securely; you can only view it once.

Step 2: Choose Your Sync Architecture

There are two primary methods to fetch data from Shopify:

  • Polling (REST/GraphQL API): Querying Shopify's endpoints (e.g., /admin/api/2024-01/orders.json) at scheduled intervals. This is resource-heavy and introduces latency.
  • Webhooks (Recommended): Shopify pushes data to your server instantly when an event occurs. Use these topics for customer and order sync:

    customers/create and customers/update

    • orders/create and orders/updated

Step 3: Implement the Webhook Receiver

Your middleware server must expose an endpoint to receive Shopify's POST requests, verify the webhook's authenticity using the HMAC header, and map the payload to your CRM's API structure.

Below is a production-ready Node.js Express example demonstrating how to receive a Shopify order webhook, verify it, and forward the mapped data to a CRM:

const express = require('express');
const crypto = require('crypto');
const axios = require('axios');

const app = express();
app.use(express.json({
  verify: (req, res, buf) => { req.rawBody = buf; }
}));

const SHOPIFY_CLIENT_SECRET = process.env.SHOPIFY_CLIENT_SECRET;
const CRM_API_URL = 'https://api.yourcrm.com/v1';
const CRM_API_KEY = process.env.CRM_API_KEY;

// Verify webhook signature to ensure request came from Shopify
function verifyWebhook(req) {
  const hmacHeader = req.headers['x-shopify-hmac-sha256'];
  const hash = crypto
    .createHmac('sha256', SHOPIFY_CLIENT_SECRET)
    .update(req.rawBody, 'utf8')
    .digest('base64');
  return hash === hmacHeader;
}

app.post('/webhooks/shopify/orders', async (req, res) => {
  if (!verifyWebhook(req)) {
    return res.status(401).send('Unauthorized: HMAC verification failed');
  }

  const order = req.body;

  // Map Shopify Order Schema to CRM Schema
  const crmPayload = {
    external_deal_id: order.id.toString(),
    deal_name: `Shopify Order #${order.order_number}`,
    amount: parseFloat(order.total_price),
    customer_email: order.email,
    customer_first_name: order.customer?.first_name || '',
    customer_last_name: order.customer?.last_name || '',
    created_at: order.created_at
  };

  try {
    // Upsert customer in CRM, then link the order/deal
    await axios.post(`${CRM_API_URL}/contacts/upsert`, {
      email: crmPayload.customer_email,
      first_name: crmPayload.customer_first_name,
      last_name: crmPayload.customer_last_name
    }, {
      headers: { 'Authorization': `Bearer ${CRM_API_KEY}` }
    });

    await axios.post(`${CRM_API_URL}/deals`, crmPayload, {
      headers: { 'Authorization': `Bearer ${CRM_API_KEY}` }
    });

    res.status(200).send('Webhook successfully processed');
  } catch (error) {
    console.error('CRM Sync Error:', error.response?.data || error.message);
    res.status(500).send('Internal Server Error');
  }
});

app.listen(3000, () => console.log('Webhook receiver running on port 3000'));

Enter fullscreen mode Exit fullscreen mode

Step 4: Handle Rate Limits and Idempotency

When syncing high volumes of data, you must account for API rate limits on both sides:

  • Shopify Rate Limits: The REST Admin API is limited to 40 requests per second per app (replenished at 2 requests/sec). GraphQL uses a point-based bucket system. Implement a retry mechanism with exponential backoff when encountering 429 Too Many Requests.
  • CRM Rate Limits: If your CRM limits concurrent API requests, use a message queue (e.g., Redis with BullMQ or RabbitMQ) to buffer incoming Shopify webhooks and process them sequentially.
  • Idempotency: Shopify webhooks guarantee "at-least-once" delivery. Your server may receive the same event twice. Always use Shopify's unique order.id or customer.id as an external key in your CRM to prevent duplicate record creation.

Need this done fast? order an integration on Kwork (https://kwork.com/scripting/52991008/integrate-your-services-api-webhooks-crm-and-payments).

Top comments (0)