Forum Discussion

micheloesoldi's avatar
micheloesoldi
New Member
10 months ago
Solved

Can’t get ClickUp API connection to work in Power BI Service with scheduled refresh

Hi! I need this dashboard to refresh on a schedule, but I can’t get it to work in Power BI Service.
It seems that the token in the header causes security issues.
I’ve tried using the token as a parameter, but that doesn’t work either.
I’m currently using an anonymous connection, but I’ve also tried other connection types without success.


Data source error
It looks like the scheduled refresh failed because at least one data source is missing credentials.
To start the refresh again, go to the settings page for this dataset and enter the credentials for all data sources.

Cluster URI: WABI-BRAZIL-SOUTH-B-PRIMARY-redirect.analysis.windows.net
Activity ID: 00000000-0000-0000-0000-000000000000
Request ID: d344f059-bc9b-4009-bd9b-fcceff03bbe0
Time: 2025-10-23 17:11:04Z


Code:
let

// ======= CONFIGURAÇÕES =======

team_id = "      ",

token = ClickUp_API_Token, //token

space_ids = {"    ", "    ", "    ", "    "},

baseUrl = "https://api.clickup.com/",

 

// ======= FUNÇÃO PARA BUSCAR UMA PÁGINA =======

GetPage = (space as text, page as number) =>

let

fonte =

try

Json.Document(

Web.Contents(

baseUrl,

[

RelativePath = "api/v2/team/" & team_id & "/task",

Query = [

include_closed = "true",

include_subtasks = "true",

archived = "false",

page = Number.ToText(page),

#"space_ids[]" = space,

fields = "id,name,status,date_done,due_date,start_date,url,list,folder,space"

],

Headers = [Authorization = token]

]

)

)

otherwise null,

 

tarefas = if fonte <> null and Record.HasFields(fonte, "tasks") then fonte[tasks] else {},

tabela = if List.Count(tarefas) > 0 then Table.FromList(tarefas, Splitter.SplitByNothing(), {"tasks"}) else #table({"tasks"}, {})

in

tabela,

 

// ======= FUNÇÃO PARA PAGINAR AUTOMATICAMENTE =======

GetAllPages = (space as text) =>

let

FirstPage = GetPage(space, 0),

AllPages =

List.Generate(

() => [Page = 0, Data = FirstPage],

each Table.RowCount([Data]) > 0,

each [

Page = [Page] + 1,

Data = Function.InvokeAfter(() => GetPage(space, [Page] + 1), #duration(0, 0, 0, 0.5))

],

each [Data]

),

Combined = try Table.Combine(AllPages) otherwise #table({"tasks"}, {})

in

Combined,

 

// ======= LOOP EM TODOS OS ESPAÇOS =======

AllSpaces = List.Transform(space_ids, each GetAllPages(_)),

CombinedAll = try Table.Combine(AllSpaces) otherwise #table({"tasks"}, {}),

  • vojtechsima's avatar
    vojtechsima
    10 months ago

    micheloesoldi  the only thing that comes to my mind is that you have try on the whole call. Put the error handling after the call, so the call will always run, and you handle only the response.

5 Replies

  • Hey, micheloesoldi ,

    The code looks good. You split the base URL and the relative path, and you use authroization header.

    With this setup, you MUST use the Anonymous connection type. Make sure the semantic model settings in workspace is also set up to Anonymous and you can also check Skip the test.


    I would also align all Privacy levels to Organizational, for example, if you use multiple sources in your semantic model.

     

    For more details, you can try checking my blog, where I cover API Authentication in Power Query :
    https://www.vojtechsima.com/post/api-authentication-in-power-query

    • micheloesoldi's avatar
      micheloesoldi
      New Member

      Hey @vojtechsima,

      Thanks for the feedback!

      I forgot to mention earlier, but I’ve already set the Privacy level to Organizational for all sources, and the semantic model in the workspace is also configured that way.

      I did try using the Skip the test option, but I couldn’t get the code to run properly. Could you help me figure out what might be going wrong?

      Thanks again!

      • vojtechsima's avatar
        vojtechsima
        Icon for Super User rankSuper User

        micheloesoldi  the only thing that comes to my mind is that you have try on the whole call. Put the error handling after the call, so the call will always run, and you handle only the response.