Contacts → Google Sheets overview

Import Hi Energy advertiser contacts into Google Sheets with Google Apps Script. Search by domain, advertiser name, email, or free text, then flatten JSON:API contact records into a Contacts tab.

Endpoint: GET /api/v1/contacts

Contacts list responses return JSON:API objects under data. Unverified contacts are excluded unless include_unverified=true is allowed for your account.

Setup in Google Sheets

  1. Open a Google Sheet → ExtensionsApps Script.
  2. Get your personal API key from API key docs. Prefer the X-Api-Key header (these samples already do).
  3. In Apps Script, open Project SettingsScript properties and add HIENERGY_API_KEY with your key value.
  4. Paste the shared client library, then the resource import script below.
  5. Click Save, reload the Sheet, and run the import from the Hi Energy AI menu (or Run in the editor).
  6. On first run, authorize the script when Google prompts for UrlFetchApp / external request permission.

1. Shared Apps Script client

Paste this helper library into your Apps Script project once. Every Hi Energy Google Sheets importer on this site reuses the same UrlFetchApp client, JSON:API flattener, and sheet writer.

/**
 * Hi Energy AI — shared Google Apps Script client
 * Paste this into Extensions → Apps Script, then add a resource script below.
 *
 * Setup:
 * 1. File → Project properties → Script properties
 * 2. Add property HIENERGY_API_KEY = your personal API key
 *    (from https://app.hienergy.ai/api_documentation/api_key)
 * 3. Optionally override HIENERGY_API_BASE if you use a custom host
 */

var HIENERGY_API_BASE = 'https://app.hienergy.ai';

function getHiEnergyApiKey_() {
  var key = PropertiesService.getScriptProperties().getProperty('HIENERGY_API_KEY');
  if (!key) {
    throw new Error(
      'Missing Script Property HIENERGY_API_KEY. ' +
      'Open Project Settings → Script properties and add your API key.'
    );
  }
  return key;
}

function hiEnergyApiGet_(path, query) {
  var url = HIENERGY_API_BASE + path;
  var params = [];
  Object.keys(query || {}).forEach(function(key) {
    var value = query[key];
    if (value === null || value === undefined || value === '') return;
    params.push(encodeURIComponent(key) + '=' + encodeURIComponent(String(value)));
  });
  if (params.length) url += '?' + params.join('&');

  var response = UrlFetchApp.fetch(url, {
    method: 'get',
    headers: {
      'X-Api-Key': getHiEnergyApiKey_(),
      'Accept': 'application/json'
    },
    muteHttpExceptions: true,
    followRedirects: true
  });

  var code = response.getResponseCode();
  var body = response.getContentText();
  var json = null;
  try { json = JSON.parse(body); } catch (e) {}

  if (code < 200 || code >= 300) {
    var message = (json && (json.error || json.message)) || body;
    throw new Error('Hi Energy AI API HTTP ' + code + ': ' + message);
  }
  return json;
}

function flattenJsonApiItem_(item) {
  var row = {};
  if (!item || typeof item !== 'object') return row;
  if (item.id !== undefined) row.id = item.id;
  if (item.type !== undefined) row.type = item.type;
  var attrs = item.attributes || {};
  Object.keys(attrs).forEach(function(key) {
    var value = attrs[key];
    row[key] = (value !== null && typeof value === 'object') ? JSON.stringify(value) : value;
  });
  return row;
}

function extractJsonApiCollection_(payload, preferredKeys) {
  if (!payload) return [];
  var keys = preferredKeys || ['data'];
  for (var i = 0; i < keys.length; i++) {
    var key = keys[i];
    var node = payload[key];
    if (Array.isArray(node)) return node;
    if (node && Array.isArray(node.data)) return node.data;
  }
  if (Array.isArray(payload.data)) return payload.data;
  return [];
}

function uniqueHeaders_(rows) {
  var seen = {};
  var headers = [];
  rows.forEach(function(row) {
    Object.keys(row).forEach(function(key) {
      if (!seen[key]) {
        seen[key] = true;
        headers.push(key);
      }
    });
  });
  return headers;
}

function writeObjectsToSheet_(sheetName, rows, clearSheet) {
  var ss = SpreadsheetApp.getActiveSpreadsheet();
  var sheet = ss.getSheetByName(sheetName) || ss.insertSheet(sheetName);
  if (clearSheet !== false) sheet.clearContents();

  if (!rows.length) {
    sheet.getRange(1, 1).setValue('No rows returned');
    return 0;
  }

  var headers = uniqueHeaders_(rows);
  var values = [headers].concat(rows.map(function(row) {
    return headers.map(function(header) {
      var value = row[header];
      return value === undefined || value === null ? '' : value;
    });
  }));

  sheet.getRange(1, 1, values.length, headers.length).setValues(values);
  sheet.setFrozenRows(1);
  return rows.length;
}

function isoDateDaysAgo_(days) {
  var date = new Date();
  date.setDate(date.getDate() - days);
  return Utilities.formatDate(date, Session.getScriptTimeZone(), 'yyyy-MM-dd');
}

function isoDateToday_() {
  return Utilities.formatDate(new Date(), Session.getScriptTimeZone(), 'yyyy-MM-dd');
}

2. Contacts import script

Paste this below the shared client, save the project, then run the import function (or use the Hi Energy AI custom menu after reloading the sheet).

/**
 * Import Hi Energy contacts into Google Sheets.
 * Requires the shared Hi Energy client helpers in this Apps Script project.
 *
 * Search by domain, advertiser name, email, or free-text q.
 */
function onOpen() {
  SpreadsheetApp.getUi()
    .createMenu('Hi Energy AI')
    .addItem('Import contacts', 'importHiEnergyContacts')
    .addToUi();
}

function importHiEnergyContacts() {
  var DOMAIN = '';           // e.g. 'nike.com'
  var ADVERTISER_NAME = '';  // e.g. 'Nike'
  var EMAIL = '';
  var QUERY = '';

  var page = 1;
  var perPage = 100;
  var allRows = [];
  var maxPages = 20;

  while (page <= maxPages) {
    var payload = hiEnergyApiGet_('/api/v1/contacts', {
      domain: DOMAIN,
      advertiser_name: ADVERTISER_NAME,
      email: EMAIL,
      q: QUERY,
      page: page,
      per_page: perPage
    });

    var records = extractJsonApiCollection_(payload, ['data']);
    if (!records.length) break;

    records.forEach(function(item) {
      allRows.push(flattenJsonApiItem_(item));
    });

    if (records.length < perPage) break;
    page += 1;
  }

  var count = writeObjectsToSheet_('Contacts', allRows, true);
  SpreadsheetApp.getActiveSpreadsheet().toast('Imported ' + count + ' contacts', 'Hi Energy AI', 5);
}

Useful query parameters

Parameter Purpose
domain Find contacts for an advertiser website domain.
advertiser_name Match contacts by program / brand name.
advertiser_id Exact advertiser id scope.
email Look up a specific contact email.
q Free-text search across contact fields.
has_linkedin Prefer contacts that include LinkedIn profile URLs.
include_unverified Include unverified contacts when your role allows it.

FAQ

Use the Apps Script samples on this page to call GET /api/v1/contacts with your API key and write flattened contact attributes to a Contacts sheet.

Domain is usually most precise for a brand website. Advertiser name is useful for fuzzy discovery. You can combine filters.

Creating contacts uses POST /api/v1/contacts and requires create permissions (admin/paid publisher on REST). This page focuses on read/import workflows; see the Contacts API docs for create payloads.

No. Unverified contacts are excluded unless include_unverified=true is allowed for your account and you enable that filter in the importer.

Yes. Set has_linkedin in the sample filters when you want outreach lists that include LinkedIn URLs.

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.