Pull advertiser click totals by date into Excel. The VBA sample requires start_date and end_date (max 90 days), authenticates with X-Api-Key, and writes flat click rows to a Clicks worksheet.
Clicks responses return flat objects under data (not nested JSON:API attributes). start_date and end_date are required; ranges cannot exceed 90 days.
Setup in Excel (VBA macros)
Open Excel on Windows (or Excel for Mac with VBA support) and enable the
Developer tab: File → Options → Customize Ribbon → Developer.
Get your personal API key from
API key docs.
Prefer the X-Api-Key header (these samples already do).
Create a worksheet named Config with
HIENERGY_API_KEY in A1 and your key value in B1.
Optionally set HIENERGY_API_BASE in A2 / B2.
Press Alt+F11 → Insert → Module. Paste the shared client library,
then add a second module for the resource import macro below.
In the VBA editor choose Tools → References and enable
Microsoft Scripting Runtime.
Save as a macro-enabled workbook (.xlsm), then run the import with
Alt+F8 (or Developer → Macros).
1. Shared VBA client
Paste this helper library into one standard module once. Every Hi Energy Excel
importer on this site reuses the same WinHttp client, JSON parser,
JSON:API flattener, and sheet writer.
OptionExplicit' Hi Energy AI — shared Excel VBA client (+ JSON helpers)' Paste into ONE standard module named HiEnergyClient.'' Setup:' 1. Enable the Developer tab (File → Options → Customize Ribbon → Developer)' 2. Alt+F11 → Insert → Module → paste this file' 3. Tools → References → check "Microsoft Scripting Runtime"' 4. Create a worksheet named Config with:' A1 = HIENERGY_API_KEY' B1 = your personal API key (https://app.hienergy.ai/api_documentation/api_key)' Optional:' A2 = HIENERGY_API_BASE' B2 = custom host (defaults to https://app.hienergy.ai)' 5. Paste a resource importer module, then run via Alt+F8'' Trust note: enable macros only for workbooks you created. Do not commit API keys to shared files.PublicConst HIENERGY_API_BASE_DEFAULT AsString = "https://app.hienergy.ai"PublicFunction GetHiEnergyApiKey() AsStringDim key AsString
key = Trim$(CStr(NzConfig("HIENERGY_API_KEY")))
If Len(key) = 0Then
Err.Raise vbObjectError + 1001, "HiEnergyClient", _
"Missing Config API key. Put HIENERGY_API_KEY in Config!A1 and your key in Config!B1."EndIf
GetHiEnergyApiKey = key
EndFunctionPublicFunction GetHiEnergyApiBase() AsStringDim base AsString
base = Trim$(CStr(NzConfig("HIENERGY_API_BASE")))
If Len(base) = 0Then base = HIENERGY_API_BASE_DEFAULT
If Right$(base, 1) = "/"Then base = Left$(base, Len(base) - 1)
GetHiEnergyApiBase = base
EndFunctionPrivateFunction NzConfig(ByVal keyName AsString) AsVariantDim ws As Worksheet
Dim lastRow AsLongDim r AsLong
On ErrorResumeNextSet ws = ThisWorkbook.Worksheets("Config")
On ErrorGoTo0If ws Is NothingThen
NzConfig = ""ExitFunctionEndIf
lastRow = ws.Cells(ws.Rows.Count, 1).End(xlUp).Row
For r = 1To Application.Max(1, lastRow)
If StrComp(Trim$(CStr(ws.Cells(r, 1).Value)), keyName, vbTextCompare) = 0Then
NzConfig = ws.Cells(r, 2).Value
ExitFunctionEndIfNext r
NzConfig = ""EndFunctionPublicFunction NewQuery() AsObjectSet NewQuery = CreateObject("Scripting.Dictionary")
EndFunctionPublicFunction HiEnergyApiGet(ByVal path AsString, OptionalByVal query AsObject = Nothing) AsObjectDim url AsStringDim http AsObjectDim body AsStringDim status AsLongDim parsed AsObjectDim message AsString
url = GetHiEnergyApiBase() & path
IfNot query Is NothingThen url = url & BuildQueryString(query)
Set http = CreateObject("WinHttp.WinHttpRequest.5.1")
http.Open "GET", url, False
http.SetRequestHeader "X-Api-Key", GetHiEnergyApiKey()
http.SetRequestHeader "Accept", "application/json"
http.Send
status = CLng(http.Status)
body = CStr(http.ResponseText)
Set parsed = ParseJson(body)
If status < 200Or status >= 300Then
message = body
IfNot parsed Is NothingThenIf parsed.Exists("error") Then message = CStr(parsed("error"))
If parsed.Exists("message") Then message = CStr(parsed("message"))
EndIf
Err.Raise vbObjectError + 1002, "HiEnergyClient", "Hi Energy AI API HTTP " & status & ": " & message
EndIfSet HiEnergyApiGet = parsed
EndFunctionPrivateFunction BuildQueryString(ByVal query AsObject) AsStringDim key AsVariantDim first AsBooleanDim out AsStringDim value AsString
first = True
out = ""ForEach key In query.Keys
value = Trim$(CStr(query(key)))
If Len(value) > 0ThenIf first Then
out = "?"
first = FalseElse
out = out & "&"EndIf
out = out & UrlEncode(CStr(key)) & "=" & UrlEncode(value)
EndIfNext key
BuildQueryString = out
EndFunctionPrivateFunction UrlEncode(ByVal value AsString) AsStringDim i AsLongDim ch AsStringDim code AsIntegerDim out AsStringFor i = 1To Len(value)
ch = Mid$(value, i, 1)
code = Asc(ch)
SelectCase code
Case48To57, 65To90, 97To122, 45, 46, 95, 126
out = out & ch
Case32
out = out & "%20"CaseElse
out = out & "%" & Right$("0" & Hex$(code), 2)
EndSelectNext i
UrlEncode = out
EndFunctionPublicFunction FlattenJsonApiItem(ByVal item AsObject) AsObjectDim row AsObjectDim attrs AsObjectDim key AsVariantSet row = CreateObject("Scripting.Dictionary")
If item Is NothingThenSet FlattenJsonApiItem = row
ExitFunctionEndIfIf item.Exists("id") Then row("id") = Scalarize(item("id"))
If item.Exists("type") Then row("type") = Scalarize(item("type"))
If item.Exists("attributes") ThenIf TypeName(item("attributes")) = "Dictionary"ThenSet attrs = item("attributes")
ForEach key In attrs.Keys
row(CStr(key)) = Scalarize(attrs(key))
Next key
EndIfEndIfSet FlattenJsonApiItem = row
EndFunctionPublicFunction FlattenFlatItem(ByVal item AsObject) AsObjectDim row AsObjectDim key AsVariantSet row = CreateObject("Scripting.Dictionary")
If item Is NothingThenSet FlattenFlatItem = row
ExitFunctionEndIfForEach key In item.Keys
row(CStr(key)) = Scalarize(item(key))
Next key
Set FlattenFlatItem = row
EndFunctionPrivateFunction Scalarize(ByVal value AsVariant) AsVariantIf IsObject(value) Then
Scalarize = JsonStringify(value)
ElseIf IsNull(value) Or IsEmpty(value) Then
Scalarize = ""Else
Scalarize = value
EndIfEndFunctionPublicFunction ExtractJsonApiCollection(ByVal payload AsObject, ParamArray preferredKeys() AsVariant) As Collection
Dim i AsLongDim key AsStringDim node AsObjectDim emptyCol As Collection
Set emptyCol = New Collection
If payload Is NothingThenSet ExtractJsonApiCollection = emptyCol
ExitFunctionEndIfIf UBound(preferredKeys) >= LBound(preferredKeys) ThenFor i = LBound(preferredKeys) To UBound(preferredKeys)
key = CStr(preferredKeys(i))
If payload.Exists(key) ThenIf TypeName(payload(key)) = "Collection"ThenSet ExtractJsonApiCollection = payload(key)
ExitFunctionEndIfIf TypeName(payload(key)) = "Dictionary"ThenSet node = payload(key)
If node.Exists("data") ThenIf TypeName(node("data")) = "Collection"ThenSet ExtractJsonApiCollection = node("data")
ExitFunctionEndIfEndIfEndIfEndIfNext i
EndIfIf payload.Exists("data") ThenIf TypeName(payload("data")) = "Collection"ThenSet ExtractJsonApiCollection = payload("data")
ExitFunctionEndIfEndIfSet ExtractJsonApiCollection = emptyCol
EndFunctionPublicFunction WriteObjectsToSheet(ByVal sheetName AsString, ByVal rows As Collection, OptionalByVal clearSheet AsBoolean = True) AsLongDim ws As Worksheet
Dim headers As Collection
Dim seen AsObjectDim rowDict AsObjectDim key AsVariantDim r AsLongDim c AsLong
On ErrorResumeNextSet ws = ThisWorkbook.Worksheets(sheetName)
On ErrorGoTo0If ws Is NothingThenSet ws = ThisWorkbook.Worksheets.Add(After:=ThisWorkbook.Worksheets(ThisWorkbook.Worksheets.Count))
On ErrorResumeNext
ws.Name = sheetName
On ErrorGoTo0EndIfIf clearSheet Then ws.Cells.ClearContents
If rows Is NothingOr rows.Count = 0Then
ws.Range("A1").Value = "No rows returned"
WriteObjectsToSheet = 0ExitFunctionEndIfSet headers = New Collection
Set seen = CreateObject("Scripting.Dictionary")
ForEach rowDict In rows
ForEach key In rowDict.Keys
IfNot seen.Exists(CStr(key)) Then
headers.Add CStr(key)
seen(CStr(key)) = TrueEndIfNext key
Next rowDict
For c = 1To headers.Count
ws.Cells(1, c).Value = headers(c)
Next c
r = 2ForEach rowDict In rows
For c = 1To headers.Count
If rowDict.Exists(headers(c)) Then
ws.Cells(r, c).Value = rowDict(headers(c))
EndIfNext c
r = r + 1Next rowDict
ws.Rows(1).Font.Bold = True
WriteObjectsToSheet = rows.Count
EndFunctionPublicFunction IsoDateDaysAgo(ByVal days AsLong) AsString
IsoDateDaysAgo = Format$(Date - days, "yyyy-mm-dd")
EndFunctionPublicFunction IsoDateToday() AsString
IsoDateToday = Format$(Date, "yyyy-mm-dd")
EndFunctionPublicFunction JsonStringify(ByVal value AsVariant) AsStringDim key AsVariantDim i AsLongDim parts() AsStringDim n AsLongDim item AsVariantIf IsObject(value) ThenIf TypeName(value) = "Dictionary"Then
n = 0If value.Count = 0Then
JsonStringify = "{}"ExitFunctionEndIf
ReDim parts(0To value.Count - 1)
ForEach key In value.Keys
parts(n) = JsonEscape(CStr(key)) & ":" & JsonStringify(value(key))
n = n + 1Next key
JsonStringify = "{" & Join(parts, ",") & "}"ExitFunctionEndIfIf TypeName(value) = "Collection"ThenIf value.Count = 0Then
JsonStringify = "[]"ExitFunctionEndIf
ReDim parts(1To value.Count)
i = 1ForEach item In value
parts(i) = JsonStringify(item)
i = i + 1Next item
JsonStringify = "[" & Join(parts, ",") & "]"ExitFunctionEndIfEndIfIf IsNull(value) Or IsEmpty(value) Then
JsonStringify = "null"ElseIf VarType(value) = vbBoolean Then
JsonStringify = IIf(value, "true", "false")
ElseIf IsNumeric(value) And VarType(value) <> vbString Then
JsonStringify = Replace$(CStr(value), ",", ".")
Else
JsonStringify = JsonEscape(CStr(value))
EndIfEndFunctionPrivateFunction JsonEscape(ByVal value AsString) AsString
value = Replace$(value, "\", "\\")
value = Replace$(value, """", "\""")
value = Replace$(value, vbCr, "\r")
value = Replace$(value, vbLf, "\n")
value = Replace$(value, vbTab, "\t")
JsonEscape = """" & value & """"EndFunctionPublicFunction ParseJson(ByVal jsonText AsString) AsObjectDim p AsLong
p = 1Set ParseJson = ParseJsonValue(jsonText, p)
EndFunctionPrivateFunction ParseJsonValue(ByRef text AsString, ByRef p AsLong) AsVariant
SkipWs text, p
SelectCase Mid$(text, p, 1)
Case"{"Set ParseJsonValue = ParseJsonObject(text, p)
Case"["Set ParseJsonValue = ParseJsonArray(text, p)
Case""""
ParseJsonValue = ParseJsonString(text, p)
Case"t"If Mid$(text, p, 4) <> "true"Then Err.Raise vbObjectError + 1100, , "Invalid JSON boolean"
p = p + 4
ParseJsonValue = TrueCase"f"If Mid$(text, p, 5) <> "false"Then Err.Raise vbObjectError + 1100, , "Invalid JSON boolean"
p = p + 5
ParseJsonValue = FalseCase"n"If Mid$(text, p, 4) <> "null"Then Err.Raise vbObjectError + 1100, , "Invalid JSON null"
p = p + 4
ParseJsonValue = Null
CaseElse
ParseJsonValue = ParseJsonNumber(text, p)
EndSelectEndFunctionPrivateFunction ParseJsonObject(ByRef text AsString, ByRef p AsLong) AsObjectDim dict AsObjectDim key AsStringDim value AsVariantSet dict = CreateObject("Scripting.Dictionary")
p = p + 1
SkipWs text, p
If Mid$(text, p, 1) = "}"Then
p = p + 1Set ParseJsonObject = dict
ExitFunctionEndIfDo
SkipWs text, p
key = ParseJsonString(text, p)
SkipWs text, p
If Mid$(text, p, 1) <> ":"Then Err.Raise vbObjectError + 1101, , "Expected :"
p = p + 1
value = ParseJsonValue(text, p)
If IsObject(value) ThenSet dict(key) = value
Else
dict(key) = value
EndIf
SkipWs text, p
If Mid$(text, p, 1) = ","Then
p = p + 1ElseExitDoEndIfLoop
SkipWs text, p
If Mid$(text, p, 1) <> "}"Then Err.Raise vbObjectError + 1102, , "Expected }"
p = p + 1Set ParseJsonObject = dict
EndFunctionPrivateFunction ParseJsonArray(ByRef text AsString, ByRef p AsLong) As Collection
Dim col As Collection
Dim value AsVariantSet col = New Collection
p = p + 1
SkipWs text, p
If Mid$(text, p, 1) = "]"Then
p = p + 1Set ParseJsonArray = col
ExitFunctionEndIfDo
value = ParseJsonValue(text, p)
If IsObject(value) Then
col.Add value
Else
col.Add value
EndIf
SkipWs text, p
If Mid$(text, p, 1) = ","Then
p = p + 1ElseExitDoEndIfLoop
SkipWs text, p
If Mid$(text, p, 1) <> "]"Then Err.Raise vbObjectError + 1103, , "Expected ]"
p = p + 1Set ParseJsonArray = col
EndFunctionPrivateFunction ParseJsonString(ByRef text AsString, ByRef p AsLong) AsStringDim out AsStringDim ch AsStringIf Mid$(text, p, 1) <> """"Then Err.Raise vbObjectError + 1104, , "Expected string"
p = p + 1DoWhile p <= Len(text)
ch = Mid$(text, p, 1)
p = p + 1If ch = """"Then
ParseJsonString = out
ExitFunctionEndIfIf ch = "\"Then
ch = Mid$(text, p, 1)
p = p + 1SelectCase ch
Case"""", "\", "/"
out = out & ch
Case"b"
out = out & vbBack
Case"f"
out = out & vbFormFeed
Case"n"
out = out & vbLf
Case"r"
out = out & vbCr
Case"t"
out = out & vbTab
Case"u"
out = out & ChrW$("&H" & Mid$(text, p, 4))
p = p + 4CaseElse
out = out & ch
EndSelectElse
out = out & ch
EndIfLoop
Err.Raise vbObjectError + 1105, , "Unterminated string"EndFunctionPrivateFunction ParseJsonNumber(ByRef text AsString, ByRef p AsLong) AsVariantDim startPos AsLongDim ch AsStringDim raw AsString
startPos = p
ch = Mid$(text, p, 1)
If ch = "-"Then p = p + 1DoWhile p <= Len(text)
ch = Mid$(text, p, 1)
If (ch >= "0"And ch <= "9") Or ch = "."Or ch = "e"Or ch = "E"Or ch = "+"Or ch = "-"Then
p = p + 1ElseExitDoEndIfLoop
raw = Mid$(text, startPos, p - startPos)
If InStr(raw, ".") > 0Or InStr(1, raw, "e", vbTextCompare) > 0Then
ParseJsonNumber = CDbl(Val(raw))
Else
ParseJsonNumber = CLng(Val(raw))
EndIfEndFunctionPrivateSub SkipWs(ByRef text AsString, ByRef p AsLong)
DoWhile p <= Len(text)
SelectCase Mid$(text, p, 1)
Case" ", vbTab, vbCr, vbLf
p = p + 1CaseElseExitDoEndSelectLoopEndSub
2. Clicks import macro
Paste this into a second standard module, save as .xlsm, then run the
import with Alt+F8.
OptionExplicit' Import click analytics into Excel.' Requires the shared HiEnergyClient module.' start_date and end_date are required. Maximum range is 90 days.PublicSub ImportHiEnergyClicks()
Dim START_DATE AsStringDim END_DATE AsStringDim PUBLISHER_ID AsStringDim page AsLongDim perPage AsLongDim maxPages AsLongDim allRows As Collection
Dim query AsObjectDim payload AsObjectDim records As Collection
Dim item AsObjectDim count AsLong
START_DATE = IsoDateDaysAgo(30)
END_DATE = IsoDateToday()
PUBLISHER_ID = ""' Admins only: set a publisher id to scope clicks
page = 1
perPage = 100
maxPages = 50Set allRows = New Collection
DoWhile page <= maxPages
Set query = NewQuery()
query("start_date") = START_DATE
query("end_date") = END_DATE
query("publisher_id") = PUBLISHER_ID
query("page") = page
query("per_page") = perPage
query("include_total") = "false"Set payload = HiEnergyApiGet("/api/v1/clicks", query)
Set records = ExtractJsonApiCollection(payload, "data")
If records.Count = 0ThenExitDoForEach item In records
allRows.Add FlattenFlatItem(item)
Next item
If records.Count < perPage ThenExitDo
page = page + 1Loop
count = WriteObjectsToSheet("Clicks", allRows, True)
MsgBox "Imported " & count & " click rows", vbInformation, "Hi Energy AI"EndSub
Useful query parameters
Parameter
Purpose
start_date
Required ISO date (YYYY-MM-DD). Inclusive range start.
end_date
Required ISO date (YYYY-MM-DD). Inclusive range end.
publisher_id
Admins can scope to a publisher; other users are auto-scoped.
page / per_page / limit
Pagination controls for large click extracts.
include_total
Optional total count for reporting UIs.
FAQ
Paste the shared VBA client and clicks importer, set HIENERGY_API_KEY on Config, then run ImportHiEnergyClicks. It calls GET /api/v1/clicks with required start_date and end_date.
The Clicks API allows at most 90 days between start_date and end_date. Split larger history into multiple imports.
Yes. Non-admin users are scoped to their publisher. Admins may optionally pass publisher_id.
Yes. GET /api/v1/clicks requires both dates. The sample defaults to the last 30 days; adjust START_DATE and END_DATE before running.
Clicks responses return flat objects under data (not nested JSON:API attributes), so the importer writes those fields directly as spreadsheet columns.
Yes. This page publishes TechArticle, HowTo, FAQPage, BreadcrumbList, WebSite SearchAction, and related endpoint ItemList structured data for answer engines.
Ask Dex AIIntegration help
If this page feels TLDR, ask Dex AI.
Dex AI speaks your language, and all the other languages you may not. It will write the integration for you with the right endpoint and headers in one plain-English answer.