In this video, I continue to look at how to use the .NET Connected Services to talk with Microsoft Dynamics 365 Business Central via OData from C#. I look at the difference between “Web Services” and “APIs” and how to manipulate data from C#.

This is the second video in my OData series, the first episode is here.
In this second episode of the series on working with OData and Business Central from C#, Erik expands on the foundations laid in the first video. This time, he explores filtering data at the source using OData query options, inserting new records into Business Central, and working with both web service endpoints and API endpoints simultaneously from the same C# application.
Where We Left Off
In the first episode, Erik set up a C# application that connects to Business Central via OData and retrieves Chart of Accounts data. The starting point for this episode is that working application. One improvement he made since last time is how the company name is injected into the URL — rather than patching the request in an event handler, it’s better to include the company name directly in the base service route. This way, you’re logged into that company on the context from the start.
Filtering Data at the Source with OData Query Options
When retrieving data from Business Central, you could pull everything into a C# list and filter locally. But in many cases, you don’t want to dump all your data and filter on the client side — you want to filter at the source. The best way to accomplish this is by adding a query option:
chartOfAccounts.AddQueryOption("$filter", "Net_Change gt 0");
This uses OData filter syntax and gets sent directly to Business Central. Business Central turns this into a true filter applied at the database level, so only the records you actually need are transferred over the wire. In this example, only accounts with a positive net change are returned.
The key takeaway: AddQueryOption is your friend when you want to ensure that filtering happens server-side rather than client-side.
Inserting Records into Business Central
A common question from the first video was: how do we actually modify or insert data? Erik demonstrates creating a new Chart of Accounts entry from C#. The process takes just four lines of code:
// Create a new chart of accounts entity
var ca = BC18.ChartOfAccounts.CreateChartOfAccounts("100");
ca.Name = "YouTube Demo from C#";
// Add it to the context and save
context.AddToChartOfAccounts(ca);
context.SaveChanges();
A few things to note here:
- The static
CreateChartOfAccountsmethod takes the primary key as a parameter (the account number). - After creating the object, you set properties like
Namejust as you would with any C# object. - The context’s
AddTomethod queues the insert, andSaveChanges()sends it to Business Central. - The entity name (e.g., “ChartOfAccounts”) comes from whatever service name you expose in Business Central’s web services. Since the service is called “ChartOfAccounts” (plural), the entity name is also plural — even for a single record.
After running the program and checking Business Central, the new account “100 – YouTube Demo from C#” appears in the Chart of Accounts immediately.
Web Services vs. API Endpoints
Another question from viewers: when connecting to Business Central via OData Connected Services, you get an impressive list of everything exposed as a web service — but what about everything exposed as an API? Those aren’t on the same list.
That’s because they live on different endpoints:
- Web Services (OData v4):
.../ODataV4/ - API Pages:
.../api/v2.0/
The API endpoint exposes a different set of entities (96 in Erik’s environment), with slightly different naming conventions. For example, vendors are exposed as singular “vendor” rather than plural.
Connecting to Both Endpoints Simultaneously
To work with both endpoints in the same project, you need to manage a couple of things carefully:
- Rename the generated files: When you add a connected service, it generates a
.csfile and a.csdl.xmlfile. The XML reference inside the C# file points to a default name, so you need to rename consistently (e.g., suffix with-bc18). - Use different namespaces: Both connected services generate a context class called
NAV. If they share the same namespace, they’ll collide. Put them in different namespaces to avoid this. - Wire up authentication for each context: Don’t forget to attach the authentication event handler to both contexts — Erik demonstrated this the hard way by getting an “Unauthorized” error when he forgot to attach it to the second context.
The API endpoint URL structure is also slightly different. Instead of specifying a company name, you use the company ID:
// Web Services URL pattern:
// .../ODataV4/Company('Hogart')/...
// API URL pattern:
// .../api/v2.0/companies({company-guid})/...
You can find the company’s system ID using the page inspector in Business Central.
With both contexts set up, Erik demonstrates pulling vendors from the API endpoint and Chart of Accounts from the web services endpoint in the same program run — and it works perfectly.
A Note on Field Name Differences
An interesting detail: when working with API pages, field names may differ from their table counterparts. For example, on the Vendor table, the number field is called “No.” but the API exposes it as “number”, and “Name” becomes “displayName”. This is by design in the standard Business Central API pages.
Creating Custom API Pages
The source code includes an example of a custom API page in AL. This shows how you can expose your own entities through the API framework:
page 50140 APITest
{
APIGroup = 'group';
APIPublisher = 'hougaard';
APIVersion = 'v2.0';
ApplicationArea = All;
Caption = 'apiTest';
DelayedInsert = true;
EntityName = 'salesheader';
EntitySetName = 'salesheaders';
PageType = API;
SourceTable = "Sales Line";
layout
{
area(content)
{
repeater(General)
{
field(documentNo; Rec."Document No.")
{
Caption = 'Document No.';
}
field(documentType; Rec."Document Type")
{
Caption = 'Document Type';
}
field("type"; Rec."Type")
{
Caption = 'Type';
}
// Additional fields...
}
}
}
}
Key properties for API pages include:
- APIGroup, APIPublisher, APIVersion: These define the URL structure for your custom API endpoint.
- EntityName / EntitySetName: Define the singular and plural names for the entity in OData.
- PageType: API: Marks this as an API page rather than a standard UI page.
- DelayedInsert: Typically set to
truefor API pages.
Important Deprecation Notes
Erik highlights two significant deprecations coming to Business Central:
- Pages exposed as web services are going away — they are being replaced by API pages. From the C# perspective, the code is essentially the same; it’s just a matter of which URL you’re accessing.
- Basic authentication is also being deprecated — the next episode in this series will cover OAuth authentication as the replacement.
Summary
This episode covered three key topics for working with Business Central from C#: filtering data server-side using OData query options like $filter, inserting records with just four lines of code using the context’s AddTo and SaveChanges methods, and connecting to both web service and API endpoints simultaneously by managing namespaces and authentication carefully. With API pages replacing traditional web service exposure and OAuth replacing basic authentication, the next episode will tackle modern authentication — stay tuned.