APIs & Integrations

Brodie1
Member

Pagination using Power BI

Hi Team,

I'm currently using this query in MS Power Query, you can copy and paste, I've substituted the 'demo' key for mine.

let

     Pagination = List.Skip(List.Generate( () => [Last_Key = "init", Counter=0], // Start Value
   		each  [Last_Key] <> null, // Condition under which the next execution will happen
   		each [ Last_Key = try if [Counter]<1 then "" else [WebCall][Value][offset] otherwise null,// determine the LastKey for the next execution
                                             WebCall = try if [Counter]<1 then Json.Document(Web.Contents("https://api.hubapi.com/contacts/v1/lists/all/contacts/all?hapikey=demo&count=250"))  else Json.Document(Web.Contents("https://api.hubapi.comts/all/contacts/all?hapikey=demo&count=250&vidOffset="&Last_Key&"")), // retrieve results per call
    		       Counter = [Counter]+1// internal counter
                      ],
   		each [WebCall]
 ),1),
    Pagination1 = Pagination{0},
    Value = Pagination1[Value],
    contacts = Value[contacts]
in
    contacts

I can not make it paginate. One issue I'm having is if I declare [offset] to [vid-offset] I can an invalid identifier error. I believe this is the source of my problem but can't figure out a workaround. Would appreciate the help,

thanks

link to documentation API Doc for Contacts

0 Upvotes
11 Replies 11
JMillere
Participant

Pagination using Power BI

Hi,

 

To fix this issue, you can try changing the following line of code:

 

WebCall = try if [Counter]<1 then Json.Document(Web.Contents("https://api.hubapi.com/contacts/v1/lists/all/contacts/all?hapikey=demo&count=250")) else Json.Document(Web.Contents("https://api.hubapi.comts/all/contacts/all?hapikey=demo&count=250&vidOffset=PowerBI"&Last_Key&"")),

 

to:

 

WebCall = try if [Counter]<1 then Json.Document(Web.Contents("https://api.hubapi.com/contacts/v1/lists/all/contacts/all?hapikey=demo&count=250")) else Json.Document(Web.Contents("https://api.hubapi.com/contacts/v1/lists/all/contacts/all?hapikey=demo&count=250&vid-offset="&Last_Key&"")),

 

Notice the change in the URL parameter from "vidOffset" to "vid-offset". This should resolve the issue of the invalid identifier error and allow you to paginate through the API results.

 

Apart from this, you can adjust the count parameter to increase or decrease the number of contacts returned per API call. This can help optimize the pagination process and reduce the number of API calls required to retrieve all of the results.

 

I hope this helps! Let me know if you have any further questions.

 

Thanks

0 Upvotes
a2
Member

Pagination using Power BI

Hi All, 

 

Managed to solve pagination with hAPI key

baseurlContacts = https://api.hubapi.com/crm/v3/objects/contacts?limit=100&archived=false&hapikey=

apikey = whateveryourAPIkeyis

 

its all based on this example by wjones from the PBI community:

https://community.powerbi.com/t5/Power-Query/Handling-a-Paginated-API-with-Prebuilt-Next-Page-URI-in...

 

 

 

let
baseuri = baseurlContacts & apikey,

initReq = Json.Document(Web.Contents(baseuri)),

initData = initReq[results],

//We want to get data = {lastNPagesData, thisPageData}, where each list has the limit # of Records,

//then we can List.Combine() the two lists on each iteration to aggregate all the records. We can then

//create a table from those records

gather = (data as list, uri) =>

let
//get new offset from active uri
newOffset = Json.Document(Web.Contents(uri))[paging][next][after],

//build new uri using the original uri so we dont append offsests
newUri = baseuri & "&after=" & newOffset,

//get new req & data
newReq = Json.Document(Web.Contents(newUri)) ,
newdata = newReq[results] ,

//add that data to rolling aggregate
data = List.Combine({data, newdata}),

//if theres no next page of data, return. if there is, call @gather again to get more data

check = if Table.Contains ( Record.ToTable(newReq) , [Name = "paging"] ) = true then @gather (data , newUri) else data

in check,

//before we call gather(), we want see if its even necesarry. First request returns only one page? Return.
outputList = if Table.Contains ( Record.ToTable (initReq) , [Name = "paging"] ) = true then gather( initData , baseuri ) else initData ,

//then place records into a table. This will expand all columns available in the record.
expand = Table.FromRecords(outputList)



in 



expand

 

 

 

0 Upvotes
MwM
Member

Pagination using Power BI

hi @a2 ,
Any idea how to use your example in the Power BI Service?
As it's dynamic, I'm guessing you need to use the relative path feature of Web.Contents but I'm struggling to see where to implement this?
Thanks

0 Upvotes
GPfeifferling
Participant

Pagination using Power BI

I got all the data I need and the table works the way I need it to; my only problem remains pagination. this is using the V3 API.

 

Any idea how this can be solved?

 

let
Source = Json.Document(Web.Contents("https://api.hubapi.com/crm/v3/objects/line_items?limit=100&properties=name%2Chs_product_id%2Chs_sku%...")),
#"Converted to Table" = Table.FromRecords({Source}),
#"Expanded results" = Table.ExpandListColumn(#"Converted to Table", "results"),
#"Expanded results1" = Table.ExpandRecordColumn(#"Expanded results", "results", {"id", "properties", "createdAt", "updatedAt", "archived", "associations"}, {"results.id", "results.properties", "results.createdAt", "results.updatedAt", "results.archived", "results.associations"}),
#"Expanded results.properties" = Table.ExpandRecordColumn(#"Expanded results1", "results.properties", {"amount", "createdate", "hs_acv", "hs_arr", "hs_lastmodifieddate", "hs_object_id", "hs_product_id", "hs_sku", "name", "price", "product_number", "quantity", "type"}, {"results.properties.amount", "results.properties.createdate", "results.properties.hs_acv", "results.properties.hs_arr", "results.properties.hs_lastmodifieddate", "results.properties.hs_object_id", "results.properties.hs_product_id", "results.properties.hs_sku", "results.properties.name", "results.properties.price", "results.properties.product_number", "results.properties.quantity", "results.properties.type"}),
#"Expanded results.associations" = Table.ExpandRecordColumn(#"Expanded results.properties", "results.associations", {"deals"}, {"results.associations.deals"}),
#"Expanded results.associations.deals" = Table.ExpandRecordColumn(#"Expanded results.associations", "results.associations.deals", {"results"}, {"results.associations.deals.results"}),
#"Expanded paging" = Table.ExpandRecordColumn(#"Expanded results.associations.deals", "paging", {"next"}, {"paging.next"}),
#"Expanded paging.next" = Table.ExpandRecordColumn(#"Expanded paging", "paging.next", {"after", "link"}, {"paging.next.after", "paging.next.link"}),
#"Changed Type" = Table.TransformColumnTypes(#"Expanded paging.next",{{"results.id", Int64.Type}, {"results.properties.amount", Int64.Type}, {"results.properties.createdate", type datetime}, {"results.properties.hs_acv", Int64.Type}, {"results.properties.hs_arr", Int64.Type}, {"results.properties.hs_lastmodifieddate", type datetime}, {"results.properties.hs_object_id", Int64.Type}, {"results.properties.hs_product_id", Int64.Type}, {"results.properties.hs_sku", type any}, {"results.properties.name", type text}, {"results.properties.price", type number}, {"results.properties.product_number", type text}, {"results.properties.quantity", Int64.Type}, {"results.properties.type", type text}, {"results.createdAt", type datetime}, {"results.updatedAt", type datetime}, {"results.archived", type logical}, {"results.associations.deals.results", type any}, {"paging.next.after", Int64.Type}, {"paging.next.link", type text}}),
#"Expanded results.associations.deals.results" = Table.ExpandListColumn(#"Changed Type", "results.associations.deals.results"),
#"Expanded results.associations.deals.results1" = Table.ExpandRecordColumn(#"Expanded results.associations.deals.results", "results.associations.deals.results", {"id"}, {"results.associations.deals.results.id"}),
#"Removed Other Columns" = Table.SelectColumns(#"Expanded results.associations.deals.results1",{"results.id", "results.properties.amount", "results.properties.hs_acv", "results.properties.hs_arr", "results.properties.hs_object_id", "results.properties.hs_product_id", "results.properties.hs_sku", "results.properties.name", "results.properties.price", "results.properties.product_number", "results.properties.quantity", "results.properties.type", "results.associations.deals.results.id", "paging.next.after", "paging.next.link"}),
#"Renamed Columns" = Table.RenameColumns(#"Removed Other Columns",{{"results.properties.quantity", "qty"}, {"results.properties.product_number", "SKU"}, {"results.properties.name", "Name"}, {"results.properties.type", "Type"}})
in
#"Renamed Columns"

0 Upvotes
coskunfirat
Participant

Pagination using Power BI

Hi all,

When I tray go get all contacts data I can only see 500 records.

I have connected via web sources by using json api https://api.hubapi.com/contacts/v1/lists/all/contacts/all?hapikey=XXX-XXX-XXX&count=2000

How can I make pagination it in the Power BI.

let
Kaynak = Json.Document(Web.Contents("https://api.hubapi.com/companies/v2/companies/paged?hapikey=**********&properties=name&properties=website")),
#"Tabloya Dönüştürüldü" = Table.FromRecords({Kaynak}),
#"Genişletilen companies" = Table.ExpandListColumn(#"Tabloya Dönüştürüldü", "companies"),
#"Genişletilen companies1" = Table.ExpandRecordColumn(#"Genişletilen companies", "companies", {"portalId", "companyId", "isDeleted", "properties", "additionalDomains", "stateChanges", "mergeAudits"}, {"companies.portalId", "companies.companyId", "companies.isDeleted", "companies.properties", "companies.additionalDomains", "companies.stateChanges", "companies.mergeAudits"}),
#"Genişletilen companies.properties" = Table.ExpandRecordColumn(#"Genişletilen companies1", "companies.properties", {"website", "name"}, {"companies.properties.website", "companies.properties.name"}),
#"Genişletilen companies.properties.website" = Table.ExpandRecordColumn(#"Genişletilen companies.properties", "companies.properties.website", {"value", "timestamp", "source", "sourceId", "updatedByUserId", "versions"}, {"companies.properties.website.value", "companies.properties.website.timestamp", "companies.properties.website.source", "companies.properties.website.sourceId", "companies.properties.website.updatedByUserId", "companies.properties.website.versions"}),
#"Genişletilen companies.properties.name" = Table.ExpandRecordColumn(#"Genişletilen companies.properties.website", "companies.properties.name", {"value", "timestamp", "source", "sourceId", "updatedByUserId", "versions"}, {"companies.properties.name.value", "companies.properties.name.timestamp", "companies.properties.name.source", "companies.properties.name.sourceId", "companies.properties.name.updatedByUserId", "companies.properties.name.versions"}),
#"Değiştirilen Tür" = Table.TransformColumnTypes(#"Genişletilen companies.properties.name",{{"has-more", type logical}, {"offset", Int64.Type}, {"companies.portalId", Int64.Type}, {"companies.companyId", Int64.Type}, {"companies.isDeleted", type logical}, {"companies.properties.website.value", type text}, {"companies.properties.website.timestamp", Int64.Type}, {"companies.properties.website.source", type text}, {"companies.properties.website.sourceId", type any}, {"companies.properties.website.updatedByUserId", type any}, {"companies.properties.website.versions", type any}, {"companies.properties.name.value", type text}, {"companies.properties.name.timestamp", Int64.Type}, {"companies.properties.name.source", type text}, {"companies.properties.name.sourceId", Int64.Type}, {"companies.properties.name.updatedByUserId", type any}, {"companies.properties.name.versions", type any}, {"companies.additionalDomains", type any}, {"companies.stateChanges", type any}, {"companies.mergeAudits", type any}})
in
#"Değiştirilen Tür"



Thanks in advance.

0 Upvotes
JonesTrac
Member

Pagination using Power BI

Thanks @snamuth this is really useful. It also works for the companies API. Just a quick note that if you want this to work in the PowerBI service you will need to use the relative path feature of Web.Contents as below

each [WebCall = Json.Document(Web.Contents("https://api.hubapi.com",
[
RelativePath="companies/v2/companies/paged?hapikey=*****&limit=250&properties=name&properties=city&offset=" & Text.From([Last_Key])
]
)),

Last_Key = try [WebCall][#"offset"] otherwise 0,
IsMore = if [Counter] < 1 then null else [WebCall][#"has-more"],
Counter = [Counter]+1,
Table = Table.FromRecords(WebCall[companies])
]

One thing I have noticed is that this seems to return duplicate companies (each company appears twice). Also when debugging this query PowerBI is calling the API twice each loop (ie. each offset is called twice). Do you have any idea why this is?

cbarley
HubSpot Alumni
HubSpot Alumni

Pagination using Power BI

Thanks so much for the reply @snamuth! This is awesome. Hopefully this solves your issue here, @Brodie

snamuth
Participant

Pagination using Power BI

Hi @Brodie,

Here is what I use and it works in Power BI.

let
Pagination = List.Skip(List.Generate( () => [IsMore = null, Last_Key = 0, Counter = 0], // Start Value
each [IsMore] <> false,// Whilst this is true, keep going
each [WebCall = Json.Document(Web.Contents("https://api.hubapi.com/contacts/v1/lists/all/contacts/all?" & "hapikey=******" & "&property=firstname" & "&property=lastname" & "&property=createdate" & "&property=email" & "&propertyMode=value_and_history" & "&count=100" & "&vidOffset="&Text.From([Last_Key])&"", [Headers=[ContentType="application/json", Authorization="Bearer Token"]])),// retrieve results per call
Last_Key = try [WebCall][#"vid-offset"] otherwise 0,
IsMore = if [Counter] < 1 then null else [WebCall][#"has-more"],
Counter = [Counter]+1,
Table = Table.FromRecords(WebCall[contacts])
]
,each [Table] // selector
) ,1)

// in
// Pagination
,
Custom1 = Table.Combine(Pagination),

One thing to note, is the max contacts you can get with each call is 100. I see you have your &count set to 250. Not sure if that is an issue or not.

Brodie1
Member

Pagination using Power BI

Thanks very much for this, this definitely solved the pagination issue.

thanks again, and I hope this helps others #powerbi #dax #hubsput #powerquery

fyi, I removed the [Headers...token] worked without it.

cbarley
HubSpot Alumni
HubSpot Alumni

Pagination using Power BI

Hi @Brodie, happy to help. While I'm not familiar with MS Power Query / how it functions, I'll try to help in any way I can. If you're trying to access the vid-offset value, have you tried using ["vid-offset"] with quotes? I recently built a tool in NodeJS to paginate through contacts in a HubSpot Account to push the values from a a specific property into an array and count them. I had the same issue of accessing the has-more and vid-offset parameters, but not sure if this is exactly what you're seeing. Here's my repo: https://github.com/cbarley10/hubspot-pagination

MS Power Query seems like it runs code and puts it into a spreadsheet, but I could be vastly oversimplifying it's capabilities. If that's the case, I saw a pretty interesting article on Medium that does something similar if you want to try testing this out: https://medium.com/@alexisbedoret/create-a-hubspot-custom-dashboard-with-google-spreadsheet-and-data...

0 Upvotes
Brodie1
Member

Pagination using Power BI

Hi Connor,

Thanks for the assist.

The following 2 codes changes in the 4th row
[vid-offset] and ["vid-offset] both result in the same error

Invalid identifier - it doesn't like the quotes nor the -

0 Upvotes