1. Home
  2. Docs
  3. Integrations
  4. Learn about Desk365 integ...
  5. Integrate Desk365 with Power BI

Integrate Desk365 with Power BI

Integrating Desk365 with Power BI is a straightforward process that involves a few simple steps. You need to import the data from Desk365 into Power BI with the help of the Desk365 API and then you can transform it into customized, impactful reports using Power Query with pagination, which enables data cleansing, shaping, and combining data from multiple sources. And then you can filter the tickets within the report in Power BI. 

By the end of this help center article, you’ll be able to create interactive reports and dashboards that provide valuable insights into your customer support operations. 

Step 1: Establish connection with Desk365's API

To initiate the integration of Desk365 with Power BI, you have to establish a connection with Desk365’s API from Power BI. To do that navigate to your Power BI tool and perform the following actions. 

  1. Select Web from common data sources under Get data.
import-data-from-web-page-desk365

2. Click on Advanced and fill in the details as mentioned below. 

Enter the below link in URL parts.

				
					https://<<yoursubdomain>>.desk365.io/apis/v3/tickets
				
			

Under HTTP request header parameters, type the value as ‘Authorization‘ and set the value to ‘<<YOUR-DESK365’S-API-KEY>>‘ as shown below and click on ‘Ok’.

enter-url-parts-desk365-power-bi

3. As the next step, select the same link mentioned earlier in the ‘Access Web content’ pop-up and click ‘Connect’.

integrate-desk365-with-power-bi

Your Power BI is now successfully connected to Desk365’s API. 

Step 2: Create a function

The second step to integrate Desk365 with Power BI is to create a function. This function facilitates the retrieval of tickets and their corresponding details from Desk365.

Follow the below steps:

1. Navigate to your Power BI platform. 

2. Select Blank query under Get data as shown below.

create-a-function-desk365-power-bi

The Power Query Editor window will open with a new blank query. From there, go to the Power Query Home menu and choose the Advanced Editor option.

select-advanced-editor-desk365

Copy and insert the code from Step 3 into the Advanced Editor as shown below.

desk365-power-bi-integration

Step 3: Use the advanced editor for data transformation

After establishing the connection, import the tickets using the below code snippet.  

				
					let
    // Base URL and API Key for the API requests
    BaseUrl = "https://yoursubdomain.desk365.io/apis/v3/",
    ApiKey = "<<YOUR-DESK365-API-KEY>>",
    // Number of tickets per page (possible values: 30, 50, 100)
    TicketCount = 30,
 
    // Query parameters for fetching tickets, including custom fields, survey details, and activity since a specific time
    QueryParams = [
        ticket_count = Text.From(TicketCount),     // Include tickets per page
        include_description = "0",                 // Include description in the response
        include_custom_fields = "0",               // Include custom fields in the response
        include_survey_details = "0",              // Include survey details in the response
        order_by = "created_time",                 // Sort tickets by "created_time" or "updated_time"
        order_type = "desc",                       // Specify the sorting order "asc" (ascending) or "desc" (descending)
        updated_since = "2024-11-01 08:48:06"      // Filter tickets with activity since the specified timestamp
    ],
 
    // Function to Fetch a Single Page of Data
    FetchPage = (offset as number) =>
        try
            Json.Document(Web.Contents(
                BaseUrl,
                [
                    RelativePath = "tickets",
                    Query = Record.Combine({[offset = Text.From(offset)] & QueryParams}), // Combine base query and custom query params
                    Headers = [Authorization = ApiKey]
                ]
            ))
        otherwise [tickets = {}, next_page = null, count = 0], // Default response in case of error
 
    // Fetch initial data to get the total count
    Source = FetchPage(0),
    TotalTickets = if Source = null or not Record.HasFields(Source, "count") then 0 else Source[#"count"],
 
    // Calculate the number of pages needed
    PageCount = Number.RoundUp(TotalTickets / TicketCount),
 
   // Generate a list of offsets for each page, using PageCount to limit the number of iterations
    PagesData = List.Generate(
        // Start with the first page's response
        () => [Page = 0, Response = Source], // Fetch the first page only once here
        each [Page] < PageCount, // Limit the iteration to PageCount
        each [
            Page = [Page] + 1,                       // Increment the page counter by 1
            Response = FetchPage(Page * TicketCount) // Fetch the next page using the updated offset (Page * TicketCount)
        ],
        each [
            Count = [Response][count],    // Extract the total count of tickets
            Tickets = [Response][tickets] // Extract the list of tickets from the response
        ]
    ),
 
    // Flatten the list of tickets and include the count
    FlattenedTicketsWithCount = List.Transform(PagesData, each List.Transform([Tickets], (ticket) => Record.AddField(ticket, "count", [Count]))),
 
    // Combine all tickets from each page into one list
    CombinedTickets = List.Combine(FlattenedTicketsWithCount),
 
    // Convert the list of records into a table
    TicketsTable = Table.FromRecords(CombinedTickets),
 
    // Select specific columns from the tickets table that are needed
    SelectedColumnsTable  = Table.SelectColumns (
        TicketsTable,
        {
            "count",
            "ticket_number",
            "contact_email",
            "subject",
            "description",
            "description_text",
            "status",
            "priority",
            "type",
            "source",
            "assigned_to",
            "sla",
            "group",
            "category",
            "subcategory",
            "created_on",
            "updated_on",
            "resolved_on",
            "closed_on",
            "due_date",
            "first_response_time",
            "first_assigned_time",
            "first_assigned_duration",
            "resolved_duration",
            "first_replied_duration",
            "closed_duration",
            "custom_fields",
            "survey_rating"
        },
        MissingField.Ignore
    ),
 
    // Expand custom fields object to get detailed values from the "custom_fields" record
    CustomFieldsExist = if Table.IsEmpty(SelectedColumnsTable) then 
                            false 
                        else 
                            List.Contains(Record.FieldNames(SelectedColumnsTable{0}), "custom_fields"),
    ExpandedCustomFields = if CustomFieldsExist then
        Table.ExpandRecordColumn (
            SelectedColumnsTable,
            "custom_fields",
            // Expanding the required custom fields 
            {
                "cf_Test dropdown", 
                "cf_Test date", 
                "cf_Text", 
                "cf_Paragraph Test",
                "cf_Sports",
                "cf_Teams",
                "cf_Players"
            },
            // Renaming the custom fields
            {
                "Test dropdown", 
                "Test date", 
                "Text", 
                "Paragraph Test",
                "Sports",
                "Teams",
                "Players"
            }
        )
    else
        SelectedColumnsTable,
 
    // Expand survey rating object to get detailed survey response data
    SurveyDetailsExist = if Table.IsEmpty(ExpandedCustomFields) then 
                            false 
                        else 
                            List.Contains(Record.FieldNames(ExpandedCustomFields{0}), "survey_rating"),
    ExpandedSurveyDetails = if SurveyDetailsExist then
        Table.ExpandRecordColumn (
            ExpandedCustomFields,
            "survey_rating",
            // Expanding the required survey details
            {
                "sv_name",
                "sv_answered",
                "sv_type",
                "sv_cs_scale",
                "sv_cs_neutral_type",
                "sv_agent_assigned",
                "sv_question",
                "sv_rating",
                "sv_additional_comments_title",
                "sv_additional_comments_response",
                "sv_sent_on",
                "sv_rated_on",
                "sv_default_rating",
                "sv_cs_question_2",
                "sv_cs_rating_2",
                "sv_cs_question_3",
                "sv_cs_rating_3"
            },
            // Renaming the survey details
            {
                "Survey Name",
                "Survey Answered",
                "Survey Type",
                "Customer Service Scale",
                "Neutral Type",
                "Agent Assigned",
                "Survey Question",
                "Survey Rating",
                "Additional Comments Title",
                "Additional Comments Response",
                "Survey Sent On",
                "Survey Rated On",
                "Default Rating",
                "Customer Service Question 2",
                "Customer Service Rating 2",
                "Customer Service Question 3",
                "Customer Service Rating 3"
            }
        )
    else
        ExpandedCustomFields,
 
    // Rename the selected columns for clarity
    RenamedColumnsTable = Table.RenameColumns (
        ExpandedSurveyDetails,
        {
            {"ticket_number", "Ticket Number"},
            {"contact_email", "Contact Email"},
            {"subject", "Subject"},
            {"description", "Description"},
            {"description_text", "Description Text"},
            {"status", "Status"},
            {"priority", "Priority"},
            {"type", "Type"},
            {"source", "Source"},
            {"assigned_to", "Assigned To"},
            {"sla", "SLA"},
            {"group", "Group"},
            {"category", "Category"},
            {"subcategory", "Subcategory"},
            {"created_on", "Created On"},
            {"updated_on", "Updated On"},
            {"resolved_on", "Resolved On"},
            {"closed_on", "Closed On"},
            {"due_date", "Due Date"},
            {"first_response_time", "First Response Time"},
            {"first_assigned_time", "First Assigned Time"},
            {"first_assigned_duration", "First Assigned Duration"},
            {"resolved_duration", "Resolved Duration"},
            {"first_replied_duration", "First Replied Duration"},
            {"closed_duration", "Closed Duration"}
        },
        MissingField.Ignore
    )
in
    RenamedColumnsTable

				
			

1. Base URL 

The Base URL is the starting point for all API requests. Replace yoursubdomain with your Desk365 helpdesk domain: 

https://<<yoursubdomain>>.desk365.io/apis/v3/ 

2. API key 

Your API key authenticates the requests to Desk365. Find your unique API key in the Desk365 portal: 

  • Go to Settings > Integrations > API and copy your API key. 

Replace the placeholder <<YOUR-DESK365’S-API-KEY>> in the code with your actual API key. 

accessing-desk365-api-key

3. Ticket count 

The ticket_count parameter determines how many tickets are retrieved per API call. You can choose from the following values: 

  • 30, 50, or 100 tickets per API call. 
  • The maximum limit for ticket retrieval is 10,000 tickets per hour. 

4. Query parameters 

The Desk365 API includes several query parameters that allow you to retrieve and customize the data based on your reporting and analytical needs. Here’s a detailed explanation of each parameter: 

  • include_description 

The description parameter in the Desk365 API not only controls whether ticket descriptions are included in the response but also provides flexibility in the format of the ticket details retrieved. 

				
					include_description = "1",                 // Include description in the response
				
			

When enabled, the API offers two distinct fields for ticket descriptions:

1. Description (HTML) – The description field contains the full content of the ticket’s description in HTML format. This field preserves any formatting applied to the text, such as bold, italic, lists, links, or other HTML elements.

2. Description text (Plain text) – The description_text field provides the plain text version of the ticket description, stripping away all HTML tags and presenting only the raw content.

  • include_custom_fields 

The include_custom_fields parameter enables the retrieval of additional, customized data associated with tickets in Desk365. By default, this parameter is set to 0, meaning custom fields are excluded from the API response. To include custom field data, set the parameter to 1.

				
					include_custom_fields = "1",              // Include custom fields in the response
				
			

Custom fields in Desk365 are uniquely identified by the prefix cf_ (e.g., cf_Players, cf_Sports). This ensures that these fields are easily distinguishable in the dataset and simplifies the process of mapping them to specific filters or analytics in Power BI.

Desk365 empowers users to define their own custom ticket fields to capture essential information beyond standard fields. Custom fields can be created in the Desk365 agent portal under Settings > Admin > Ticket Fields. 

When working with data in Power BI, you can further refine the report by selecting only the necessary custom fields from the API response. This is achieved by expanding the “custom_fields” object in the table. For example, you can choose to include fields like cf_Paragraph Test or cf_Teams and exclude others, ensuring your dataset remains streamlined and focused on relevant metrics.

				
					// Expand custom fields object to get detailed values from the "custom_fields" record
    CustomFieldsExist = if Table.IsEmpty(SelectedColumnsTable) then 
                            false 
                        else 
                            List.Contains(Record.FieldNames(SelectedColumnsTable{0}), "custom_fields"),
    ExpandedCustomFields = if CustomFieldsExist then
        Table.ExpandRecordColumn (
            SelectedColumnsTable,
            "custom_fields",
            // Expanding the required custom fields 
            {
                "cf_Test dropdown", 
                "cf_Test date", 
                "cf_Text", 
                "cf_Paragraph Test",
                "cf_Sports",
                "cf_Teams",
                "cf_Players"
            },
				
			
  • include_survey_details 

The include_survey_details parameter allows you to retrieve customer feedback collected through surveys as part of the API response. By default, this parameter is set to 0, meaning survey data is excluded. To include survey feedback, set this parameter to 1.

				
					include_survey_details = "1",            // Include survey details in the response
				
			

Survey fields in the API response are prefixed with sv_ (e.g., sv_rating, sv_question) for easy identification. These fields provide valuable insights into customer satisfaction, service quality, and agent performance. You have the flexibility to tailor the survey data included in your reports. By selectively expanding only the required survey fields, you can focus on the metrics that are most relevant to your analysis. For example, you might include only sv_rating and sv_question to track customer ratings and their corresponding queries, while excluding other fields to keep the dataset concise.

				
					// Expand survey rating object to get detailed survey response data
    SurveyDetailsExist = if Table.IsEmpty(ExpandedCustomFields) then 
                            false 
                        else 
                            List.Contains(Record.FieldNames(ExpandedCustomFields{0}), "survey_rating"),
    ExpandedSurveyDetails = if SurveyDetailsExist then
        Table.ExpandRecordColumn (
            ExpandedCustomFields,
            "survey_rating",
            // Expanding the required survey details
            {
                "sv_name",
                "sv_answered",
                "sv_type",
                "sv_cs_scale",
                "sv_cs_neutral_type",
                "sv_agent_assigned",
                "sv_question",
                "sv_rating",
                "sv_additional_comments_title",
                "sv_additional_comments_response",
                "sv_sent_on",
                "sv_rated_on",
                "sv_default_rating",
                "sv_cs_question_2",
                "sv_cs_rating_2",
                "sv_cs_question_3",
                "sv_cs_rating_3"
            },
				
			
  • Sorting parameters 

order_by 

The order_by parameter defines the attribute by which tickets are sorted. You can choose to sort tickets based on either their created_time (the date and time a ticket was opened) or their updated_time (the date and time the ticket was last modified). This helps prioritize the data display based on your reporting objectives. For instance, sorting by created_time is useful for analyzing ticket volume over a period, while sorting by updated_time helps monitor ongoing or recently resolved tickets. 

				
					order_by = "created_time",  // Sort tickets by "created_time" or "updated_time"
				
			

order_type 

The order_type parameter specifies the direction of sorting: 

  • Use asc for ascending order. This will display the oldest tickets first. 
  • Use desc for descending order. This will display the newest tickets first. 

Combining order_by with order_type provides flexibility in how tickets are organized, making it easier to focus on specific data subsets like newly created tickets or recently updated ones. 

				
					order_type = "desc",     // Specify the sorting order "asc" (ascending) or "desc" (descending)
				
			
  • Filtering tickets by date and time using the “updated_since” parameter

If you want to retrieve tickets updated after a specific date and time, simply use the “updated_since” parameter in this format “yyyy-mm-dd hh:mm:ss” into your code within the advanced editor for both functions. This addition ensures that only tickets updated from the specified date will be displayed. 

				
					updated_since = "yyyy-mm-dd hh:mm:ss"   // Filter tickets with activity since the specified timestamp
				
			

Note: When using “updated_since” parameter indicate the specific date and time from which you want to showcase your tickets such as “updated_since=2024-11-01 00:00:00”. 

Integrate Desk365 with other applications using the Desk365 API.

Explore our endpoints ranging from

Tickets

Contacts

Companies

Time entries

Surveys

Contracts

Impactful reports from raw data

Finally, you can use the Power BI tool to transform these raw data into actionable insights, enabling better decision-making, data-driven strategies, and improved business performance.  

For instance, here you may see the sample report generated for ‘No. of tickets vs status‘ 

power-bi-number-of-tickets-vs-status

Here is another report depicting the bar graph for ‘No. of tickets vs groups‘. 

power-bi-number-of-tickets-vs-grouppower-bi-number-of-tickets-vs-group

Integrating Desk365 with Power BI is a strategic move for any organization looking to leverage its helpdesk data for better customer support and operational efficiency. Embrace the power of data, and watch your customer support operations reach new heights with Desk365 and Power BI integration. 

Require additional assistance? Please reach out to us at help@desk365.io

How can we help?