Building Custom REST API Connectors in Business Central: Exposing Data Securely for Third-Party Integrations and Mobile Apps

Building Custom REST API Connectors in Business Central: Exposing Data Securely for Third-Party Integrations and Mobile Apps

Business Central’s strength lies in its ability to integrate with modern cloud applications, but the real challenge emerges when you need to expose your financial and operational data through APIs that external systems and mobile clients can reliably consume. Out-of-the-box endpoints expose standard entities, but most integration scenarios demand custom data shapes, calculated fields, filtered subsets, or aggregate views tailored to specific business processes. Building these custom REST API connectors requires careful architectural decisions around authentication, data filtering, performance optimization, and monitoring, particularly in organizations handling high transaction volumes or supporting third-party mobile applications.

Understanding Business Central’s Native API Framework

Business Central exposes data through two primary API mechanisms: OData v4 endpoints for standard pages and tables, and the newer Pages API designed for application-level consumption. The Pages API builds on the modern AL language and provides a more controlled, versioned approach to data exposure than direct table access. Unlike Dynamics 365, which includes a unified Microsoft Dataverse layer, Business Central requires you to explicitly architect data exposure through custom API pages, which means your integration strategy must balance between leveraging the platform’s built-in capabilities and accepting responsibility for designing clean, maintainable contracts between Business Central and consuming systems.

The distinction matters operationally. Standard OData endpoints expose the database schema directly, which couples external consumers tightly to your internal data model. When you restructure a table or rename a field for internal reasons, external integrations break. Custom API pages decouple that contract, allowing you to evolve your internal schema independently from the promises you have made to external systems.

Designing Custom API Pages for External Consumption

Custom API pages in Business Central are AL procedures exposed through the REST endpoint /api/v2.0/companies({company-id})/custom-apis/. Define these using the Page object subtype, marking them as API and APIVersion to control versioning and backward compatibility. The page structure mirrors a standard page but operates as a service layer, processing inbound requests and returning structured JSON responses rather than rendering a user interface.

The design pattern establishes a clear separation: your custom page receives the incoming request, validates it, queries the underlying tables or reports with any necessary business logic, transforms the result into the contracted JSON shape, and returns it. This allows you to filter at the data layer, aggregate values, apply security row-level filters, and enforce business logic before data leaves the system. For example, a third-party field service application might request customer shipment history and location data. Rather than exposing raw table access, you create a custom API page that joins customer, sales order, and shipment tables, filters by the authenticated user’s assigned territory, calculates on-time delivery percentage, and returns only the fields the mobile app requires.

Authentication and authorization flow through the AL code itself. Within the API page, AL procedures can access the authenticated user’s context and apply permissions hierarchically. A request arriving with a specific OAuth token corresponds to a Business Central user; that user’s role, responsibility center assignments, and dimension filters determine what data the API returns. Building this filtering into the API page ensures that integrations consuming the endpoint respect your organization’s security model without requiring external filtering logic that might go stale or be misconfigured.

Authentication Strategies and Secure Data Exposure

Business Central supports OAuth 2.0 authentication via Azure AD, which securely delegates user identity without transmitting credentials directly to applications. For third-party integrations, you register the consuming application as an Azure AD client, establish trust with Business Central’s tenant, and issue tokens that grant scoped access. This pattern scales across internal applications, third-party SaaS vendors, and mobile apps developed for field teams.

For service-to-service integrations where no interactive user exists, you configure Azure AD application permissions and use the client credentials flow. The integrating service authenticates with its own client ID and secret, receives a token, and calls the API with that token’s authority. Business Central’s authorization layer validates the token and enforces whatever permissions the service principal has been granted, typically read-only access to specific entities for automation scenarios.

The critical security decision is scope: never grant an external service permission to the entire database. An automated reconciliation job needs specific journal entries and GL accounts, not access to vendor master records or payroll data. Implement this by controlling AL permissions at the table and field level within your custom API page. The code executes in a specific permission context; requests outside that context return 403 Forbidden before any data is retrieved.

Rate limiting prevents external integrations from accidentally or intentionally overwhelming Business Central with requests. Implement this at the API page level using a simple counter in a temporary table or in-memory structure, logging the authenticated user’s token, timestamp, and request count, then rejecting requests that exceed a threshold (for example, 100 requests per minute per token). This protects the system during integration testing when third-party code loops unexpectedly, or when a mobile app’s sync logic gets into a retry storm during network instability.

Common Integration Patterns and Implementation Considerations

Third-party integrations typically follow one of three patterns: read-heavy analytics flows that pull data into external dashboards or reporting systems, transaction-driven flows that insert or update Business Central records from external sources, and bidirectional syncs where data changes in either system trigger updates in the other.

For read-heavy scenarios, design your custom API to return data in a shape optimized for the consuming tool. A data warehouse pulling nightly sales history might request summarized daily shipment totals grouped by customer and region, not individual line items. An analytics platform might want both transaction details and aggregated metrics in a single response. Custom API pages let you compute these shapes once in Business Central and deliver them efficiently.

For transaction-driven inbound flows, implement idempotency. When a third-party order management system sends a new sales order to Business Central, include a unique idempotency key. The API page stores this key with the created record; if the same request arrives again due to a network retry, the API recognizes the duplicate and returns the existing record without creating a second one.

Bidirectional syncs require careful conflict resolution. If Business Central and an external inventory system both allow updates to stock levels, and both systems update the value simultaneously, which one wins? Document your conflict resolution policy explicitly: last-write-wins, field-level rules, or row-level versioning. Without explicit conflict resolution, silent data loss occurs.

Performance Optimization and Monitoring at Scale

As external integrations scale, API performance directly affects integration throughput and cost. A slowly responding API forces external systems to maintain more concurrent connections and retry more frequently. Optimize by indexing the tables you query most frequently within the custom API, filtering at the database layer rather than in application logic, and using efficient AL patterns.

Monitor API health using Application Insights or similar observability tools. Instrument your custom API page to log request count, response time, error rates, and authenticated users consuming high volumes. This visibility lets you spot performance degradation early and make data-driven decisions about whether to add rate limits, optimize queries, or provision additional capacity.

Establish a communication channel with integrating partners about expected availability, planned maintenance windows, and API contract changes. When you modify a custom API’s response shape, maintain backward compatibility by supporting both versions for a defined sunset period.

Conclusion

Secure, maintainable API integration in Business Central demands intentional architecture. Custom API pages decouple your internal data model from external contracts, authentication flows enforce security boundaries, and thoughtful rate limiting and monitoring protect system stability. Organizations that treat API design as a core platform responsibility, document integration contracts clearly, and actively monitor consuming applications’ health build integration ecosystems that scale with business growth rather than becoming bottlenecks during busy cycles.


Routeget Technologies has architected integration frameworks for mid-market and enterprise Business Central deployments, helping organizations balance the flexibility of third-party ecosystems with the security and governance demands of regulated industries. Custom API design, Azure AD federation, and integration monitoring are core areas of our Dynamics and Power Platform consulting practice.

#DynamicsIntegration #BusinessCentralAPI #RESTfulArchitecture #MicroservicesPatterns #CloudIntegration #DataSecurityGovernance #EnterpriseIntegration #APIDesignBestPractices

Business Central’s OData Deprecation Is the Deadline That Actually Matters

Solution architect reviewing integration and API connection status on a monitor, representing Business Central OData migration planning

Every Business Central partner with a client list has spent the last few months triaging one deadline: SOAP web services on Microsoft-authored pages stop working the moment version 29.0 goes generally available on October 1, 2026. It’s a real cutoff, it’s close, and it deserves the attention it’s getting. But teams that treat that project as the finish line are missing the bigger one sitting six months behind it. Business Central’s OData deprecation for Microsoft UI pages lands with version 30.0, the 2027 release wave 1 release scheduled for the first workday of April 2027, and it is going to break far more integrations than SOAP ever did, because OData has been the default, path-of-least-resistance protocol for Business Central reporting since NAV migrated to the cloud.

Here’s the scenario that shows up in almost every environment once you actually go looking: a controller built an Excel workbook years ago that pulls G/L entries through an OData feed on a standard Microsoft page. Nobody remembers who set it up. It isn’t in the integration inventory because nobody classified a spreadsheet as an integration. A Power BI dataset does the same thing against the Customer or Item Ledger Entry pages, refreshing nightly through a service account that predates the current IT team. None of this shows up when you audit “our integrations,” because the people who’d know to look for it moved on, and the connections themselves were never registered anywhere except a connection string buried in a Power Query step. SOAP, by contrast, was mostly used by a smaller set of legacy middleware tools that companies have already been migrating off for years because SOAP has felt dated since well before Microsoft announced its removal. OData never felt dated. It’s still the protocol Microsoft’s own documentation recommends for ad hoc reporting scenarios, right up until version 30 removes the ability to expose a Microsoft-authored page through it at all.

Solution architect reviewing integration and API connection status on a monitor, representing Business Central OData migration planning

What Business Central’s OData deprecation actually removes

The scope here matters, because it’s narrower than the headlines suggest and that narrowness is exactly what makes it easy to underestimate. Starting in version 30, Business Central will no longer allow a page published by a Microsoft-authored app, meaning the Base Application, System Application, or any other first-party extension, to be exposed as an OData endpoint. Custom pages you or a partner built in your own AL extension are unaffected. Standard API pages and API queries, which already use a different endpoint structure under /api/v2.0/, are unaffected. What goes away is specifically OData access to the UI pages Microsoft ships out of the box: the Customer Card, the Chart of Accounts, the Sales Order list, and every other page that a reporting tool or Excel workbook has been happily pointing at for a decade.

Microsoft’s stated rationale is worth understanding because it explains why there’s no reprieve coming. A UI page isn’t governed by the same change-management discipline as an API. Microsoft can add a field, reorder a FastTab, or rename a control on a standard page in a minor update without that counting as a breaking change to the platform, but if your OData integration depends on that page’s exact shape, the same update breaks your feed. Microsoft has effectively decided it can no longer support that implicit contract at scale, and the SOAP removal in version 29 was the first half of enforcing that decision. Version 30 finishes it for OData.

Finding what you don’t know is there

Before any migration plan makes sense, you need an honest inventory, and guessing from documentation or asking the client “what connects to BC” will undercount every time. Business Central’s telemetry to Application Insights already logs this if you have it wired up. Web service requests are recorded under event ID RT0008, and the category custom dimension on that event records whether each call came in as API, ODataV4, ODataV3, or SOAP. Paired with the alObjectName and endpoint dimensions, a straightforward Kusto query against your Application Insights workspace, filtering customDimensions.eventId == "RT0008" and grouping by category and object name, will produce a real list of which Microsoft pages are being called through OData, how often, and from what client. Run that query across a full month rather than a day or two; monthly reports and quarter-end reconciliation jobs won’t show up in a short window, and those are exactly the integrations most likely to have been forgotten.

Abstract illustration of a legacy data connection node fading out as a new API connection node forms, representing migration from OData to API v2.0

Triaging what the audit finds

Once you have the list, not every entry needs the same fix, and treating them uniformly wastes effort on the easy ones while under-resourcing the hard ones. Some OData calls map directly onto an existing standard API entity: Customer, Vendor, Item, and Sales Order OData feeds usually have a clean equivalent already published under API v2.0, and switching the connection string plus adjusting field names is genuinely a low-effort change. Others don’t have a standard API match because they’re pulling something specific, like a custom-shaped join across ledger entries and dimensions that a spreadsheet author built by hand in Power Query. For those, an AL query object is usually the right tool rather than trying to force a page-based API to do the work. Query objects are read-only, they can join across multiple tables the way the old OData feed effectively did through Power Query, and they publish as their own API endpoint with proper OData-style $filter and $select support, without exposing a Microsoft UI page at all. A third category is the genuinely awkward one: integrations built around unbound actions on standard pages, which as of now have no direct equivalent in the REST API surface. Microsoft hasn’t closed this gap yet, so the practical workaround is either wrapping the needed logic in a bound action on a custom API page you control, or moving that piece of orchestration out of Business Central entirely into an Azure Function or a Logic Apps flow that calls the standard API for the parts it can and handles the rest itself.

The option nobody should default to, but should know exists

If a specific OData integration truly cannot be replatformed before April 2027, Microsoft’s own guidance leaves one path open: copy the source code of the standard page into your own extension and publish that copy as the OData endpoint instead. This works because the restriction is specifically on pages published by a Microsoft-authored app, not on OData as a protocol. It should be treated as a last resort rather than a template, though, because it means you now own maintaining a forked copy of a Microsoft page indefinitely, including replicating any future field or logic changes Microsoft makes to the original. For a page that rarely changes, that’s a manageable trade-off for another year or two of runway. For a page tied to core financial posting, it’s a maintenance burden that will outlast the convenience it buys.

Building the plan now

Version 29’s SOAP removal is close enough that most partners already have a project underway for it, and there’s real value in doing the OData audit at the same time rather than as a separate engagement six months from now. The RT0008 telemetry query doesn’t distinguish urgency by protocol, so pulling both SOAP and OData usage in one pass gives you a single, complete picture of every legacy web service dependency in an environment instead of two half-finished ones. Clients who hear “we already checked your integrations for the SOAP deadline” and then get surprised by an OData outage eighteen months later will reasonably ask why the first audit didn’t catch it. It’s a fair question, and the honest answer is that it’s a different telemetry filter and a few extra hours of query classification, not a fundamentally different project. Doing both now, while the environment’s already open on the workbench, is the cheaper version of this work by a wide margin.

Routeget Technologies has been walking clients through Business Central’s SOAP and OData retirement timelines as part of standard health-check engagements, building the telemetry-based inventory first so the migration scope is based on what’s actually running rather than what’s documented.


#BusinessCentralOData #ODataDeprecation #APIv2Migration #BCIntegrations #ERPGovernance #BusinessCentralAPI

Why Business Central Webhook Notifications Go Missing, and How to Architect Around It

Solutions architect reviewing a network integration dashboard representing Business Central webhook notifications

A Business Central integration that sailed through testing starts dropping records three weeks into production, and nobody can explain why until someone finally opens the subscription logs and finds a long trail of silent deletions. This is one of the more common failure patterns solution architects run into once Business Central webhook notifications move from a sandbox demo into a live integration carrying order confirmations, inventory adjustments, or approval status changes. The webhook model itself is well documented, but a handful of its operational rules are easy to miss during initial build-out, and missing them is exactly what causes integrations to degrade quietly instead of failing loudly where someone would notice.

The Handshake Most Implementations Get Half Right

Every Business Central webhook subscription begins with a validation handshake, and it is stricter than most developers expect on first pass. When a subscription is created against the v2.0 API, Business Central sends a request to the registered notification URL with a validationToken appended as a query parameter. The receiving endpoint has to echo that exact token back in the response body with an HTTP 200 status, and this is not a one-time formality. The same handshake fires again every time the subscription is renewed, which matters because Business Central webhook subscriptions expire after three days by design. There is no way to extend that window through configuration; the only supported pattern is issuing a PATCH request to the subscription resource before expiration, which triggers a fresh validation round trip.

Teams that build their receiver as a lightweight Azure Function often hit trouble here because of cold starts. If the function has scaled to zero and the handshake response takes more than a few seconds to come back, Business Central treats it as a failed validation and the subscription is never established or renewed. Keeping the receiver warm, or at minimum handling the validation response as the very first branch in the function before any other logic runs, removes most of the flakiness teams report during initial rollout.

Why Business Central Webhook Notifications Stop Coming, With No Error in Sight

The part of the design that catches experienced integration teams off guard is what happens after a notification actually fails to deliver. Business Central will retry a failed notification for up to 36 hours, but only if the subscriber’s endpoint responds with HTTP 408, 429, or something in the 5xx range. Any other response code, including a 400 or a 404 that might result from a temporary bug in the receiver’s routing logic, causes the subscription to be deleted immediately with no further retry and no separate alert. From the Business Central side, everything looks fine because the delivery attempt technically completed. From the integration’s side, notifications simply stop arriving for that entity, and unless someone is actively polling the subscriptions endpoint to check for unexpected deletions, the gap can persist for days before anyone notices missing sales order lines or unsynced customer records downstream.

This is the mechanism behind the scenario at the top of this article. A receiver that returns a 500 during a genuine outage is actually in a safer position than one that returns a 400 because of a malformed payload edge case, since the 500 at least buys 36 hours of retry attempts while the underlying issue gets fixed. Teams that want resilience here should treat any unhandled exception in the receiver as a 5xx rather than letting it bubble up as a generic error page, and should build a scheduled check that compares active subscriptions against the expected list so a silent deletion gets flagged rather than discovered by a downstream data gap weeks later.

Developer workstation showing an abstract data synchronization diagram representing a Business Central API integration

The Records Webhooks Quietly Refuse to Support

Before troubleshooting delivery issues, it is worth confirming the subscribed entity was ever eligible for webhooks in the first place, since Business Central will let a subscription be created against certain API pages that then never fire a single notification. Webhooks are not supported for API pages built on temporary tables, for pages where the OData key consists of more than one field or is otherwise composite, for system tables above table number 2000000000, for anything exposed as an API type query rather than an API type page, or for the Job Queue Entry table specifically. An API page built for a custom extension needs ODataKeyFields set to a single field, typically SystemId, or the subscription will appear to register successfully while silently never delivering anything.

Document-style entities carry their own nuance worth designing around. A change to a sales invoice line does not generate its own notification; instead, Business Central notifies against the parent sales invoice header when any of its lines change. Integrations that subscribe only at the header level and assume line-level granularity will miss the specific detail of what changed and need to follow up with a GET request against the full document to reconstruct it, which is standard practice anyway since webhook payloads never carry the actual record data, only a pointer to it and the type of change that occurred.

Batching, Delay, and the Events That Let You Tune Both

Business Central does not fire a notification the instant a record changes. There is a default 30 second delay built in after the first change to a watched entity, which exists to let a burst of related changes settle before anything is sent. If more than 1,000 records change within that delay window, Business Central collapses the individual notifications into a single collection notification rather than sending a thousand separate payloads, which is a sensible default for bulk imports but can surprise a downstream system expecting one notification per record during something like a large data migration or batch order release.

Both behaviors are adjustable for AL developers who need finer control. The delay interval can be modified through the OnGetDelayTime integration event in the API Webhook Notification Mgt. codeunit, and the threshold that triggers collection-style batching can be adjusted through OnGetMaxNumberOfNotifications in API Webhook Notification Send. Extensions that need near-real-time delivery for smaller entities, such as a status flag that a warehouse floor system needs to react to within a couple of seconds, are reasonable candidates for tightening the delay through these events; extensions dealing with high-volume header tables like sales lines are usually better served leaving the defaults alone and designing the receiver to handle collection notifications gracefully.

Designing for the Gaps: A Hybrid Pattern That Actually Holds Up

Given all of the above, the honest engineering position is that Business Central webhooks were never meant to be the sole source of truth for keeping two systems in sync, and Microsoft’s own documentation is candid that delivery is not guaranteed. Subscriptions can lapse from a missed renewal, a receiver bug can trigger an unannounced deletion, and network conditions on either side can drop a notification outright. The pattern that holds up in production combines the two mechanisms rather than choosing one: webhooks handle the fast path, giving near-real-time propagation for the vast majority of changes, while a scheduled reconciliation job, often running hourly or nightly depending on data volume, polls the same API endpoints using a last-modified timestamp filter to catch anything the webhook layer missed.

This is a small amount of extra engineering for a meaningful reliability gain, and it also solves the operational blind spot described earlier: the reconciliation job can double as the subscription health check, verifying that expected subscriptions still exist and re-registering anything that was unexpectedly deleted. Teams that skip this step tend to discover the gap only when a customer or finance team member notices a record that should have synced and did not, which is a far more expensive way to find the same bug.

What This Means for Your Next Integration Build

None of these behaviors are hidden or undocumented, but they are scattered across API reference pages that most teams read once during initial scoping and rarely revisit once the integration is live. The practical takeaway is to treat the three-day renewal window, the narrow retry code list, the unsupported table types, and the batching thresholds as design inputs from day one rather than issues to debug after the fact. At Routeget Technologies, the integrations that hold up longest in production are the ones where the reconciliation safety net was scoped alongside the webhook subscriptions from the start, not bolted on after the first silent data gap got noticed. Getting that sequencing right the first time is usually the difference between an integration the business trusts and one that quietly needs babysitting.


#BusinessCentralAPI #WebhookReliability #ERPIntegration #DynamicsBusinessCentral #ALDevelopment #EnterpriseIntegration