# Calling and extending the Business Central API v2.0

> Source: https://netray.co/erp-help/dynamics-business-central-api-v2-how-to
> Publisher: Netray (netray.co), AI and integration engineering for ERP and manufacturing systems.
> Section: ERP Help

## Short answer

The Business Central API v2.0 is a REST/OData endpoint at api.businesscentral.dynamics.com/v2.0/{tenant}/{environment}/api/v2.0, authenticated with Azure AD OAuth 2.0. It exposes standard entities like customers and items, and lets you publish your own with an AL API page.

## Kind

how-to

## System

dynamics

## Erp

Microsoft Dynamics 365 Business Central

## Module

API v2.0 / integration

## Query

how to call Business Central API v2.0 with OAuth

## Alternate Queries

- business central api v2
- Business Central REST API v2.0 tutorial
- how to create custom API page in Business Central
- BC API v2.0 authentication setup

## Applies To

Dynamics 365 Business Central (SaaS and on-premises with API access enabled), API v2.0.

## Steps

### Authenticate and call the API

**Items:**

In Azure AD (Entra ID), register an app, grant it the Dynamics 365 Business Central API permission (Automation.ReadWrite.All or a narrower delegated/application scope), and generate a client secret or certificate.

In Business Central, open the Microsoft Entra Applications page and register the same client ID with the permission set needed (D365 BUS FULL ACCESS or a custom set scoped down for the integration).

Acquire an OAuth token from https://login.microsoftonline.com/{tenant}/oauth2/v2.0/token using client credentials (app-to-app) or the authorization code flow (user context), requesting scope https://api.businesscentral.dynamics.com/.default.

Call GET https://api.businesscentral.dynamics.com/v2.0/{tenant}/{environment}/api/v2.0/companies to retrieve the company id GUID you need for company-scoped calls.

Query a standard entity, e.g. GET .../companies({id})/customers, and use OData query options ($filter, $select, $expand, $top) to shape the response.

For writes, POST/PATCH with the If-Match header (ETag from a prior GET) on updates to satisfy Business Central's optimistic concurrency control.

To expose custom data, create an AL page of type API with ApplicationArea, APIPublisher, APIGroup, APIVersion, EntityName and EntitySetName properties, publish the extension, and it appears automatically under the custom API path.

## Sections

### v1.0 versus v2.0 and custom API versions

**Body:**

v2.0 is the current general-availability surface and is what Microsoft recommends for new integrations; v1.0 remains available mainly for backward compatibility. Both sit alongside any custom API pages you publish, which get their own version segment (e.g. v1.0, v2.0, or a custom string) under APIPublisher/APIGroup rather than Microsoft's.

Custom API pages are reached at a different URL segment than the standard Microsoft entities: .../api/{publisher}/{group}/{version}/companies({id})/{entitySetName}, which keeps custom extensions from colliding with Microsoft's own evolving standard API surface.

### Concurrency, ETags, and PATCH failures

**Body:**

Business Central enforces optimistic concurrency: every record returned carries an @odata.etag value, and a PATCH or DELETE must send it back in an If-Match header. Omitting it, or sending a stale value after another process updated the record, returns a 412 Precondition Failed.

For high-volume integrations, re-GET the record immediately before a retry rather than caching ETags for long periods - Business Central records change frequently from posting routines, jobs, and user edits.

### Choosing between standard entities, $expand, and $batch

**Body:**

Standard entities cover the common master data and transactional objects (customers, items, sales orders, journals) but not every table; anything not exposed needs a custom API page or the older SOAP/OData v4 web service pattern.

$expand lets you retrieve a header and its lines in one call (e.g. salesOrders with $expand=salesOrderLines) which is usually cheaper than separate round trips; for bulk operations across many records, use the $batch endpoint to combine multiple requests into a single HTTP call and reduce throttling exposure.

## Pitfalls

Requesting the wrong OAuth scope (a generic Graph scope instead of the Business Central resource) and getting 401 errors that look like a permissions problem but are actually a token audience mismatch.

Forgetting to also register the app inside Business Central's Microsoft Entra Applications page - Azure AD registration alone is not sufficient.

Sending PATCH/DELETE without an If-Match header and hitting unnecessary 412 errors, or worse, using If-Match: * which bypasses the concurrency check entirely.

Assuming a table exists as a standard API entity when it does not - check the API entity list or build a custom API page rather than guessing endpoint names.

Hardcoding a company id instead of resolving it per environment, which breaks the integration the moment it is deployed to a sandbox or a different tenant.

## Ai Angle

ERPray, connected read-only to a Business Central environment via the API, can answer questions like which sales orders are missing a shipment date or summarize open customer balances without a developer writing OData filters by hand, and can point to the exact standard entity or custom API page a given integration should target.

## Faq

### Do I need a Business Central developer license to call the API?

**Answer:** No - calling the API only needs an appropriate Business Central user/permission license and an Azure AD app registration. A developer license is only needed to build and publish custom AL extensions such as custom API pages.

### Why does my API call return an empty companies list?

**Answer:** The token's audience or tenant is wrong, or the app has not been granted access within Business Central's own Microsoft Entra Applications setup even though Azure AD shows the permission granted - both sides need to match.

### What is the difference between application and delegated permissions here?

**Answer:** Application permissions let a background service call the API as itself (client credentials flow, no signed-in user); delegated permissions call on behalf of a signed-in Business Central user and respect that user's own record-level permissions.

### Can I get webhooks instead of polling?

**Answer:** Yes - Business Central supports the standard OData webhook subscription mechanism (POST to a notificationUrl-bearing subscription resource), which is generally preferable to polling for near-real-time integrations.

## Search terms

Business Central API v2.0, BC OAuth 2.0 setup, Business Central REST API tutorial, custom API page AL Business Central, Business Central ETag PATCH, Business Central Entra app registration, BC API endpoint structure, Business Central $expand $batch

---
Talk to an engineer: https://netray.co/contact?intent=erp_ai | Machine catalog: https://netray.co/agent/catalog.json
