> ## Documentation Index
> Fetch the complete documentation index at: https://docs.coreflux.org/llms.txt
> Use this file to discover all available pages before exploring further.

# Dynamics 365 Business Central

> Client-mode REST API connector for a curated Business Central API v2.0 slice: items, journalLines, salesOrders, and webhook subscriptions on items

Technical Preview

## Overview

A client-mode connector for a **curated inventory / sales / webhook** slice of [Business Central Standard API v2.0](https://learn.microsoft.com/en-us/dynamics365/business-central/dev-itpro/webservices/api-endpoint-structure) under `https://api.businesscentral.dynamics.com/v2.0/{tenant}/{env}/api/v2.0/`:

| Catalog connector event | Entity / path | Notes |
| - | - | - |
| GET items | `companies({companyId})/items` | Items; supports `$filter`, `$select`, `$top` |
| POST itemLedgerEntries via journals | `companies({companyId})/journals({journalId})/journalLines` | Standard writable journal path (G/L or Bank). `itemLedgerEntries` are **GET-only**; inventory Item Journal → custom API |
| GET salesOrders | `companies({companyId})/salesOrders` | Sales order headers; optional `$expand=salesOrderLines` |
| subscribe webhook on items | `subscriptions` | POST with `resource` = `/api/v2.0/companies({id})/items`; handshake required |

`BASE_ADDRESS` is the Standard API root (no trailing slash in the template). Topics use `erp/dynamics365-bc/<object>/<verb>`.

> [!NOTE]
>
> This is **Business Central** cloud API v2.0, not Dataverse and not Finance & Operations. For CRM/Dataverse Web API see [Dynamics 365 (Dataverse)](/latest/lot-language/routes/rest-api-apps/dynamics365). For F\&O OData see [Dynamics 365 Finance and Supply Chain](/latest/lot-language/routes/rest-api-apps/dynamics365-fscm).

> [!NOTE]
>
> Business Central API v2.0 requires a real tenant + environment, a company GUID, and an Entra ID OAuth 2.0 Bearer token. This template has not been verified against a live tenant. Prefer Hub secrets for tokens. Discover companies with `GET .../api/v2.0/companies`.

## Basic Syntax

```lot wrap theme={"theme":"css-variables","languages":{"custom":["/languages/lot.json"]}}
# Coreflux REST_API template — Microsoft Dynamics 365 Business Central (API v2.0 slice)
# Auth: Bearer {value.json.access_token} (Entra ID)
# BASE_ADDRESS: https://api.businesscentral.dynamics.com/v2.0/YOUR_TENANT/YOUR_ENV/api/v2.0

DEFINE ROUTE Dynamics365BcRestApi WITH TYPE REST_API
    ADD REST_API_CONFIG
        WITH BASE_ADDRESS "https://api.businesscentral.dynamics.com/v2.0/YOUR_TENANT/YOUR_ENV/api/v2.0"
        WITH ENABLE_CLIENT "true"
        WITH USE_SSL "true"
        WITH REQUEST_TIMEOUT '60'
        WITH DEFAULT_CONTENT_TYPE "application/json"
    ADD EVENT Getitems
        WITH SOURCE_TOPIC "erp/dynamics365-bc/items/get"
        WITH DESTINATION_TOPIC "erp/dynamics365-bc/items/get/response"
        WITH METHOD "GET"
        WITH ENDPOINT "/companies({value.json.companyId})/items?$top={value.json.top}&$filter={value.json.filter}&$select={value.json.select}"
        WITH HEADERS
            ADD "Accept" "application/json"
            ADD "OData-MaxVersion" "4.0"
            ADD "OData-Version" "4.0"
            ADD "Authorization" "Bearer {value.json.access_token}"
    ADD EVENT Createjournallines
        WITH SOURCE_TOPIC "erp/dynamics365-bc/journal-lines/create"
        WITH DESTINATION_TOPIC "erp/dynamics365-bc/journal-lines/create/response"
        WITH METHOD "POST"
        WITH ENDPOINT "/companies({value.json.companyId})/journals({value.json.journalId})/journalLines"
        WITH HEADERS
            ADD "Accept" "application/json"
            ADD "Content-Type" "application/json"
            ADD "OData-MaxVersion" "4.0"
            ADD "OData-Version" "4.0"
            ADD "Authorization" "Bearer {value.json.access_token}"
        WITH BODY "{payload}"
    ADD EVENT Getsalesorders
        WITH SOURCE_TOPIC "erp/dynamics365-bc/sales-orders/get"
        WITH DESTINATION_TOPIC "erp/dynamics365-bc/sales-orders/get/response"
        WITH METHOD "GET"
        WITH ENDPOINT "/companies({value.json.companyId})/salesOrders?$top={value.json.top}&$filter={value.json.filter}&$select={value.json.select}"
        WITH HEADERS
            ADD "Accept" "application/json"
            ADD "OData-MaxVersion" "4.0"
            ADD "OData-Version" "4.0"
            ADD "Authorization" "Bearer {value.json.access_token}"
    ADD EVENT Createsubscription
        WITH SOURCE_TOPIC "erp/dynamics365-bc/subscriptions/create"
        WITH DESTINATION_TOPIC "erp/dynamics365-bc/subscriptions/create/response"
        WITH METHOD "POST"
        WITH ENDPOINT "/subscriptions"
        WITH HEADERS
            ADD "Accept" "application/json"
            ADD "Content-Type" "application/json"
            ADD "OData-MaxVersion" "4.0"
            ADD "OData-Version" "4.0"
            ADD "Authorization" "Bearer {value.json.access_token}"
        WITH BODY "{payload}"

```

## Events

| Event | Method | Endpoint | Request topic | Response topic |
| - | - | - | - | - |
| Getitems | GET | `/companies({companyId})/items` | `erp/dynamics365-bc/items/get` | `erp/dynamics365-bc/items/get/response` |
| Createjournallines | POST | `/companies({companyId})/journals({journalId})/journalLines` | `erp/dynamics365-bc/journal-lines/create` | `erp/dynamics365-bc/journal-lines/create/response` |
| Getsalesorders | GET | `/companies({companyId})/salesOrders` | `erp/dynamics365-bc/sales-orders/get` | `erp/dynamics365-bc/sales-orders/get/response` |
| Createsubscription | POST | `/subscriptions` | `erp/dynamics365-bc/subscriptions/create` | `erp/dynamics365-bc/subscriptions/create/response` |

## Auth

**OAuth 2.0 (Entra ID) — default in the template:**

1. Register an app in Microsoft Entra ID; create a client secret; grant Dynamics 365 Business Central API permissions (e.g. `API.ReadWrite.All`).
2. In Business Central: **Azure Active Directory Applications** (Microsoft Entra Applications) — add the client ID and assign permission sets.
3. Request a token (client credentials example):

```http theme={"theme":"css-variables","languages":{"custom":["/languages/lot.json"]}}
POST https://login.microsoftonline.com/{tenant}/oauth2/v2.0/token
Content-Type: application/x-www-form-urlencoded

grant_type=client_credentials&client_id={clientId}&client_secret={secret}&scope=https://api.businesscentral.dynamics.com/.default
```

Delegated / authorization-code flows also work when your BC setup requires a licensed user context.

4. Pass the access token and company GUID on the MQTT request payload:

```json theme={"theme":"css-variables","languages":{"custom":["/languages/lot.json"]}}
{"access_token": "YOUR_ENTRA_ACCESS_TOKEN", "companyId": "YOUR_COMPANY_GUID", "top": "10", "filter": "number eq '1896-S'", "select": "id,number,displayName,inventory,unitPrice"}
```

The connector sends `Authorization: Bearer {value.json.access_token}`. Prefer Hub secrets / `GET SECRET`. Never commit real tokens.

## Companies and OData

Resolve `companyId` with `GET https://api.businesscentral.dynamics.com/v2.0/{tenant}/{env}/api/v2.0/companies`. All company-scoped entities nest under `companies({id})/...`. Send OData headers `Accept: application/json`, `OData-Version: 4.0`, `OData-MaxVersion: 4.0`.

## Item ledger vs journals

[itemLedgerEntry](https://learn.microsoft.com/en-us/dynamics365/business-central/dev-itpro/api-reference/v2.0/resources/dynamics_itemledgerentry) supports **GET only**. Catalog “POST itemLedgerEntries via journals” maps to the standard API writable journal path [`journalLines`](https://learn.microsoft.com/en-us/dynamics365/business-central/dev-itpro/api-reference/v2.0/api/dynamics_journalline_create) (G/L or Bank). Inventory quantity adjustments that create item ledger entries need a **custom Item Journal API** in AL.

## Webhooks

[Working with webhooks](https://learn.microsoft.com/en-us/dynamics365/business-central/dev-itpro/api-reference/v2.0/dynamics-subscriptions): `items` is a supported entity. Example subscription body:

```json theme={"theme":"css-variables","languages":{"custom":["/languages/lot.json"]}}
{
  "notificationUrl": "https://YOUR_PUBLIC_HTTPS_ENDPOINT/bc-webhook",
  "resource": "/api/v2.0/companies(YOUR_COMPANY_GUID)/items",
  "clientState": "optionalSharedSecret"
}
```

Handshake is mandatory: BC GETs `notificationUrl?validationToken=...` and expects the token in the 200 response body. Renew with `PATCH /subscriptions({id})` before expiry (\~3 days).

## Deploy

1. Copy `Dynamics365BcRestApi.lot` (no `ADD METADATA`).
2. Replace `YOUR_TENANT` and `YOUR_ENV` in `BASE_ADDRESS`.
3. `-addRoute` on the broker (or Hub deploy).
4. Publish JSON to a request topic; subscribe to the matching `/response` topic.

Hub catalog metadata (icon, description, `STATUS "beta"`) is in `hub-metadata.lot` for Hub / `-listTemplates` only.

## Status

**Blocked** until a live authenticated call succeeds (factory has no BC tenant/env or Entra credentials). Unblock with lab tenant + environment + company GUID + client-credentials (or delegated) token, then smoke `GET /companies({id})/items?$top=1` expecting HTTP 200.

## References

* [API endpoint structure — Business Central](https://learn.microsoft.com/en-us/dynamics365/business-central/dev-itpro/webservices/api-endpoint-structure)
* [item resource type](https://learn.microsoft.com/en-us/dynamics365/business-central/dev-itpro/api-reference/v2.0/resources/dynamics_item)
* [salesOrder resource type](https://learn.microsoft.com/en-us/dynamics365/business-central/dev-itpro/api-reference/v2.0/resources/dynamics_salesorder)
* [Create journalLines](https://learn.microsoft.com/en-us/dynamics365/business-central/dev-itpro/api-reference/v2.0/api/dynamics_journalline_create)
* [Working with webhooks](https://learn.microsoft.com/en-us/dynamics365/business-central/dev-itpro/api-reference/v2.0/dynamics-subscriptions)
* [REST API Connectors](/latest/lot-language/routes/rest-api-routes)


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.