API & Webhooks

Getting Started: Building Out Your Toolbox [Part 2 of 2]

  • 21 September 2022
  • 11 replies
  • 989 views

Userlevel 7
Badge +4

 

This guide is the second in a series of new guides brought to you by @Bfarkas. Links to the full Guide Series can be found at the end of this article.

 

Please note: This is Part 2 of the second guide in this series. If you missed Part 1, click here.

 

Guide Table of Contents

 

Power Automate: How to Build Quick Workflows

Ready to go a step further? Great, because this is my favorite part!

 

Now, I am going to do this example using Power Automate, as that is what I have access to. It is an example of how you can take your API knowledge a step further. Alternatives like Tray.io, Workato, MuleSoft, etc. all have ways to do this as well. Staying within your supported ecosystem has many advantages, so make sure to see what is supported in your organization.

 

For those that do not know, Power Automate is part of Office365 from Microsoft. It allows users to connect various services, both Microsoft based and others, to build workflows using a visual interface to automate actions between systems.

 

While there is currently not an official supported connector in Power Automate for Docebo, you can build your own custom connector using your API knowledge. Once this connector is built, you can share it with others in your organization, allowing them to work with the API without detailed knowledge of it. Cool, right?

 

 

Building the Custom Connector

Here’s how to configure the custom connector:

 

  1. Before going to Office365, go to Docebo and configure a new OAuth2 app for the custom connector, following the same steps as before.
  1. Log into Office365 by going to https://portal.office.com
  1. Using the menu, navigate to ‘Power Automate’.
  1. On the left-hand side, open the ‘Data’ tab.
  1. Select ‘Custom Connectors’.

 

  1. Select ‘New custom connector’.
  1. If you built out a detailed Postman collection, you can choose that option to import. I am going to create from blank to demo the full process.
  1. Give the connector a descriptive and distinctive name.
  1. Select ‘Continue’.
  1. You can choose to upload an icon. I like to do this as it shows up throughout the interface and helps keep things like sandbox vs. production connectors differentiated.
  1. In the ‘Host’ field put <[yoursubdomain].docebosaas.com>
  1. In the ‘Base URL’ put a forward slash. → /

 

 

  1. Select ‘Security’ to move on.
  1. Select ‘OAuth 2.0’ from the type dropdown menu. Fill in the information:
  • Client ID: This should match the client ID you configured in Docebo.

  • Client Secret: This is generated by Docebo when you created the OAuth2 app.

  • Authorization URL: https://<[yoursubdomain].docebosaas.com>/oauth2/authorize

  • Token URL: https://<[yoursubdomain].docebosaas.com>/oauth2/token

  • Refresh URL: https://<[yoursubdomain].docebosaas.com>/oauth2/token

  • Redirect URL: Once you save, this will generate a URL you need to copy and go update the Docebo OAuth2 app with.

     

  1. Select ‘Definition’.
  1. On the right side select ‘New Action’. This is how you define the API to the connector. Let’s add our original example, looking up a user’s information:
  • Summary: Give it a distinctive and descriptive name. This is what will be shown within the application.

  • Description: Add information here that might be useful to know about this request.

  • Operation ID: I generally make this a simpler version of the ‘Summary’ without spaces as they are not allowed.

     

  1. Select ‘Import from sample’ under the ‘Request’ area.
  • Verb: Choose the appropriate action for what you want to do, in this case, ‘Get’.

  • Enter the slug of the URL for the API endpoint, in this case, /manage/v1/user/{user_id}

  1. Select ‘Import’.

 

  1. The URL should load and the appropriate paths, queries, headers, and body details should fill in, in this case just the ‘user_id’ variable. This is important as it will allow us to define it programmatically in the workflow later.
  1. Notice there is a down chevron on the ‘user_id’. Select ‘edit’ from this menu. You can edit and detail as much or as little as you want here. For more complex calls, this can be incredibly useful. For instance you can define values into a dropdown so that you and others do not need to memorize the options. Select ‘Back’ to return to the definition.
  1. Under ‘Response’ select ‘Add default response’.
  1. Copy the example response schema code from the API Browser, or if you have Postman still open, you can grab a sample response from there too. Paste it into the ‘Body’ section.
  1. Select ‘Import’.

 

  1. You will find a ton of new items loaded into the body area. Each one of these can also be edited. Defining these variables is important for ease of use when building within the flow later.

 

  1. Select ‘Create Connector’ or ‘Update Connector’ depending on if this is new or not.

 

You can repeat this process to add more API calls to the connector. I recommend starting with a few simple ones and building a few Flows to get a feel for how the system works. You might develop your own preferences along the way.

 

Example: Using the Connector to Look Up a User’s Information

Now that you have made a custom connector with the ability to request a user’s information, let’s look at how it works within a flow:

 

  1. Log into Office365 by going to https://portal.office.com
  1. Select ‘Create’.
  1. Select ‘Instant cloud flow’. 

We are making a very simple proof of concept flow here. Notice how you can schedule flows or have them start based on other events, as these will be incredibly useful later in this series.

  1. Give it a descriptive name.
  1. Select ‘Manually trigger a flow’.
  1. Select ‘Create’.

 

  1. You will see that the trigger for this flow is a manual step. To add a step, select ‘New Step’.
  1. Under the ‘Custom’ tab, look for your new connector and select ‘Get User Information’ or whatever you named the action.

 

  1. If it is your first time using the custom connector, you will need to sign in to authorize it with the Docebo API and follow the steps on the screen.
  1. Once you have authorized properly, you should see a spot for the ‘User ID’. For now, type in a known Docebo User ID. (In later articles, we will cover how you can use variables to fill this field).
  1. Select ‘New Step’.
  1. Search for and select ‘Send an email’.
  1. Fill in an email address it is okay to send this example to and add a subject.​​​​​​
  1. In the Body area, once you click into it, notice that there is a menu of ‘Dynamic Content’ which matches the response details from the user information you requested in the previous step. Select a few blocks to insert them into the email.

 

  1. Select ‘Save’.
  1. Select ‘Test’.
  1. Select ‘Manually’.
  1. Select ‘Test’.
  1. Select ‘Run Flow’.
  1. After a few seconds, the flow should run successfully, and you should receive the email with the information on the user. Notice that you can open the blocks in the middle of the screen in Power Automate and review what happened at each step as well.

 

 

 

Congratulations, you have successfully created the base of your custom connector and made your first flow!


From here, your abilities are nearly limitless. It’s just a matter of time, creativity, and learning.

 

 

Monitoring, Mitigation, and Maintenance Strategies

Before we really dig in to see what we can do with all these great tools, let’s tap the brakes for just a second. It is incredibly easy to get carried away and start building solutions constantly. While there is nothing wrong with that, I strongly encourage you to balance needs and time, and make sure to factor in the cost of any long-term maintenance by producing a solution. These things will increase over time as you build more, but it is unlikely you will be given more time to manage them.

 

A big piece of using the Docebo API (or really any API) is that it has restrictions. In Docebo’s case this is a soft limit of 1,000 calls per IP address per hour. I know what you’re saying, I want to do so many things and that doesn’t seem like a lot. You are right. But while it is a soft limit, it is best to not blatantly ignore it. With that in mind, you may wish to develop a method to monitor how many calls you are using in any hour. While everyone will have their own solution for this, I can tell you what I do.

 

When I am building workflows in Power Automate that use a lot of calls regularly throughout the day, I build in two things: 

 

  1. A check at the start of the flow to see if a variable I have stored in a SharePoint list shared by all of my workflows is less than 1,000. If it is not, then it waits until the next hour to run.
  1. At the end of any workflow, it updates that same SharePoint variable with how many calls were used.

 

This has been very effective, and I can rest easy that I am not abusing the service and causing issues.

 

Additionally, API’s change, break, get updated, and eventually get deprecated. This means it is vital to be aware of which ones you are using and where. I highly recommend some sort of tracker that shows you- at least the following:

  • The endpoint URL
  • The type of API (GET, DELETE, PUT)
  • Where it is used (I name my workflows, so I use the names, but coming up with a method that is easy to tie back where it is used is important)
  • When it is used (if scheduled, mark the hours in the day it runs)

 

Here is an example of a simple Excel file I use:

 

 

Now this is useful in multiple ways:

  • It is a great document for collaboration on teams to keep an eye on everything and passing knowledge on as you move on to other positions.
  • When building new workflows that you want to schedule, you can see which hours are already being used too much and find appropriate times.
  • Docebo gives a list of upcoming API endpoint changes in the monthly notices. This document makes it super easy to scan for impacts of changes across everything you have built to see what you may need to change.

 

 

A Note on Tools and Ecosystems

I covered a few tools above, which happen to be my personal preference, but that is mostly because I work in an office that has and supports tools like Power Automate and SharePoint in Office365, and Postman is what most of the developers also use. These are not the only tool solutions out there. I strongly encourage you to ask around, see what is available within your organization, make friends with a couple developers and see what they use, etc. 

 

While any tool can be used to some degree, often it is much easier to stay within your company’s ecosystem as it can open doors to interacting with other systems and existing data instead of needing to find workarounds to make it work with things just because I wrote about them here.

 

This is vitally important to keep in mind as we continue our journey. The goal of this series is not to give you purely repeatable steps, but to explain concepts that can be applied regardless of your precise scenario, so you can begin to think about solutions in a different way. 

 

 

What’s Next?

Ok, so the car is packed, time to hit the road.


Next time we will take a look at reports, how they can often help mitigate API limitations, how to manage and edit them, and how to turn them into data feeds for excel dashboards. Get your tools together so that you can play along!

 

Guide Series:

The Art of Being Lazy: Leveraging the API to Take Care of Repetitive Tasks & Fill Feature Gaps

Getting Started: Building Out Your Toolbox [Part 1]

Reports: Sending, modifying, and more!

In the Room When it Happens: Act On Events with Webhooks

Bulk Scheduling ILT Sessions with a CSV File

Tag, You’re It!: Tracking and Managing Content Tags

Let Others Do It: The Power of Forms in a Workflow

And We're Back: How to Let Users have a Form as a Wizard Scheduling Tool

You Built It, They Came, Now What?: Scheduling ILT Wizard Bonus Activities

 


11 replies

Userlevel 7
Badge +7

Um...more please 😋

Userlevel 7
Badge +4

Um...more please 😋

oh, more is coming :)

 

Userlevel 7
Badge +4

Anyone out there who has built their custom connector or is working on one, super curious which API’s were your “Must Haves”?

Let me know in the comments!

Userlevel 3

this is amazing 😮 thanks @Bfarkas !!!!!

Userlevel 7
Badge +4

this is amazing 😮 thanks @Bfarkas !!!!!

Thanks @rebeccam , more to come, the next one all about reports just came out yesterday, make sure to keep an eye out for new ones, or let me know if there's a topic you are interested in to make sure the series works for you!

Userlevel 7
Badge +4

Anyone out there who has built their custom connector or is working on one, super curious which API’s were your “Must Haves”?

Let me know in the comments!

Those who are interested in the Power Automate Custom Connector and don’t want to build it from scratch, we now offer a base version to start with. Right now the focus was on enrollments and scheduling, but we intend to grow its support over time. Also going to make some simple flow recipes for sharing soon too once we gather the feedback on what folks would find useful.

Anyways, readily available for adding now on https://fark.tools

 

Has anyone run into the following error with running the sample flow? 

 

The execution of template action 'Apply_to_each' failed: the result of the evaluation of 'foreach' expression '@outputs('Get_User_Information')?['body/data/items']' is of type 'Null'. The result must be a valid array.

 

 

 


 

 

 

Userlevel 7
Badge +4

What are you trying to do exactly. The call you have is for 1 user’s information, and then you set up a loop to go through a list(array) of items within that user, but it seems like you are just trying to send them an email, you shouldn’t need the items at all, and the error response is that in order to use a looping element, you have to put an array(list) into it, but the [body/data/items] you have in it is empty (null) so it does not know what to loop on.

 

On your ‘Get User Information’ is there anything showing in the ‘raw outputs’? Just curious.

 

Just as an aside, might be better in the future to do this as a new post since troubleshooting this could go quite away from the article’s purpose.

What are you trying to do exactly. The call you have is for 1 user’s information, and then you set up a loop to go through a list(array) of items within that user, but it seems like you are just trying to send them an email, you shouldn’t need the items at all, and the error response is that in order to use a looping element, you have to put an array(list) into it, but the [body/data/items] you have in it is empty (null) so it does not know what to loop on.

 

On your ‘Get User Information’ is there anything showing in the ‘raw outputs’? Just curious.

 

Just as an aside, might be better in the future to do this as a new post since troubleshooting this could go quite away from the article’s purpose.

Thank you for the reply. I was trying to following along on your “Example: Using the Connector to Look Up a User’s Information”. Power automate automatically adds “items” in the step where I’m trying to send an email with some of the user’s information: This is one difference that I noticed from your steps. I think starting a new thread is a good idea.

 

Power Automate flow from adding ‘Apply to each’ automatically:

 

The raw output for ‘Get User Information’:

 

  "statusCode": 200,

    "headers": {

        "Vary": "Accept-Encoding,Origin",

        "Content-Security-Policy": "frame-ancestors 'self' XXXXXXXXXXXXXXXXXXX XXXXXXXXXXX",

        "Access-Control-Expose-Headers": "X-Docebo-Api-Version",

        "X-Docebo-Api-Version": "1.0.0",

        "Access-Control-Allow-Origin": "*",

        "X-UA-Compatible": "IE=Edge,chrome=1",

        "X-Frame-Option": "SAMEORIGIN",

        "X-XSS-Protection": "1",

        "Referrer-Policy": "origin-when-cross-origin",

        "X-Docebo-Backyard": "manage",

        "x-ms-apihub-cached-response": "true",

        "x-ms-apihub-obo": "false",

        "Date": "Mon, 23 Oct 2023 16:15:07 GMT",

        "Content-Type": "application/json; charset=utf-8"

    },

    "body": {

        "data": {

            "user_data": {

                "user_id": "13036",

                "username": "XXXXXXXX",

                "first_name": "XXXXXXXX",

                "last_name": "XXXXXXXX",

                "email": "XXXXXXXX",

                "uuid": "XXXXXXXXX",

                "lang_code": "english",

                "lang_browsercode": "en",

                "force_change": "0",

                "expiration": null,

                "email_validation_status": "1",

                "valid": "1",

                "avatar": "",

                "can_manage_subordinates": false,

                "is_saml_provision": "0",

                "language": "english",

                "newsletter_optout": "0",

                "newsletter_optout_date": null,

                "level": "3",

                "date_format": null,

                "timezone": "America/Edmonton",

                "manager_first_name": "XXXXXXXXXX",

                "manager_last_name": "XXXXXXXXXX",

                "manager_username": "XXXXXXXXXX",

                "manager_id": "13748",

                "cant_have_direct_manager": false,

                "spu_edit_mode": null

            },

            "additional_fields": [

                {

                    "id": "1",

                    "title": "Job Title",

                    "type": "textfield",

                    "mandatory": false,

                    "invisible_to_user": false,

                    "settings": null,

                    "sequence": 1,

                    "value": "XXXXXXXXXXXX",

                    "enabled": true

                },

                {

                    "id": "2",

                    "title": "Branch",

                    "type": "textfield",

                    "mandatory": false,

                    "invisible_to_user": false,

                    "settings": null,

                    "sequence": 2,

                    "value": "XXXXXXXXXX",

                    "enabled": true

                },

                {

                    "id": "3",

                    "title": "XXXXXXXXXXX",

                    "type": "textfield",

                    "mandatory": false,

                    "invisible_to_user": true,

                    "settings": null,

                    "sequence": 3,

                    "value": "",

                    "enabled": true

                },

                {

                    "id": "4",

                    "title": "Object Identifier",

                    "type": "textfield",

                    "mandatory": false,

                    "invisible_to_user": true,

                    "settings": null,

                    "sequence": 4,

                    "value": "XXXXXXXXXXX",

                    "enabled": true

                }

            ],

            "branches": [

                {

                    "id": 17,

                    "iLeft": 27,

                    "iRight": 28

                }

            ],

            "saml_settings": {

                "unique_field": "username",

                "lock_provisioned_user_fields": 0,

                "provisioned_user_fields": {

                    "1": "http://schemas.xmlsoap.org/ws/2005/05/identity/claims/jobtitle",

                    "2": "http://schemas.xmlsoap.org/ws/2005/05/identity/claims/department",

                    "4": "http://schemas.microsoft.com/identity/claims/objectidentifier",

                    "firstname": "http://schemas.xmlsoap.org/ws/2005/05/identity/claims/givenname",

                    "lastname": "http://schemas.xmlsoap.org/ws/2005/05/identity/claims/surname",

                    "email": "http://schemas.xmlsoap.org/ws/2005/05/identity/claims/emailaddress"

                }

            }

        },

        "version": "1.0.0",

        "_links": []

Userlevel 7
Badge +4

That is interesting, the ‘items’ in the apply to each should only apply if there is an array in the response, so that it looks for each user for instance, like when you look up a list of users, but your output does not even show an items array, so seems to not be there. For the individual get user info, shouldn’t need it and just the users info should go straight into the email.

That is interesting, the ‘items’ in the apply to each should only apply if there is an array in the response, so that it looks for each user for instance, like when you look up a list of users, but your output does not even show an items array, so seems to not be there. For the individual get user info, shouldn’t need it and just the users info should go straight into the email.

There’s something definitely odd going on. I’ll start a new thread as this looks like it may require more attention. 

Reply