With the release of Business Central 2020 wave 2, a new version of the standard API set has been released. This new version got its own documentation here: https://docs.microsoft.com/en-us/dynamics-nav/api-reference/v2.0/. But while looking into it I was missing an overview of what has been changed between v1.0 and v2.0. And nothing was mentioned in the what’s new overview either. The only resource I’ve found so far is this video from the virtual launch event: https://events1.social27.com/MSDyn365BCLaunchEvent/agenda/player/72576. Which is a great video by the way, but I that kind of guy that prefers to read instead of watching. So I decided to dive in and try to compile a complete list of all these changes. I guess I can’t be 100% complete here, but with your help we can expand this list. If you notice any change that should be on this list, then please drop me an email or write it in the comments below.
URL
First of all, the URL has been changed. For version v2.0 you need to use /api/v2.0 in the URL. The full URL of the API in a production environment on SaaS is now:
https://api.businesscentral.dynamics.com/v2.0/production/api/v2.0
Don’t let the double v2.0 in the URL confuse you. The first v2.0 is the version of the online platform that supports multiple environments. It allows you to use your own names for the environments. The second v2.0 is the api version that you want to call.
For an on-prem server, or docker container, the URL is now:
https://mysandbox:7048/bc/api/v2.0
Whereas mysandbox is the name of your container or server where the Business Central service tier is running.
One important thing to mention here: the v1.0 version is still available. Your existing integrations with API v1.0 will not break because v2.0 was introduced. This is a very common scenario in the API world, you get the time to implement the new version. Of course you will be encouraged to do so because v1.0 will be removed at a certain point in the future. But hey, the API beta version should already been gone by now but it is still available. 😉
Source code
The source code of API v1.0 and v2.0 can be found on GitHub in the ALAppExtensions repository:
https://github.com/microsoft/ALAppExtensions/tree/master/Apps/W1/APIV1
https://github.com/microsoft/ALAppExtensions/tree/master/Apps/W1/APIV2
Just clone the repository and you have full access to the code, which can be very helpful!
Differences
The most important question is of course how different the API v2.0 is from v1.0. Are there many new fields, did the structure change, etc.? Best way to see the differences the two version is by comparing the metadata. And there is a massive difference between the two versions. See here for yourself: https://editor.mergely.com/oTms3IZF. Let’s look at a number of important differences.
Nested objects
In v1.0 there was something called Edm Types or complex types. This was a feature to return nested JSON objects in the result of an API call. In the picture below that is the case with the address property in the customer API.
// Customers API v1.0 { "@odata.etag": "W/\"JzQ0O0NVYTIrTXBEV0V6VGZtcStpa3Zaekp0clFGZFRndDArZFJSRFh6eUkrL0U9MTswMDsn\"", "id": "983833b3-b1fd-ea11-bc7d-00155df3a615", "number": "10000", "displayName": "Adatum Corporation", "type": "Company", "phoneNumber": "", "email": "robert.townes@contoso.com", "website": "", "taxLiable": true, "taxAreaId": "df3a33b3-b1fd-ea11-bc7d-00155df3a615", "taxAreaDisplayName": "ATLANTA, GA", "taxRegistrationNumber": "", "currencyId": "00000000-0000-0000-0000-000000000000", "currencyCode": "USD", "paymentTermsId": "aa3733b3-b1fd-ea11-bc7d-00155df3a615", "shipmentMethodId": "00000000-0000-0000-0000-000000000000", "paymentMethodId": "8a3a33b3-b1fd-ea11-bc7d-00155df3a615", "blocked": " ", "lastModifiedDateTime": "2020-09-23T15:31:09.68Z", "address": { "street": "192 Market Square", "city": "Atlanta", "state": "GA", "countryLetterCode": "US", "postalCode": "31772" } }
In the code of the v1.0 API page this was defined as follows (note the property ODataEDMType):
field(address; PostalAddressJSON) { Caption = 'address', Locked = true; ODataEDMType = 'POSTALADDRESS'; ToolTip = 'Specifies the address for the customer.'; trigger OnValidate() begin PostalAddressSet := TRUE; end; }
To read more about the property ODataEDMType, I recommend reading this detailed post from Vjeko about this topic. The point I would like to make here is that this property is not used anymore in the v2.0 API. Not any of the APIs does have a nested data structure that is defined in this way. Instead, you will see first-level properties or navigation properties. The address property in the customer API for example has been replaced by first-level properties. In the picture below you can see that we now have all address fields directly on the same level as the other properties, just as they appear in the table.
// Customers API v2.0 { "@odata.etag": "W/\"JzQ0O0NVYTIrTXBEV0V6VGZtcStpa3Zaekp0clFGZFRndDArZFJSRFh6eUkrL0U9MTswMDsn\"", "id": "983833b3-b1fd-ea11-bc7d-00155df3a615", "number": "10000", "displayName": "Adatum Corporation", "type": "Company", "addressLine1": "192 Market Square", "addressLine2": "", "city": "Atlanta", "state": "GA", "country": "US", "postalCode": "31772", "phoneNumber": "", "email": "robert.townes@contoso.com", "website": "", "taxLiable": true, "taxAreaId": "df3a33b3-b1fd-ea11-bc7d-00155df3a615", "taxAreaDisplayName": "ATLANTA, GA", "taxRegistrationNumber": "", "currencyId": "00000000-0000-0000-0000-000000000000", "currencyCode": "USD", "paymentTermsId": "aa3733b3-b1fd-ea11-bc7d-00155df3a615", "shipmentMethodId": "00000000-0000-0000-0000-000000000000", "paymentMethodId": "8a3a33b3-b1fd-ea11-bc7d-00155df3a615", "blocked": " ", "lastModifiedDateTime": "2020-09-23T15:31:09.68Z" }
An example of a navigational property can be found in the items API. In v1.0 the properties of the Base Unit of Measure are represented as a nested object.
// Items API v1.0 { "@odata.etag": "W/\"JzQ0O1NsakZCQWNRU21INi8xOS9zWFhXSWRwWGxNbVArOXdjWVM0NGxqOUJxUUU9MTswMDsn\"", "id": "a23833b3-b1fd-ea11-bc7d-00155df3a615", "number": "1896-S", "displayName": "ATHENS Desk", "type": "Inventory", "itemCategoryId": "2fd92eb9-b1fd-ea11-bc7d-00155df3a615", "itemCategoryCode": "TABLE", "blocked": false, "baseUnitOfMeasureId": "023933b3-b1fd-ea11-bc7d-00155df3a615", "gtin": "", "inventory": 4, "unitPrice": 1000.8, "priceIncludesTax": false, "unitCost": 780.7, "taxGroupId": "ee3a33b3-b1fd-ea11-bc7d-00155df3a615", "taxGroupCode": "FURNITURE", "lastModifiedDateTime": "2020-09-23T15:31:11.057Z", "baseUnitOfMeasure": { "code": "PCS", "displayName": "Piece", "symbol": null, "unitConversion": null } }
In the Items API v2.0 not all of these Unit of Measure properties are included as first-level properties. Only the Base Unit of Measure Code is included as that is a field in the table.
// Items API v2.0 { "@odata.etag": "W/\"JzQ0O0xYWXRncXdObnU0Q2ppc25kV1Jac2NNMHZmUExXSjNVSy8yWGZBSFdXY0E9MTswMDsn\"", "id": "a23833b3-b1fd-ea11-bc7d-00155df3a615", "number": "1896-S", "displayName": "ATHENS Desk", "type": "Inventory", "itemCategoryId": "2fd92eb9-b1fd-ea11-bc7d-00155df3a615", "itemCategoryCode": "TABLE", "blocked": false, "gtin": "", "inventory": 4, "unitPrice": 1000.8, "priceIncludesTax": false, "unitCost": 780.7, "taxGroupId": "ee3a33b3-b1fd-ea11-bc7d-00155df3a615", "taxGroupCode": "FURNITURE", "baseUnitOfMeasureId": "023933b3-b1fd-ea11-bc7d-00155df3a615", "baseUnitOfMeasureCode": "PCS", "lastModifiedDateTime": "2020-09-23T15:34:03.207Z" }
So, where did those properties go? The Items API v2.0 has a new navigation property, called unitOfMeasure. A navigation property represents data from related tables and can be optionally included in the returned data. To add this as to the result, you need to add the parameter ?$expand=unitOfMeasure. The URL then looks like:
https://api.businesscentral.dynamics.com/v2.0/production/api/v2.0/company({id})/items?$expand=unitOfMeasure
The result now looks like this:
// Items API v2.0 { "@odata.etag": "W/\"JzQ0O0xYWXRncXdObnU0Q2ppc25kV1Jac2NNMHZmUExXSjNVSy8yWGZBSFdXY0E9MTswMDsn\"", "id": "a23833b3-b1fd-ea11-bc7d-00155df3a615", "number": "1896-S", "displayName": "ATHENS Desk", "type": "Inventory", "itemCategoryId": "2fd92eb9-b1fd-ea11-bc7d-00155df3a615", "itemCategoryCode": "TABLE", "blocked": false, "gtin": "", "inventory": 4, "unitPrice": 1000.8, "priceIncludesTax": false, "unitCost": 780.7, "taxGroupId": "ee3a33b3-b1fd-ea11-bc7d-00155df3a615", "taxGroupCode": "FURNITURE", "baseUnitOfMeasureId": "023933b3-b1fd-ea11-bc7d-00155df3a615", "baseUnitOfMeasureCode": "PCS", "lastModifiedDateTime": "2020-09-23T15:34:03.207Z", "unitOfMeasure": { "@odata.etag": "W/\"JzQ0O25yOXVDUTNxWDdtMTRIcnZ5UHZpOGp2Q0lQWFl1NFhqbzA0OTdXOGNPbDA9MTswMDsn\"", "id": "023933b3-b1fd-ea11-bc7d-00155df3a615", "code": "PCS", "displayName": "Piece", "internationalStandardCode": "EA", "symbol": "", "lastModifiedDateTime": "2020-09-23T15:31:13.643Z" } }
Another property that was changed in the same way is the property dimensions. Previously, you would find dimensions of a journal line under the property dimensions. In v2.0 this has been changed to dimensionSetLines and needs to be expanded.
To find all available navigational properties, you can read either the documentation. If an API has a navigation property is will be documented. For the Items API it can be found here. You can of course also look into the metadata, where you will find the complete definition in XML.
The change to use navigation properties instead of complex types has a big effect on performance. Complex types needed to be constructed by code, but the navigation properties are just other API pages (or subpages if you want). Which results in less code, but you need to remember to include $expand= in the url to get those navigation properties.
Relationship multiplicities
The move from complex types to API subpages comes with another change that was needed. The complex types could be defined as an object or as a collection. But API subpages were always treated as a collection, even if they only could contain one record. Here is an example what I mean. In the source code of the customers API page you will find this subpage:
part(customerFinancialDetails; 20048) { Caption = 'Customer Financial Details', Locked = true; EntityName = 'customerFinancialDetail'; EntitySetName = 'customerFinancialDetails'; SubPageLink = SystemId = FIELD(SystemId); }
The metadata shows what the result will look like, as a collection:
<NavigationProperty Name="customerFinancialDetails" Type="Collection(Microsoft.NAV.customerFinancialDetail)" Partner="customer" ContainsTarget="true"> <ReferentialConstraint Property="id" ReferencedProperty="id" /> </NavigationProperty>
When you call the customers API with $expand=customerFinancialDetails you will get the details in an array. But the page subpage itself is based on the same table customer and just includes a number of flowfields. This is done for performance reasons, by the way. In API v1.0 the JSON looks like this:
{ "id": "5eea6afd-4a2a-eb11-bb4f-000d3a25f2a9", "number": "10000", "displayName": "Adatum Corporation", "type": "Company", "customerFinancialDetails": [ { "@odata.etag": "W/\"JzQ0O25GVTRvaWdTUk13aG9TOUEySzhYaTM1WE84SkxDeXF5MEdTeUlZblhGSlk9MTswMDsn\"", "id": "5eea6afd-4a2a-eb11-bb4f-000d3a25f2a9", "number": "10000", "balance": 0, "totalSalesExcludingTax": 223598.4, "overdueAmount": 0 } ] }
As you can see, the array contains only one record, and it will always contain just one record. With complex types, you could define this in the Edm type definition. But Edm types are now not used anymore. Instead, Business Central v17 allows to specify the multiplicity as a property on the page part and that’s being used in API v2.0 app to get a single nested object instead of a collection:
part(customerFinancialDetails; "APIV2 - Cust Financial Details") { //TODO - WaitingModernDevProperty, Caption = 'Customer Financial Details'; CaptionML = ENU = 'Multiplicity=ZeroOrOne'; EntityName = 'customerFinancialDetail'; EntitySetName = 'customerFinancialDetails'; SubPageLink = SystemId = Field(SystemId); }
The metadata now shows that this is a single object instead of a collection. But be careful, because it is a single object it’s referenced by its EntityName, not by the EntitySetName!
<NavigationProperty Name="customerFinancialDetail" Type="Microsoft.NAV.customerFinancialDetail" ContainsTarget="true"> <ReferentialConstraint Property="id" ReferencedProperty="id" /> </NavigationProperty>
This is another breaking change with API v2.0. In this example, we must add $expand=customerFinancialDetail to the URL (without the s at the end). The result now looks like:
{ "id": "5eea6afd-4a2a-eb11-bb4f-000d3a25f2a9", "number": "10000", "displayName": "Adatum Corporation", "type": "Company", "customerFinancialDetail": { "id": "5eea6afd-4a2a-eb11-bb4f-000d3a25f2a9", "number": "10000", "balance": 0, "totalSalesExcludingTax": 223598.4, "overdueAmount": 0 } }
Back to the property that is used to define the multiplicity. At the release of Business Central v17, there was no property available. As a workaround the CaptionML property is used in this way:
CaptionML = ENU = 'Multiplicity=ZeroOrOne';
Multiplicuty can be set as ‘ZeroOrOne’ or ‘Many’. The default is ‘Many’, which will result in a collection. In runtime 6.1 the new property Multiplicity is already available, however, it doesn’t work yet. If you need this in your custom APIs, then you have to use the workaround with CaptionML for now.
Key fields in the url
In v1.0 there were still some APIs that didn’t use the SystemId as the primary key. But in v2.0 that has changed. All entities can be retrieved with the SystemId, which is a unique GUID. In case you have scenario to create a new record and provide the SystemId, that’s also possible in API v2.0.
Enums
Another change in the schema of API v2.0 is the possibility to use enums. To use enums, you must add ?$schemaversion=2.0 to the API url. If you do so, you will get different behavior for fields that are based on enums. All exposed fields that were of type option in v1.0 are converted into enums for v2.0. The difference can be explored here: https://editor.mergely.com/IWfP3kR0/.
Here is an example of what is added to the schema:
<EnumType Name="contactType"> <Member Name="Company" Value="0" /> <Member Name="Person" Value="1" /> </EnumType> <EnumType Name="customerBlocked"> <Member Name="_x0020_" Value="0" /> <Member Name="Ship" Value="1" /> <Member Name="Invoice" Value="2" /> <Member Name="All" Value="3" /> </EnumType>
Those fields were previously exposed as Edm.String, but now they are strong typed:
<Property Name="blocked" Type="Microsoft.NAV.customerBlocked" />
This is very helpful in case you want to know which values are available for enum fields. For example to verify data before sending it or to display only valid values in a dropdown to a user.
What about that strange value “_x0020_”? That’s of course the empty ordinal value, also known as ” “. It’s the Unicode encoded representation of a space. You would expect that you also need to use this Unicode encoding when posting data. But it turns out that spaces can still be used. Below are two examples of a JSON body for the customers API. The first one is only accepted when you use schema version 2.0, the second one works fine in all cases.
// This body works only with ?$schemaversion=2.0 { "displayName": "Demo Enum", "blocked": "_x0020_" } // This body works for both schemaversions { "displayName": "Demo Enum", "blocked": " " }
In case you want to present the possible options to a user, then you need to decode the Unicode value to get back the original value. But wait… there is another new feature in API v2.0 that’s even better…
Captions
Yep… captions are now exposed by a specific endpoint. For those integrations that need to present fields and/or enum values in a UI, they can grab the captions coming from BC, including the translations! The endpoint is named entityDefinitions. Actually, this is not only available for v2.0, it’s also available for v1.0. But for v1.0 it doesn’t make much sense, because most translations are missing in v1.0. In other words, it’s a new platform feature for APIs in Business Central v17, and API v2.0 is the first app to make use of it.
Ok, what is it?
The entityDefinitions endpoint provides multilanguage captions for the entity, the entity set plus all properties of the entity. And if you include schema version 2.0, then you get the enum captions included. This is how the structure looks like:
{ "entityName": "customer", "entitySetName": "customers", "entityCaptions": [], "entitySetCaptions": [], "properties": [], "actions": [], "enumMembers": [] }
Each array contains multiple translations. For example, the entityCaptions looks like this:
"entityCaptions": [ { "languageCode": 3079, "caption": "Debitor" }, { "languageCode": 2055, "caption": "Debitor" }, { "languageCode": 1044, "caption": "Kunde" }, { "languageCode": 1031, "caption": "Debitor" }, { "languageCode": 1053, "caption": "Kund" }, { "languageCode": 4105, "caption": "Customer" }, { "languageCode": 2057, "caption": "Customer" }, { "languageCode": 5129, "caption": "Customer" }, { "languageCode": 3081, "caption": "Customer" }, { "languageCode": 1030, "caption": "Kunde" }, { "languageCode": 1043, "caption": "Klant" }, { "languageCode": 2067, "caption": "Klant" }, { "languageCode": 1049, "caption": "Клиент" }, { "languageCode": 1033, "caption": "Customer" }, { "languageCode": 1040, "caption": "Cliente" }, { "languageCode": 2064, "caption": "Cliente" }, { "languageCode": 1035, "caption": "Asiakas" }, { "languageCode": 1029, "caption": "Zákazník" }, { "languageCode": 3082, "caption": "Cliente" }, { "languageCode": 3084, "caption": "Client" }, { "languageCode": 4108, "caption": "Client" }, { "languageCode": 2058, "caption": "Cliente" }, { "languageCode": 1039, "caption": "Viðskiptamaður" }, { "languageCode": 1036, "caption": "Client" }, { "languageCode": 2060, "caption": "Client" } ]
The properties contains a list of all properties with their captions (only showing displayName here):
"properties": [ { "name": "displayName", "captions": [ { "languageCode": 3079, "caption": "Anzeigename" }, { "languageCode": 2055, "caption": "Anzeigename" }, { "languageCode": 1044, "caption": "Visningsnavn" }, { "languageCode": 1031, "caption": "Anzeigename" }, { "languageCode": 1053, "caption": "Visningsnamn" }, { "languageCode": 4105, "caption": "Display Name" }, { "languageCode": 2057, "caption": "Display Name" }, { "languageCode": 5129, "caption": "Display Name" }, { "languageCode": 3081, "caption": "Display Name" }, { "languageCode": 1030, "caption": "Visningsnavn" }, { "languageCode": 1043, "caption": "Weergavenaam" }, { "languageCode": 2067, "caption": "Weergavenaam" }, { "languageCode": 1049, "caption": "Отображаемое имя" }, { "languageCode": 1033, "caption": "Display Name" }, { "languageCode": 1040, "caption": "Nome visualizzato" }, { "languageCode": 2064, "caption": "Nome visualizzato" }, { "languageCode": 1035, "caption": "Näyttönimi" }, { "languageCode": 1029, "caption": "Zobrazit název" }, { "languageCode": 3082, "caption": "Nombre para mostrar" }, { "languageCode": 3084, "caption": "Nom d’affichage" }, { "languageCode": 4108, "caption": "Nom d’affichage" }, { "languageCode": 2058, "caption": "Nombre para mostrar" }, { "languageCode": 1039, "caption": "Birtingarheiti" }, { "languageCode": 1036, "caption": "Nom d’affichage" }, { "languageCode": 2060, "caption": "Nom d’affichage" } ] } ]
Where do the captions and the translations come from? Not from the base app! Every API page has captions defined as you can see here in the first lines of the customers API:
page 30009 "APIV2 - Customers" { APIVersion = 'v2.0'; EntityCaption = 'Customer'; EntitySetCaption = 'Customers'; ChangeTrackingAllowed = true; DelayedInsert = true; EntityName = 'customer'; EntitySetName = 'customers'; ODataKeyFields = SystemId; PageType = API; SourceTable = Customer; Extensible = false; layout { area(content) { repeater(Group) { field(id; SystemId) { Caption = 'Id'; Editable = false; } field(number; "No.") { Caption = 'No.'; } field(displayName; Name) { Caption = 'Display Name'; ShowMandatory = true; [further lines truncated]
You can see the property EntityCaption and EntitySetCaption, both of which are also visible in the JSON from entityDefinitions. Same counts for the caption on the fields. The translations of these captions are included in the API app. They are not taken from the base app. This is something to keep in mind, as this can be really confusing!
If you use schema version 2.0, then you also get the enums in this way:
{ "entityName": "customerBlocked", "entitySetName": null, "entityCaptions": [], "entitySetCaptions": [], "properties": [], "actions": [], "enumMembers": [ { "name": "_x0020_", "value": 0, "captions": [ { "languageCode": 1033, "caption": " " } ] }, { "name": "Ship", "value": 1, "captions": [ { "languageCode": 1033, "caption": "Ship" } ] }, { "name": "Invoice", "value": 2, "captions": [ { "languageCode": 1033, "caption": "Invoice" } ] }, { "name": "All", "value": 3, "captions": [ { "languageCode": 1033, "caption": "All" } ] } ] }
What is strange here is that we only see captions for language code 1033 (ENU). Somehow, the translations of the enum “Customer Blocked” are not included. I checked the translation files of the base app (because the enums are defined in the base app), but the translations for those enums are definitely there. My guess is that the entityDefinitions only takes translations from the API app and does not look into the base app. This is something for Microsoft to fix!
This new entityDefinitions endpoint also works with custom APIs. Just include the captions and translations and you’re all set!
That’s what I could find about the new API features in Business Central v17 and API v2.0. If you have any addition, please let me know!
Thank you for the really interesting and detailed post. I’m one of them that used EDM for a particular scenario that currently I cannot achieve with parts. Let us say that you have a page with Header and Lines of a document that uses lines in a part.
If we look at the events raised:
1) PageOpen
2) Header.Init
3) Header.Insert
4) Line.Init and Line.Insert (for each line)
then there is not any other event that goes back at the level of the page/header.
Do you have any suggestion on this?
Would you mind to share the scenario so I can understand why you need an event back at the page header?
We need to handle a request which must update purchase blanket order line quantities and then create a purchase order from this blanket order, within the same request.
We have a request similar to the following:
{
“blanketNo”: “BO-0001”,
“lines”: [{
sku: “1000”,
qty: 2
},{
sku: “1001”,
qty: 3
}]
]
We cannot use batch because we want to do all the logic within the same request, and if a part of it fails, everything must fail.
There seems to be a way to do this, need to test and then blog about it. Stay tuned, will take me a few days! I need to blog about batch calls anyway…
It would be great if you find a way.
Looking forward to read your new post.
I know how to create batch calls but not able to achieve what needed, because I need that the 3 actions will be done in a transaction.
Hi Sergio
https://docs.microsoft.com/en-us/powerapps/developer/common-data-service/webapi/execute-batch-operations-using-web-api this suggests doing change sets which then sets it as atomic or
As I read this https://docs.microsoft.com/en-us/dynamics365/business-central/dev-itpro/developer/devenv-connect-apps-tips you can “To enable transactional batch behavior, include the Isolation: snapshot header with the $batch request.” which would help. Of course if AJ does a post on this that would massively help as the documentation isnt great.
Hi Matthew,
Thank you for the urls you shared, I will try the “Isolation: snapshot”, it is a valid solution for my scenario but I still think that having an event after processed the parts would be the optimal solution to make evething in one call. I have an open ticket with Microsoft, let me see what I can get.
Hi,
I am trying to make the sub parts work in a custom api, but there is absolutly no info, and its turning me bonkers 🙁
I have added a block in my custom api:
part(partName; ListPartPage)
{
EntityName = ‘customerEventLinkList’;
EntitySetName = ‘customerEventLinkLists’;
SubPageLink = “No.” = field(“No.”);
}
Based on the presentation video. I tried multiple variants, using api pages, list parts pages, nothing. It never show up my json. Not even empty.
Any idea on how to make those sub parts work in the custom api’s? Is there something special?
If i call the sub part api, i get results. But if i call the api that uses that api part,nothin shows fro the “part” part?
I hope someone here can help 🙂
Cheers
Did you add ?$expand=partName to the url?
If i do that, i get the following:
“code”: “BadRequest”,
“message”: “Could not find a property named ‘my_part_,name’ on type ‘Microsoft.NAV.customer’.
Something is wrong in your API. Feel free to send me the source code at aj at kauffmann.nl and I’ll take a look.
Hi, Thanks for the explanation it’s really helpful.
I tried the deep Insert, it worked great, but when i tried patch. It doesn’t update non triggered the subpart page, this is really a concern. Please can you help on this?
PATCH /bc/api/APIPublisher/APIGroup/v2.0/companies(7a2dff80-ee7e-4036-950d-656ecc2f567e)/unassignedExpenses(id=a4bf7ca6-886c-eb11-837a-80911061923f)?tenant%3Dtest=null&$schemaversion=2.0&$expand=laDimensionSetLines HTTP/1.1
Host: ope-nobase:7048
If-Match: *
Content-Type: application/json
Authorization: Basic b3BlOlBAc3N3b3JkMQ==
Content-Length: 354
{
“glAccountNo”: “63100”,
“laDimensionSetLines”: [
{
“code”: “DEPARTMENT”,
“valueCode”: “PROD”
},
{
“code”: “PROGRAM”,
“valueCode”: “MEDIUM”
}
]
}
I actually got 200 Ok status code back, the header updated successfully but the part page wasn’t triggered at all.
I hope someone here can help 🙂
Thanks
Unfortunately, deep patching is not supported by Business Central.
https://docs.microsoft.com/en-us/dynamics365/business-central/dev-itpro/webservices/odata-web-services#deep-patching
Thank you
Hi,
having a issue with EntityName, the json that are sending to the endpoint have the first letter in capital letter
“NoRequestItem”:{}
But BC makes NoRequestItem in to noRequestItem this only happen for EntityName
Do you have any idea how to force BC to use “NoRequestItem”
part(NoRequestItem; ALines2)
{
CaptionML = ENU = ‘Multiplicity=ZeroOrOne’;
ApplicationArea = All;
EntityName = ‘NoRequestItem’;
EntitySetName = ‘NoRequestItems’;
SubPageLink = EntryNo = field(EntryNo), ParentEntryNo = field(ParentEntryNo);
}
The OData implementation defaults to camel casing automatically. As far as I know, it’s not possible to change that behavior.
Hi ajk, thanks for all the help.
I have an API page which works fine for rest post calls, but this is when a single json object it is sent. I’m trying now to send a jsonArray which fails with error “An unexpected ‘StartArray’ node was found when reading from the JSON reader. A ‘StartObject’ node was expected.”
Is there anyway I can receive jsonarrays?
Regards,
DO you mean you want to POST a Json array? That’s not possible with a BC API page. A POST request inserts a single record, so you need to pass in a Json object.
If you want to POST multiple records at once, then you should look at batch requests: https://www.kauffmann.nl/2020/12/18/batch-calls-with-business-central-apis-1-basic-operation/
Does anyone know if CaptionClass translations do NOT work in an API page? Or, if they should, why do mine not work? I have a UI page that was easily converted to API, but the CaptionClass translations do not take effect. In fact, not even the specified “Caption = ‘xyz'” captions show up–only the actual field names. Thanks for any illumination.
Hello,
Microsoft has deprecated the ODataEDMType Property and set the Table “OData Edm Type” and Pages to Read-only.
My issue now is that i have an API for Warehouse Shipment Header, with the Subpage “Warehouse Shipment Lines”. I now need a third level for Lot Information. In the Past I would have created an ODataEDMType for the Lot Information, which is not possible anymore.
How does Microsoft handle that now?
Best regards,
Silas
Can we call a bound action using api v2 end point? like, http://nv-d365:7048/BC180/api/publisher/customAPI/v2.0/purchaseInvoices(2c3289e-b72a-ed11-a2d9-005056bf3c5)/Microsoft.NAV.Post
Or is it only possible with OData?
Yes, bound actions are supported on the API endpoint.
But they are case sensitive: the first word of the function MUST start as lower case. E.g. Microsoft.NAV.post (and not Post).
Thankyou.
Curiously, I have created a custom api, which works perfectly when there is only one company created in the database. When there are two companies, the custom APIs do not work but the standard APIs work perfectly. do you know why?
No, I can’t think of any reason why custom APIs would not work with more than one company.
Do you get any error message? Maybe you can share the URL and the result?
When I configure 2 or more companies in the same installation and I consult the api it tells me the following:
{
“error”: {
“code”: “Internal_CompanyNotFound”,
“message”: “Cannot process the request because the default company cannot be found. You can specify a default company in the service configuration file, or specify one for each tenant, or you can add a query string in the form of \”company=[name]\”. You can see the available companies by accessing the default OData web service, Company. For more information, see \”OData Web Services\” in Help. CorrelationId: 049d9bfd-cde0-4760-9cd5-66870e87f41f.”
}
}
but if I place the code in the url the same as in the standard api I get this error
{
“error”: {
“code”: “BadRequest_NotFound”,
“message”: “No HTTP resource was found that matches the request URI ‘https://api.businesscentral.dynamics.com/v2.0/511bb6cd-2b0f-ed11-b845-000d3a392829/Production/api/public/integracion/v1.0/companies(511bb6cd-2b0f-ed11-b845-000d3a392829)/purchaseHeaderAPIs?tenant=msweua355677765037&aid=FIN’.”
}
}
the url does not work the same way in the standard api as in a custom api
The parameter tenant and aid are not required.
The first error message means there was no company specified in the URL. The URL in the second request looks fine, up to the question mark. Just remove the question mark and everything beyond. That should work.
why is there no open api spec for v2.0? there is only the spec for v1.0 https://learn.microsoft.com/en-us/dynamics365/business-central/dev-itpro/api-reference/v2.0/dynamics-open-api
would be nice to have this available for v2.0
This is a great overview, thanks!
Hello, Can anyone please help me with the issue that i am facing. https://community.dynamics.com/business/f/dynamics-365-business-central-forum/487192/odata-v4-web-service-expansion
I am unable to figure out the problem. The api works sometimes and stops working.
Hi there,
I am facing the same problem (BC 21, on-premise).
Trying over and over again to be able to expand a part on my custom API-page.
At last I copied the source code from https://learn.microsoft.com/en-us/dynamics365/business-central/dev-itpro/developer/devenv-develop-custom-api to see if that would work.
Same problem…
Did you find a reason and a solution for this problem, Arend-Jan?
The problem I am facing is the error “code”: “BadRequest”, “message”: “Could not find a property named ‘my_page_part’ on type NAV.myAPIPage’