npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@mipod/bigcommerce

v1.1.1

Published

Multi-tenant BigCommerce API client — connect multiple stores to a single Business Central environment

Readme

@mipod/bigcommerce

Multi-tenant BigCommerce API client for Node.js. Designed for connecting multiple BigCommerce stores to a single Business Central environment.

Installation

npm install @mipod/bigcommerce

Setup

Each store needs a store hash and access token from your BigCommerce API credentials. You can provide these via environment variables or register them at runtime.

Option 1 — Environment variables

Create a .env file (use .env.example as a template). Any <CODE>_BIGCOMMERCE_STORE_HASH / <CODE>_BIGCOMMERCE_CLIENT_ACCESS_TOKEN pair is auto-loaded at startup.

B2B_BIGCOMMERCE_STORE_HASH=your_store_hash
B2B_BIGCOMMERCE_CLIENT_ACCESS_TOKEN=your_access_token

B2C_BIGCOMMERCE_STORE_HASH=your_store_hash
B2C_BIGCOMMERCE_CLIENT_ACCESS_TOKEN=your_access_token

Option 2 — Programmatic registration

Register stores directly in code — useful when credentials come from a database or secret manager.

const bc = require('@mipod/bigcommerce');

bc.registerStore('B2B', { storeHash: 'abc123', accessToken: 'xyz' });
bc.registerStore('B2C', { storeHash: 'def456', accessToken: 'uvw' });

You can mix both options. Programmatic registration takes effect immediately and overrides any env-var entry with the same code.


Required API Permissions

When creating an API account in BigCommerce (Settings → API Accounts → Create API Account), configure the following OAuth scopes. Use read-only if your integration only reads data; use modify if it also writes (create/update/delete).

| Scope | Level needed | Covers | |---|---|---| | Products | read-only / modify | products, variants, brands, categories, productOptions, images, priceLists | | Customers | read-only / modify | customers, customerGroups | | Orders | read-only / modify | orders, shipments | | Store Locations | read-only | inventory.getLocations() | | Store Inventory | read-only / modify | inventory.getItems(), inventory.setAbsolute(), inventory.adjustRelative() | | Information & settings | read-only / modify | shipping (zones and methods) | | Metafields Access | Standard or full | metafieldsStandard covers app-owned namespaces; full covers all namespaces including those created by other apps |

Webhooks do not have a dedicated scope. Webhook management works with any valid API account. Webhooks will only deliver events for resources covered by your account's other scopes.

Recommended setup for a full Business Central integration

| Scope | Level | |---|---| | Products | modify | | Customers | modify | | Orders | modify | | Store Locations | read-only | | Store Inventory | modify | | Information & settings | modify | | Metafields Access | full |

You need one API account per store. Each account generates its own store hash + access token pair, which maps to a single registerStore() call.


Usage

Every method takes a store code as its first argument. This is the key used when registering the store ('B2B', 'B2C', etc.).

const bc = require('@mipod/bigcommerce');

const { data } = await bc.products.getList('B2B', { limit: 50 });
const { data } = await bc.orders.getList('B2C', { status_id: 11 });

API Reference

bc.registerStore(code, { storeHash, accessToken })

Register a store at runtime. code is case-insensitive.

bc.registerStore('WHOLESALE', { storeHash: 'abc123', accessToken: 'your_access_token' });

Products — bc.products

const { data } = await bc.products.getList('B2B', { limit: 50, page: 1 });
const { data } = await bc.products.getOne('B2B', 42);
const { data } = await bc.products.create('B2B', {
  name: 'My Product',
  type: 'physical',
  price: 19.99,
  weight: 1,
});
const { data } = await bc.products.update('B2B', 42, { price: 24.99 });
await bc.products.remove('B2B', 42);

Variants — bc.variants

// Variants for a specific product
const { data } = await bc.variants.getList('B2B', productId);
const { data } = await bc.variants.getOne('B2B', productId, variantId);
const { data } = await bc.variants.create('B2B', productId, {
  sku: 'SKU-RED-LG',
  option_values: [{ option_display_name: 'Color', label: 'Red' }],
});
const { data } = await bc.variants.update('B2B', productId, variantId, { price: 29.99 });
await bc.variants.remove('B2B', productId, variantId);

// All variants across all products — useful for bulk inventory sync
const { data } = await bc.variants.listAll('B2B', { sku: 'SKU-001' });

Product Options — bc.productOptions

Options produce variants (e.g. Size, Color). Modifiers don't (e.g. text engraving, gift wrap).

// Options
const { data } = await bc.productOptions.getOptions('B2B', productId);
const { data } = await bc.productOptions.createOption('B2B', productId, {
  display_name: 'Size',
  type: 'rectangles',
  option_values: [{ label: 'S' }, { label: 'M' }, { label: 'L' }],
});
await bc.productOptions.updateOption('B2B', productId, optionId, { display_name: 'Size (US)' });
await bc.productOptions.removeOption('B2B', productId, optionId);

// Option values
const { data } = await bc.productOptions.getOptionValues('B2B', productId, optionId);
await bc.productOptions.createOptionValue('B2B', productId, optionId, { label: 'XL' });
await bc.productOptions.updateOptionValue('B2B', productId, optionId, valueId, { label: 'XL / Extra Large' });
await bc.productOptions.removeOptionValue('B2B', productId, optionId, valueId);

// Modifiers
const { data } = await bc.productOptions.getModifiers('B2B', productId);
await bc.productOptions.createModifier('B2B', productId, { display_name: 'Gift Message', type: 'text' });
await bc.productOptions.updateModifier('B2B', productId, modifierId, { required: true });
await bc.productOptions.removeModifier('B2B', productId, modifierId);

Orders — bc.orders

// List orders — supports BC filter params (status_id, min_date_created, customer_id, etc.)
const orders = await bc.orders.getList('B2B', { status_id: 11, limit: 50 });

const order = await bc.orders.getOne('B2B', orderId);

// Update order status (e.g. 2 = Pending, 10 = Awaiting Fulfillment, 11 = Awaiting Shipment)
await bc.orders.update('B2B', orderId, { status_id: 2 });

const products = await bc.orders.getProducts('B2B', orderId);
const addresses = await bc.orders.getShippingAddresses('B2B', orderId);
const statuses = await bc.orders.getStatuses('B2B');

Shipments — bc.shipments

const shipments = await bc.shipments.getList('B2B', orderId);
const shipment  = await bc.shipments.getOne('B2B', orderId, shipmentId);

// Create a shipment — marks the order as shipped and sends tracking to the customer
await bc.shipments.create('B2B', orderId, {
  tracking_number: '1Z999AA10123456784',
  shipping_provider: 'ups',
  order_address_id: addressId,
  items: [{ order_product_id: productId, quantity: 1 }],
});

await bc.shipments.update('B2B', orderId, shipmentId, { tracking_number: '9400111899223397910163' });
await bc.shipments.remove('B2B', orderId, shipmentId);

Price Lists — bc.priceLists

// Price list CRUD
const { data } = await bc.priceLists.getList('B2B');
const { data } = await bc.priceLists.create('B2B', { name: 'Wholesale Pricing', active: true });
await bc.priceLists.update('B2B', priceListId, { name: 'Wholesale Pricing 2025' });
await bc.priceLists.remove('B2B', priceListId);

// Records — the actual price overrides per SKU/currency
const { data } = await bc.priceLists.getRecords('B2B', priceListId, { sku: 'SKU-001' });
await bc.priceLists.upsertRecords('B2B', priceListId, [
  { sku: 'SKU-001', currency: 'USD', price: 14.99, sale_price: 12.99 },
  { sku: 'SKU-002', currency: 'USD', price: 29.99 },
]);
await bc.priceLists.deleteRecords('B2B', priceListId, { sku: 'SKU-001' });

// Assignments — link a price list to a customer group or channel
await bc.priceLists.upsertAssignments('B2B', [
  { price_list_id: priceListId, customer_group_id: groupId },
]);
const { data } = await bc.priceLists.getAssignments('B2B', { price_list_id: priceListId });
await bc.priceLists.deleteAssignments('B2B', { price_list_id: priceListId });

Metafields — bc.metafields

Store cross-system IDs (e.g. Business Central record IDs) on any BigCommerce entity without polluting core fields.

Supported resource types: products, variants, categories, brands, customers, orders, channels

// Store a Business Central ID on a product
await bc.metafields.create('B2B', 'products', productId, {
  key: 'bc_item_no',
  value: 'ITEM-001',
  namespace: 'business_central',
  permission_set: 'read',
});

// Read it back
const { data } = await bc.metafields.getList('B2B', 'products', productId, {
  namespace: 'business_central',
});

// Update or remove
await bc.metafields.update('B2B', 'products', productId, metafieldId, { value: 'ITEM-002' });
await bc.metafields.remove('B2B', 'products', productId, metafieldId);

// Works the same for any resource type
await bc.metafields.create('B2B', 'customers', customerId, {
  key: 'bc_customer_no',
  value: 'C-00042',
  namespace: 'business_central',
  permission_set: 'read',
});

await bc.metafields.create('B2B', 'orders', orderId, {
  key: 'bc_sales_order_no',
  value: 'SO-10001',
  namespace: 'business_central',
  permission_set: 'read',
});

Webhooks — bc.webhooks

const { data } = await bc.webhooks.getList('B2B');
const { data } = await bc.webhooks.getOne('B2B', hookId);

// Register a webhook — BC will POST to your endpoint when the event fires
await bc.webhooks.create('B2B', {
  scope: 'store/order/statusUpdated',
  destination: 'https://your-app.com/webhooks/bigcommerce',
  is_active: true,
  headers: { 'X-Custom-Auth': 'secret' },
});

await bc.webhooks.update('B2B', hookId, { is_active: false });
await bc.webhooks.remove('B2B', hookId);

Common webhook scopes:

  • store/order/created — new order placed
  • store/order/statusUpdated — order status changed
  • store/product/updated — product edited
  • store/inventory/updated — stock level changed

Shipping — bc.shipping

// Zones
const zones = await bc.shipping.getZones('B2B');
const zone  = await bc.shipping.getZone('B2B', zoneId);
await bc.shipping.createZone('B2B', { name: 'Continental US' });
await bc.shipping.updateZone('B2B', zoneId, { name: 'Lower 48' });
await bc.shipping.removeZone('B2B', zoneId);

// Methods per zone
const methods = await bc.shipping.getMethods('B2B', zoneId);
await bc.shipping.createMethod('B2B', zoneId, {
  name: 'Ground Shipping',
  type: 'perorder',
  settings: { rate: '9.99' },
  enabled: true,
});
await bc.shipping.updateMethod('B2B', zoneId, methodId, { enabled: false });
await bc.shipping.removeMethod('B2B', zoneId, methodId);

Brands — bc.brands

const { data } = await bc.brands.getList('B2B');
const { data } = await bc.brands.getOne('B2B', brandId);
await bc.brands.create('B2B', { name: 'Acme Co.' });
await bc.brands.update('B2B', brandId, { name: 'Acme Corp.' });
await bc.brands.remove('B2B', brandId);

Categories — bc.categories

const { data } = await bc.categories.getList('B2B');
const { data } = await bc.categories.getOne('B2B', categoryId);
await bc.categories.create('B2B', { name: 'Electronics', parent_id: 0 });
await bc.categories.update('B2B', categoryId, { name: 'Electronics & Gadgets' });
await bc.categories.remove('B2B', categoryId);

Customers — bc.customers

const { data } = await bc.customers.getList('B2C', { limit: 100 });
const { data } = await bc.customers.getOne('B2C', customerId);
await bc.customers.create('B2C', { first_name: 'Jane', last_name: 'Smith', email: '[email protected]' });
await bc.customers.update('B2C', customerId, { phone: '555-1234' });
await bc.customers.remove('B2C', customerId);

Customer Groups — bc.customerGroups

const groups  = await bc.customerGroups.getList('B2B');
await bc.customerGroups.create('B2B', {
  name: 'Wholesale',
  discount_rules: [{ type: 'all', method: 'percent', amount: '10.0000' }],
});
await bc.customerGroups.update('B2B', groupId, { name: 'Wholesale VIP' });
await bc.customerGroups.remove('B2B', groupId);

Images — bc.images

// Upload from a public URL (BC fetches and stores it)
await bc.images.uploadFromUrl('B2B', productId, {
  image_url: 'https://example.com/photo.jpg',
  is_thumbnail: true,
});

// Upload from buffer (use when source URLs may expire)
await bc.images.uploadFromBuffer('B2B', productId, 'https://example.com/photo.jpg', {
  is_thumbnail: true,
});

await bc.images.remove('B2B', productId, imageId);

Inventory — bc.inventory

const { data } = await bc.inventory.getLocations('B2B');
const { data } = await bc.inventory.getItems('B2B', { sku: 'SKU-001' });

// Set to exact quantity
await bc.inventory.setAbsolute('B2B', [{ sku: 'SKU-001', location_id: 1, quantity: 50 }]);

// Adjust by delta
await bc.inventory.adjustRelative('B2B', [{ sku: 'SKU-001', location_id: 1, quantity: -5 }]);

Multi-store example

const bc = require('@mipod/bigcommerce');

bc.registerStore('B2B', { storeHash: process.env.B2B_HASH, accessToken: process.env.B2B_TOKEN });
bc.registerStore('B2C', { storeHash: process.env.B2C_HASH, accessToken: process.env.B2C_TOKEN });

// Sync an order to Business Central, then stamp the BC sales order number back as a metafield
async function syncOrderToBC(site, orderId, bcSalesOrderNo) {
  const order = await bc.orders.getOne(site, orderId);
  const products = await bc.orders.getProducts(site, orderId);

  // ... send to Business Central ...

  await bc.metafields.create(site, 'orders', orderId, {
    key: 'bc_sales_order_no',
    value: bcSalesOrderNo,
    namespace: 'business_central',
    permission_set: 'read',
  });
}

// When Business Central ships, create the shipment in BigCommerce
async function fulfillOrder(site, orderId, addressId, items, trackingNumber) {
  await bc.shipments.create(site, orderId, {
    tracking_number: trackingNumber,
    shipping_provider: 'ups',
    order_address_id: addressId,
    items,
  });
  await bc.orders.update(site, orderId, { status_id: 2 }); // Shipped
}

// Sync inventory across both stores
async function syncInventory(sku, quantity) {
  await Promise.all([
    bc.inventory.setAbsolute('B2B', [{ sku, location_id: 1, quantity }]),
    bc.inventory.setAbsolute('B2C', [{ sku, location_id: 1, quantity }]),
  ]);
}

License

MIT