Open Forum

 View Only

 PowerBI Reporting

Jump to Best Answer
Luke Page's profile image
Luke Page posted 03-21-2023 14:46

Hi all,

We are new to 8x8 and while the 8x8 reporting dashboards are great, we want this data in PowerBi for additional reporting.

Anyone had any luck with this? I've tried following the API documentation for 8x8 work and it's not working.

8x8 x4 licenses, trying to connect to https://api.8x8.com/analytics/work with no luck.

Thanks a lot!

Oisin Glynn's profile image
Oisin Glynn Best Answer

You should make sure you understand and are comfortable with code snipits before using them. 

This would be a multi step process involved in authenticating and then requesting data.

This example assumes you've setup some parameters names

  • apikey - contains the api key for Work Analytics
  • WorkAUsername - contains the username for a user who has the correct permission and has used the browser Analytics at least one time
  • WorkAPassword - contains the password for the user.
  • pbxname - contains the name of the PBX you are looking for data from
  • StartTimeDate - contains the start time/date for the query
  • EndTimeDate - contains the start time/date for the query

Step 1 function called GetBearer

(username as text, password as text) =>

let
credentials = "username=" & username & "&password=" & password,
body = credentials,

webdata = Web.Contents("https://api.8x8.com/analytics/work/v1/oauth/token", [Headers=[#"8x8-apikey"=apikey, #"Content-Type"="application/x-www-form-urlencoded"], Content = Text.ToBinary(body)]),
response = Json.Document(webdata)

in
    response[access_token]

Create a Query (This shows call-legs but you could hit any of the endpoints)

This calls GetBearer function above to authenticate

The formatting of the data was for this purpose you can change this to suit your needs.

let

	BaseURL = "https://api.8x8.com/analytics/work/v2/call-legs?",
	EntitiesPerPage = 1000,
	pageSize = "1000",

	bearertoken = GetBearer(WorkAUsername, WorkAPassword),

	pbxid = pbxname,
	startTime = DateTime.ToText(StartTimeDate, "yyyy-MM-dd HH:mm:ss"),
	endTime = DateTime.ToText(EndTimeDate, "yyyy-MM-dd HH:mm:ss"),
	timeZone = "Europe/London",

	params = "pbxId=" & pbxid & "&startTime=" & startTime & "&endTime=" & endTime & "&timeZone=" & timeZone & "&pageSize=" & pageSize,
	Options = [Headers=[ #"Authorization" = "Bearer " & bearertoken, #"8x8-apikey"=apikey, #"Content-Type"="application/json" ]],
	url = BaseURL&params,
	scrollUrl = BaseURL&params & "&scrollId=",


		GetJson = (Url) =>
			let Options = [Headers=[ #"Authorization" = "Bearer " & bearertoken, #"8x8-apikey"=apikey, #"Content-Type"="application/json" ]],
				RawData = Web.Contents(Url, Options),
				Json    = Json.Document(RawData)
			in  Json,

		GetTotalRecords = () =>
			let Url = BaseURL & params & "&pageSize=1",
				Json  = GetJson(Url),
				Count = Json[meta]
			in  Count,
 
	EntityCount = GetTotalRecords()[totalRecordCount],
	PageCount   = Number.RoundUp(EntityCount / EntitiesPerPage),
	Pages       = Fetch(url, scrollUrl, Options, null, null, PageCount),
	Entities    = Pages,
    #"Expanded Column1" = Table.ExpandRecordColumn(Entities, "Column1", {"callId", "legId", "startTimeUTC", "startTime", "connectTimeUTC", "connectTime", "disconnectedTimeUTC", "disconnectedTime", "talkTimeMS", "talkTime", "caller", "callerName", "callee", "calleeName", "lra", "direction", "parentCallId", "transferToCallId", "dnis", "status", "callerDeviceId", "calleeDeviceId", "callerDeviceModel", "calleeDeviceModel", "callerId", "missed", "abandoned", "answered", "cause", "callerSvcName", "callerSvcType", "calleeSvcName", "calleeSvcType", "lraType", "calleeHoldDurationMS", "calleeHoldDuration", "calleeDisconnectOnHold", "callerDisconnectOnHold", "pbxId", "sipCallId", "departments", "branches", "recordServiceOn", "bargeServiceOn", "masterSlaveExts", "propsLastPartyDisp", "accountCode", "aaPath", "callTime"}, {"callId", "legId", "startTimeUTC", "startTime", "connectTimeUTC", "connectTime", "disconnectedTimeUTC", "disconnectedTime", "talkTimeMS", "talkTime", "caller", "callerName", "callee", "calleeName", "lra", "direction", "parentCallId", "transferToCallId", "dnis", "status", "callerDeviceId", "calleeDeviceId", "callerDeviceModel", "calleeDeviceModel", "callerId", "missed", "abandoned", "answered", "cause", "callerSvcName", "callerSvcType", "calleeSvcName", "calleeSvcType", "lraType", "calleeHoldDurationMS", "calleeHoldDuration", "calleeDisconnectOnHold", "callerDisconnectOnHold", "pbxId", "sipCallId", "departments", "branches", "recordServiceOn", "bargeServiceOn", "masterSlaveExts", "propsLastPartyDisp", "accountCode", "aaPath", "callTime"}),
	
    #"Changed Type" = Table.TransformColumnTypes(#"Expanded Column1",{{"startTime", type datetimezone}, {"disconnectedTime", type datetimezone}, {"connectTime", type text}, {"legId", Int64.Type}, {"callTime", Int64.Type}, {"calleeHoldDurationMS", Int64.Type}, {"direction", type text}})
in
    #"Changed Type"

EDITED

Add Fetch Function

let
    RecursiveFetch = (Url, scrollUrl, options, scroll, counter, pageCount) =>
			let
				TotalPageCount = pageCount,
				
				Counter = if (counter = null) then 0 else counter,

				Results = if (scroll = null) then            
					Json.Document(Web.Contents(Url, options))
				else
					Json.Document(Web.Contents(scrollUrl&scroll, options)),

				ParsedResults = Table.FromList(Results[data], Splitter.SplitByNothing(), null, null, ExtraValues.Error),

				Return = if (Counter < TotalPageCount) then
					ParsedResults & Fetch(Url, scrollUrl, options, Results[meta][scrollId], Counter+1, TotalPageCount)
				else
					ParsedResults 
			in Return
in
    RecursiveFetch
Ged Attwood's profile image
Ged Attwood

I don't think it's that easy to connect directly to an Oauth from PowerBI, at least 8x8 don't publish a packaged solution, firstly I would suggest using a tool like Postman to test the API key you have set up (presume you have followed the 8x8 guide) and take a look at the PowerBI community forums there is a good post about getting VCC data out using the api among others, you can use similar techniques to get what you want. If thats sounds a bit much for you to roll you own there are commercial solutions but I have no experience of them to recommend any.

Luke Page's profile image
Luke Page

Thanks for firing that over, entered all that, and its saying Fetch not recognised, not sure if you have seen that one before?

Thanks for your help!

Oisin Glynn's profile image
Oisin Glynn

You should make sure you understand and are comfortable with code snipits before using them. 

I missed the Fetch function So you would need to add this function also to the post below.

This is what I have in the Fetch function, I added it to the original post as well for clarity.

let
    RecursiveFetch = (Url, scrollUrl, options, scroll, counter, pageCount) =>
			let
				TotalPageCount = pageCount,
				
				Counter = if (counter = null) then 0 else counter,

				Results = if (scroll = null) then            
					Json.Document(Web.Contents(Url, options))
				else
					Json.Document(Web.Contents(scrollUrl&scroll, options)),

				ParsedResults = Table.FromList(Results[data], Splitter.SplitByNothing(), null, null, ExtraValues.Error),

				Return = if (Counter < TotalPageCount) then
					ParsedResults & Fetch(Url, scrollUrl, options, Results[meta][scrollId], Counter+1, TotalPageCount)
				else
					ParsedResults 
			in Return
in
    RecursiveFetch

Luke Page's profile image
Luke Page

Thanks that's working :) 

For those with less PowerBi experience, ensure you set the web data source setting to annonomous, or it will complain.

Justin Mangano's profile image
Justin Mangano

I was unable to make this work. Is this something 8x8 support can assist with?