---
title: "Integrate Microsoft Dynamics 365 Business Central with Medusa"
description: "How to integrate Dynamics 365 Business Central with Medusa: API v2.0, webhooks, data mapping, rate limits, a code skeleton, and the Shopify Connector."
url: https://medusajs.com/kb/erp-integration/business-central
last_updated: 2026-10-29T06:55:50Z
topic: "erp-integration"
type: "concept"
applies_to: "Medusa v2.x"
related:
  - "https://medusajs.com/kb/erp-integration/ecommerce-erp-integration.md"
  - "https://medusajs.com/kb/erp-integration/netsuite.md"
  - "https://medusajs.com/kb/erp-integration/sap-business-one.md"
  - "https://medusajs.com/kb/erp-integration/odoo.md"
  - "https://medusajs.com/kb/b2b/b2b-customer-specific-pricing.md"
  - "https://medusajs.com/kb/b2b/shopify-b2b-alternatives.md"
sources:
  - "https://docs.medusajs.com/resources/recipes/erp"
  - "https://docs.medusajs.com/learn/fundamentals/modules"
  - "https://docs.medusajs.com/learn/fundamentals/events-and-subscribers"
  - "https://docs.medusajs.com/learn/fundamentals/workflows/compensation-function"
  - "https://docs.medusajs.com/learn/fundamentals/workflows/workflow-hooks"
  - "https://docs.medusajs.com/learn/fundamentals/scheduled-jobs"
  - "https://docs.medusajs.com/learn/fundamentals/workflows/retry-failed-steps"
  - "https://docs.medusajs.com/learn/fundamentals/workflows/long-running-workflow"
  - "https://docs.medusajs.com/resources/references/medusa-workflows/updateInventoryLevelsWorkflow"
  - "https://docs.medusajs.com/resources/references/medusa-workflows/createPriceListsWorkflow"
  - "https://docs.medusajs.com/resources/commerce-modules/pricing/price-rules"
  - "https://docs.medusajs.com/resources/examples/guides/custom-item-price"
  - "https://docs.medusajs.com/resources/integrations"
  - "https://medusajs.com/pricing"
  - "https://learn.microsoft.com/en-us/dynamics365/business-central/dev-itpro/api-reference/v2.0/"
  - "https://learn.microsoft.com/en-us/dynamics365/business-central/dev-itpro/api-reference/v2.0/dynamics-subscriptions"
  - "https://learn.microsoft.com/en-us/dynamics365/business-central/dev-itpro/api-reference/v2.0/api/dynamics_subscriptions_create"
  - "https://learn.microsoft.com/en-us/dynamics365/business-central/dev-itpro/administration/operational-limits-online"
  - "https://learn.microsoft.com/en-us/dynamics365/business-central/dev-itpro/api-reference/v2.0/resources/dynamics_item"
  - "https://learn.microsoft.com/en-us/dynamics365/business-central/dev-itpro/api-reference/v2.0/resources/dynamics_salesorder"
  - "https://learn.microsoft.com/en-us/dynamics365/business-central/shopify/shopify-connector-overview"
  - "https://learn.microsoft.com/en-us/dynamics365/business-central/shopify/synchronize-orders"
  - "https://learn.microsoft.com/en-us/dynamics365/business-central/shopify/shopify-faq"
  - "https://shopify.dev/docs/api/functions/latest/cart-and-checkout-validation"
---

# Integrate Microsoft Dynamics 365 Business Central with Medusa

> Medusa has no first-party Business Central connector, so you build one as a custom Medusa module that calls the Business Central API v2.0. Orders push to Business Central sales orders from an order.placed subscriber with rollback, Business Central webhooks drive order status updates, and scheduled jobs sync stock and customer prices into Medusa.

## How a Business Central integration with Medusa works

Medusa has no first-party connector for Microsoft Dynamics 365 Business Central. You build the integration as a custom Medusa [module](https://docs.medusajs.com/learn/fundamentals/modules) that calls the [Business Central API v2.0](https://learn.microsoft.com/en-us/dynamics365/business-central/dev-itpro/api-reference/v2.0/), a REST API on OData v4. Workflows, subscribers, scheduled jobs and API routes then use that module, following Medusa's [ERP recipe](https://docs.medusajs.com/resources/recipes/erp).

Business Central pushes changes through [webhooks](https://learn.microsoft.com/en-us/dynamics365/business-central/dev-itpro/api-reference/v2.0/dynamics-subscriptions):

- You register with `POST /api/v2.0/subscriptions`, and your endpoint must echo the `validationToken` with a `200` response.
- Subscriptions expire after three days unless renewed with a `PATCH`.
- A notification carries the changed record's URL and a change type, not the record itself, so you `GET` the record afterwards.
- Supported entities include `items`, `customers`, `salesOrders` and `salesInvoices`. Item ledger entries, which hold stock movements, are not on the list.
- If more than 1,000 records change within 30 seconds, you get one `collection` notification with a filter instead of one per record.

## Mapping Business Central data to Medusa

Each Business Central entity maps to a Medusa commerce module. Statuses describe the Medusa side.

| Business Central | Medusa | Direction | Mechanism | Status |
| --- | --- | --- | --- | --- |
| items, itemVariants | Products and variants, with the BC ID in external_id or metadata | BC to Medusa | Scheduled job, plus items webhook | Official guide |
| item inventory (read-only field) | Inventory levels via updateInventoryLevelsWorkflow | BC to Medusa | Scheduled job, plus a live check at add-to-cart | Custom (scheduled sync); Official guide (live check at add-to-cart) |
| Customer price groups and price lists | Price lists with customer group rules | BC to Medusa | Scheduled job reading a custom BC API page | Custom |
| customers | Customers and customer groups | Both | Webhook in, subscriber out | Custom |
| salesOrders, salesOrderLines | Orders | Medusa to BC, status back | order.placed subscriber; salesOrders webhook | Official guide |

The standard API v2.0 has no price list or customer price group resource; items expose a single `unitPrice`. To sync customer-specific prices, publish a custom API page in AL. Custom API pages can also send webhooks if they meet Business Central's webhook requirements.

## Real-time or scheduled sync for each Business Central flow

Pick the trigger per flow, not per integration:

- **Orders:** real time. An `order.placed` subscriber runs a workflow that creates the BC sales order.
- **Order status:** real time. A `salesOrders` webhook calls a Medusa API route that fetches the order and updates Medusa. A scheduled job renews the subscription before its three days run out.
- **Stock:** scheduled, because stock movements don't fire webhooks. For exact stock, check BC in the `validate` hook of `addToCartWorkflow`.
- **Prices:** scheduled into Medusa price lists, or fetched per cart with a [custom item price](https://docs.medusajs.com/resources/examples/guides/custom-item-price) workflow.

Business Central online allows [6,000 OData requests per user](https://learn.microsoft.com/en-us/dynamics365/business-central/dev-itpro/administration/operational-limits-online) in a 5-minute window, 5 concurrent requests, and 100 operations per `$batch`. Above the limits it returns `429`. Set `maxRetries` and `retryInterval` on steps that call BC; a `retryInterval` makes the workflow [long-running](https://docs.medusajs.com/learn/fundamentals/workflows/long-running-workflow).

## Code skeleton: push a Medusa order to Business Central with rollback

This skeleton assumes a custom module registered as `bc` whose service wraps `salesOrders` create and delete calls. The compensation function deletes the BC sales order if the metadata update fails.

```ts
// src/workflows/sync-order-to-bc.ts
import { createStep, createWorkflow, StepResponse, WorkflowResponse } from "@medusajs/framework/workflows-sdk"
import { updateOrderWorkflow, useQueryGraphStep } from "@medusajs/medusa/core-flows"
import { OrderDTO } from "@medusajs/framework/types"

const createBcSalesOrderStep = createStep(
  { name: "create-bc-sales-order", maxRetries: 3 },
  async ({ order }: { order: OrderDTO }, { container }) => {
    const bcOrderId = await container.resolve("bc").createSalesOrder(order)
    return new StepResponse(bcOrderId, bcOrderId)
  },
  async (bcOrderId, { container }) => {
    if (!bcOrderId) return
    await container.resolve("bc").deleteSalesOrder(bcOrderId)
  }
)

export const syncOrderToBcWorkflow = createWorkflow(
  "sync-order-to-bc",
  ({ order_id }: { order_id: string }) => {
    const { data: orders } = useQueryGraphStep({
      entity: "order",
      fields: ["*", "items.*", "shipping_address.*", "billing_address.*"],
      filters: { id: order_id },
    })
    const bcOrderId = createBcSalesOrderStep({ order: orders[0] as unknown as OrderDTO })
    updateOrderWorkflow.runAsStep({
      input: { id: order_id, user_id: "", metadata: { bc_order_id: bcOrderId } },
    })
    return new WorkflowResponse(bcOrderId)
  }
)
```

```ts
// src/subscribers/order-placed-bc.ts
import type { SubscriberArgs, SubscriberConfig } from "@medusajs/framework"
import { syncOrderToBcWorkflow } from "../workflows/sync-order-to-bc"

export default async function orderPlacedBcHandler({ event: { data }, container }: SubscriberArgs<{ id: string }>) {
  await syncOrderToBcWorkflow(container).run({ input: { order_id: data.id } })
}

export const config: SubscriberConfig = { event: "order.placed" }
```

## Medusa compared with the Shopify Connector for Business Central

| Aspect | Shopify with Microsoft's Shopify Connector | Medusa with a custom Business Central module |
| --- | --- | --- |
| Who builds it | Microsoft. Preinstalled in new Business Central online environments | You or your agency |
| Deployment | Business Central online only, not on-premises | Any environment where the BC APIs are reachable |
| Sync trigger | Job queue; Auto Sync Orders starts the order import job when Shopify reports a new order | Medusa events, BC webhooks and scheduled jobs |
| Customer prices | Exports prices from selected customer price groups and discounts, plus B2B catalogs | Price lists with customer group rules, or a live BC price at add-to-cart |
| ERP rules in the cart | Shopify Functions; external fetch only for custom apps on Enterprise stores | validate hook calls BC directly |
| Upkeep | Microsoft adopts new Shopify API versions in Business Central major releases | You maintain the module as BC's API changes |
| Licenses | Business Central and Shopify | Business Central, plus Medusa hosting: self-hosted, or Medusa Cloud from $29 per month with a 0% GMV fee |

## When Medusa is not the right choice for Business Central

- You run Business Central online and Shopify, and the connector's syncs cover your order, stock and price flows. Use the connector.
- You have no developer capacity. A Medusa integration is code you own.
- You need a vendor-supported connector. Medusa has none for Business Central today.

## Common questions

### Is there a Medusa plugin for Business Central?

No. Medusa has no first-party or official plugin for Microsoft Dynamics 365 Business Central. You build the integration as a custom module following the Medusa ERP recipe.

### Does Business Central send webhooks for stock changes?

Not directly. Business Central webhooks cover entities such as items, customers and salesOrders, but item ledger entries, which record stock movements, are not webhook-supported. Sync stock on a schedule or check it live during add-to-cart.

### How do I sync Business Central customer prices to Medusa?

The standard Business Central API v2.0 has no price list resource, so publish a custom API page in AL that exposes price list lines. A Medusa scheduled job can then write them to price lists with customer group rules.

### What are the Business Central API rate limits?

Business Central online allows 6,000 OData requests per user in a 5-minute sliding window and 5 concurrent requests per user, and returns HTTP 429 when limits are exceeded. A $batch request holds up to 100 operations.

### Does the Shopify Connector work with Business Central on-premises?

No. Microsoft's Shopify Connector is available only for Business Central online. A Medusa integration calls the Business Central API, so it can target any environment where the APIs are enabled and reachable.

## Documentation

- [Integrate ERP with Medusa](https://docs.medusajs.com/resources/recipes/erp)
- [Modules](https://docs.medusajs.com/learn/fundamentals/modules)
- [Events and Subscribers](https://docs.medusajs.com/learn/fundamentals/events-and-subscribers)
- [Compensation Function](https://docs.medusajs.com/learn/fundamentals/workflows/compensation-function)
- [Scheduled Jobs](https://docs.medusajs.com/learn/fundamentals/scheduled-jobs)

## Related

- [Which ecommerce platform is easiest to integrate with an ERP?](https://medusajs.com/kb/erp-integration/ecommerce-erp-integration.md)
- [How to integrate NetSuite with Medusa](https://medusajs.com/kb/erp-integration/netsuite.md)
- [How to integrate SAP Business One with Medusa](https://medusajs.com/kb/erp-integration/sap-business-one.md)
- [How to integrate Odoo with Medusa](https://medusajs.com/kb/erp-integration/odoo.md)
- [How to build a B2B store with custom pricing per customer](https://medusajs.com/kb/b2b/b2b-customer-specific-pricing.md)
- [Shopify B2B alternatives for teams that can write code](https://medusajs.com/kb/b2b/shopify-b2b-alternatives.md)
