Skip to main content

Notifications

How to create Custom APIs for Business Central… even from MacOS!

Standard APIs

With the Spring 18 release of Business Central, Microsoft introduced APIs. There 44 APIs available out-of-the-box. 

There are a lot of materials available on the web about APIs for Business Central. Some of them:

Standard APIs are perfect for Connect Apps. If you want to pull/push data to Business Central, but don’t have experience in AL or Business Central architecture – you can still build your app, using any available technology and programming language.

 

But what if you want to create your own APIs for Business Central?

Now, with October release, that becomes possible, and actually very easy. 

Custom APIs 

With October 18 release of Business Central now it’s possible to create your custom APIs in AL. 

Step 1. Open VS Code with AL extension installed

Usually, I use https://aka.ms/bcsandbox VM to develop in AL. But at DirectionsNA Microsoft announced support of AL for MacOS!

So, next scenario I will cover from my brand new MacOS Mojave desktop!

For Windows users … continue reading =)

1588.Scr01.png

Step 2. Open/clone/create AL project and download symbols

I will create a new AL project, and this will be a hybrid App. It will have Add-on capabilities (internal data structure and UI) and Connect capabilities (exposed API to my tables). 

How to create new AL project and download symbols on MacOS

Step 3. Create a new table, list page and publish an app

My app will show the list of aeroplanes. Very simple example. I will not show here, how to create new AL table and page – there are tons of material available on the web.

Here is the AL code

After this step, a user will have an opportunity to create/change/delete records in a new table from Business Central UI.

Scr02.png

Ok, now we have Add-on app. What’s about Connected App part? 

Step 4. Create custom API for your App

Assume, that you want to provide to the world opportunity to communicate with your App. In my case, I have the list of all aeroplane’s models. So, why not to share that with the world?

Add an Id  field to the table

First, add an ID field to your table with type GUID.

Scr03.png

Assign a value, when you insert the record

Scr04.png

From now, any new entry in my table will have a unique ID.

API endpoints

Before continuing, let’s stop in a minute on API endpoints. Endpoint – is a URL, which gives you access to one or many entities inside of Business Central, from outside. 

You can access data, through the endpoint, using 2 types of authentication: AAD and Direct (Web service Key).

Depending on authentication type - endpoints URI will differ. In the next examples, I'll use Direct authentication.

Production Tenant

Business Central offers out-of-the box API endpoints to the base APIs. Like:

The list of all APIs

https://api.businesscentral.dynamics.com/v1.0/<your domain>/api/beta

The list of companies

https://api.businesscentral.dynamics.com/v1.0/<your domain>/api/beta/companies 

The list of items

https://api.businesscentral.dynamics.com/v1.0/<your domain>/api/beta/

companies(<companyId>)/items

Endpoints described above, give you access to the data inside production Business Central tenant. They are well described in official docs

 

Sandbox Tenant

What about API endpoints for the online sandbox tenant? It’s not documented feature (yet). But it’s possible!

The list of all APIs

https://api.businesscentral.dynamics.com/v1.0/<sandbox tenant id>/sandbox/api/beta

The list of companies

https://api.businesscentral.dynamics.com/v1.0/<sandbox tenant id>/sandbox/api/beta/companies

The list of items

https://api.businesscentral.dynamics.com/v1.0/<sandbox tenant id>/sandbox/api/beta/companies(<companyId>)/items

 

Cool, but all endpoints, described above, link us to the base 44 APIs, published by Microsoft.

Is it possible to create our own APIs? And if yes, how to call them both for production and sandbox tenants?

YES! It’s possible!

Custom APIs endpoints

It’s also not documented feature (or I should improve my Google experience:).

I discovered them during DirectionsNA.

Production Sandbox
The list of all custom APIs

https://api.businesscentral.dynamics.com/v1.0/

<your domain>/api/<ApiPublisher>

/<ApiGroup>/<ApiVersion>

https://api.businesscentral.dynamics.com/v1.0/

<sandbox tenant id>/sandbox/api/<ApiPublisher>

/<ApiGroup>/<ApiVersion>

The list of companies

https://api.businesscentral.dynamics.com/v1.0/

<your domain>/api/<ApiPublisher>

/<ApiGroup>/<ApiVersion>/companies

https://api.businesscentral.dynamics.com/v1.0/

<sandbox tenant id>/sandbox/api/<ApiPublisher>

/<ApiGroup>/<ApiVersion>/companies

The list of your entities

https://api.businesscentral.dynamics.com/v1.0/

<your domain>/api/<ApiPublisher>

/<ApiGroup>/<ApiVersion>/companies

(<companyId>)/<entitySetNames>

https://api.businesscentral.dynamics.com/v1.0/

<sandbox tenant id>/sandbox/api/<ApiPublisher>

/<ApiGroup>/<ApiVersion>/companies

(<companyId>)/<entitySetNames>

Great! So how to publish and consume them?

 

Create a new page with type API

API pages where introduced in NAV2018. All 44 base APIs have own pages with type API.

Let’s create a new API page for aeroplane models. Use snippet for that.

page 50102 "AIR AirplaneModel Entity"
{
    PageType = API;
    Caption = 'airplaneModels';
    APIPublisher = 'DmitryKatson';
    APIVersion = 'beta';
    APIGroup = 'airplanes';
    EntityName = 'airplaneModel';
    EntitySetName = 'airplaneModels';
    SourceTable = "AIR Airplane Model";
    DelayedInsert = true;
    ODataKeyFields = Id;

    layout
    {
        area(Content)
        {
            repeater(GroupName)
            {
                field(id; Id)
                {
                    Caption = 'Id';
                    ApplicationArea = All;
                }
                field(icaoCode; "ICAO Code")
                {
                    Caption = 'icaoCode';
                    ApplicationArea = All;
                }
                field(description; Description)
                {
                    Caption = 'description';
                    ApplicationArea = All;
                }

            }
        }
    }
    trigger OnInsertRecord(BelowxRec: Boolean): Boolean
    begin
        Insert(true);

        Modify(true);
        exit(false);
    end;

    trigger OnModifyRecord(): Boolean
    var
        AirplaneModel: Record "AIR Airplane Model";
    begin
        AirplaneModel.SETRANGE(Id, Id);
        AirplaneModel.FINDFIRST;

        IF "ICAO Code" <> AirplaneModel."ICAO Code" THEN BEGIN
            AirplaneModel.TRANSFERFIELDS(Rec, FALSE);
            AirplaneModel.RENAME("ICAO Code");
            TRANSFERFIELDS(AirplaneModel);
        END;
    end;
}

Remember some important rules:

  • Fields should be named in the APIs supported format
  • Add Insert(true) for OnInsert Trigger. Cos when you insert an entity through API endpoint, Business Central don’t run OnInsert trigger on the table. And you remember – we assign the ID for the new record there.
  • Add business logic to Modify trigger. Remember that an external user can change values through API, even the value of the primary key field.
  • Add Delete(true) for On Delete trigger. The same story as described above. 

That’s it!

You’ve created custom API. But it’s not available yet. We have one final step to be able to consumpt it.

 

Publish your app

Just publish your app, as usual. 

Now let’s test our custom API, using Postman.

 

Before publishing

After publishing

Amazing!!!

From that moment we have our own API on the cloud Business Central!

Explore custom APIs

Let’s save custom endpoint to the variable

urlCustomApiSandbox = https://api.businesscentral.dynamics.com/v1.0/b7268087-f626-4efe-ac43-37bfaafc16d8/sandbox/api/DmitryKatson/airplanes/beta

Get the list of companies

Get the list of custom entities

Insert a new custom entity

Update custom entity

Delete custom entity

Conclusion

It took me about 5 minutes to create custom API (and 4 hours to turn it into a blog:) 

Do you believe in that? It’s a new future! We can’t even dream about this before, but it’s possible now!

And yes! Once again, I made it without docker, VM, developer licence or whatever. Just my MacOs and VSCode with AL.

One more thing

Did you know that it’s even possible to extend base APIs! Oh yeee… That’s true! But this is a topic for another blog.

Stay tuned! 

Comments

*This post is locked for comments

  • Hello, Can you please guide how to publish the custom api? Thanks much Sandip
  • Community Member Profile Picture Community Member Microsoft Employee
    Posted at

    you need to add IF-Match:W/"......./" in the header of the patch request .

  • Robyn2018 Profile Picture Robyn2018 Most Valuable Professional
    Posted at

    Great post Dimitry,

    I could use the POST and GET instruction, but when I use the PATCH or DELETE, the system give an error:

    "error": {

           "code": "BadRequest_InvalidToken",

           "message": "Could not validate the client concurrency token required by the service. Please provide a valid token in the client request."

       }

    Do you know what's the problem?

    Thanks in advance.

    Roberto

  • minaise Profile Picture minaise
    Posted at

    Cool reading. How to enable custom API for own made document type page like the sales order what always contain sales header table and sales line table?  I am just little confusing about that.

  • MrPingu Profile Picture MrPingu
    Posted at

    After failed attempts of getting the API working I download your code and compiled it and uploaded it to a production tenant. But the API doesn't work at all. What's wrong, the request or some switch I need to flip somewhere else?

    I tried the following request:

    GET api.businesscentral.dynamics.com/.../airplaneModels

    The response I always get is:

    {

       "error": {

           "code": "BadRequest_NotFound",

           "message": "No HTTP resource was found that matches the request URI 'api.businesscentral.dynamics.com/.../airplaneModels;aid=FIN'."

       }

    }

    Also tried the following request:

    api.businesscentral.dynamics.com/.../beta

    This gives me the same result as "Before Publishing": an Empty response

    For correct understanding an Custom API url is build up like, correct?

    api.businesscentral.dynamics.com/.../

    For the entities within a company you use the following request, right?

    api.businesscentral.dynamics.com/.../companies()

    It's a shame the documentation on this part of Business Central is so little. API endpoints and how to make your own.

    @Jignesh Dhandha: replace the tenant-id in the url with your own tenant-id, I believe that's the way to do it but I don't seem to get it right though.

  • Community Member Profile Picture Community Member Microsoft Employee
    Posted at

    Hello dkatson,

    Very good article to create custom api.

    I have one query, when we

    api.businesscentral.dynamics.com/.../beta

    system will pop up user name and password so which user name and password we use to test this url in postman.

    Thank you

  • MrPingu Profile Picture MrPingu
    Posted at

    Thanks for your useful blog. This got me started! :)

    Can you explain what you did on  "OnModifyRecord()"?

    Also, I'm interested in what Dave Saman asked: How to expose fields of an Item Extension through a Custom API?

  • Community Member Profile Picture Community Member Microsoft Employee
    Posted at

    Great post! Can we create custom api:s on local development? That is, for a local installation of Business Central via docker

  • Community Member Profile Picture Community Member Microsoft Employee
    Posted at

    Hi Dmitry,

    Great post.

    I'm trying to extend the existing API's by using a page extension on page 5471, but the fields are not showing on the default endpoints.

    Could you point me in the right directions on how to achieve this?

    Regards,

    Dave

  • Vignir Einarsson Profile Picture Vignir Einarsson 45
    Posted at

    Very good article that got me started. The API has given me some headaches but overall cool feature, I wrote a little article on mibuso on how to create complex types in the API if anyone is interested.  forum.mibuso.com/.../nav-2018-api-complex-types