Skip to main content

API Help Thread - posts about iiQ API use

  • February 11, 2026
  • 8 replies
  • 136 views

Forum|alt.badge.img+10

I would love to be able to make better use of the iiQ APIs.
If any other users would like to share ideas, repos w code, examples, etc, let’s do it in this thread.
Of if you know of other threads, please post them here.

 

8 replies

Emily Jones
Forum|alt.badge.img+7
  • Community Manager
  • February 17, 2026

  

Hi! ​@jo.cpa Here are a few threads I wanted to share with different district uses of iiQ API! 

 

 

Best,


Forum|alt.badge.img+1

This is 1 of 3 posts to for the Senior Device and Fee solution.

As we prepare for graduation, I want to provide a way for seniors to verify what devices they have assigned to them and their outstanding fees.

This will be done by them submitting a google form to request the information. Their device and fee information will be sent to them in an email. 

This is not the complete solution. But these are the building blocks I needed to create it.

The first thing I need to do is create a view of all seniors and then obtain the view id.  Here is the function I used to retrieve my user views.

/**
* Queries the IIQ User Views endpoint and parses the 'Items' array
* to find the GUID (ViewId) for your senior list.
*/
function findSeniorViewGuid() {
const bearerToken = getBearerToken();
const siteId = getSiteId();
const url = `${BASE_URL}/users/views`;

const options = {
method: 'get',
headers: {
'Authorization': `Bearer ${bearerToken}`,
'SiteId': siteId,
'Accept': 'application/json'
},
muteHttpExceptions: true
};

try {
const response = UrlFetchApp.fetch(url, options);
const result = JSON.parse(response.getContentText());

// Based on your JSON example, the data is in the 'Items' property
const views = result.Items || [];

console.log("--- YOUR USER VIEWS ---");

if (views.length > 0) {
views.forEach(view => {
// Logging the Name and the ViewId (GUID)
console.log(`Name: ${view.Name}`);
console.log(`GUID: ${view.ViewId}`);
console.log(`Entity: ${view.ViewTypeId}`); // Helps confirm if it's a User view
console.log('---------------------------');
});
} else {
console.warn("No views found in the 'Items' array.");
console.log("Full Response Structure: " + Object.keys(result).join(", "));
}

} catch (e) {
console.error("Script Error: " + e.message);
}
}

 


Forum|alt.badge.img+1

This is 2 of 3 posts to for the Senior Device and Fee solution.

Due to my "learn as you go" approach to the API, I was not aware of the meta data contained in a user record. I used this function to return the record structure to the execution log. 

This allowed me to see where a users assigned devices are contained within that structure.

/**
* Standalone Diagnostic: Fetches the Senior View and logs the RAW data
* structure of the first record found. Use this to verify property names.
*/
function debugFirstAssetStructure() {
const viewId = 'your view id';
const productId = 'IIQ product id';

try {
const bearerToken = getBearerToken();
const siteId = getSiteId();

// We only need the first record for this test, so we set $s=1
const url = `${BASE_URL}/assets?$s=1`;

const payloadData = {
"ProductId": productId,
"Filters": [{ "Facet": "View", "Id": viewId }]
};

const options = {
'method': 'post',
'contentType': 'application/json',
'headers': {
'Authorization': `Bearer ${bearerToken}`,
'SiteId': siteId
},
'payload': JSON.stringify(payloadData),
'muteHttpExceptions': true
};

const response = UrlFetchApp.fetch(url, options);
const result = JSON.parse(response.getContentText());
const items = result.Items || [];

if (items.length > 0) {
const firstAsset = items[0];

// We use JSON.stringify with (null, 2) to make it "pretty print" with indentation
Logger.log("--- RAW ASSET DATA STRUCTURE ---");
Logger.log(JSON.stringify(firstAsset, null, 2));
Logger.log("--- END OF RECORD ---");

} else {
Logger.log("No assets found in the specified view.");
}

} catch (e) {
Logger.log(`❌ Diagnostic Error: ${e.message}`);
}
}

 


Forum|alt.badge.img+1

This is 3 of 3 posts to for the Senior Device and Fee solution.

I used this function to extract the assigned devices and write them to a sheet. 

As always, please verify and use good judgement when it comes to the information I post.

/**
* Refreshes the 'Senior Assigned Devices' sheet from the IIQ View.
* Populates Column A with Email, Column C with SchoolIdNumber, and Column I with Category.
*/
function refreshAssetLookupTable() {
const viewId = 'Your view id';
const sheetName = 'Senior Assigned Devices';
const productId = 'IIQ product ID';

try {
const bearerToken = getBearerToken();
const siteId = getSiteId();

const url = `${BASE_URL}/assets?$s=99999`;
const payloadData = {
"ProductId": productId,
"Filters": [{ "Facet": "View", "Id": viewId }]
};

const options = {
'method': 'post',
'contentType': 'application/json',
'headers': {
'Authorization': `Bearer ${bearerToken}`,
'SiteId': siteId
},
'payload': JSON.stringify(payloadData),
'muteHttpExceptions': true
};

const response = UrlFetchApp.fetch(url, options);
const result = JSON.parse(response.getContentText());
const items = result.Items || [];

if (items.length > 0) {
const allData = items.map(asset => {
// Mapping based on your specific IIQ response structure
const studentEmail = (asset.Owner?.Email || asset.Owner?.EmailAddress || "").toLowerCase().trim();
const studentId = asset.Owner?.SchoolIdNumber || asset.Owner?.EmployeeNumber || "";
const categoryName = asset.Model?.Category?.Name || "Other";

return [
studentEmail, // Column A: Email
asset.Location?.Name || "District 279", // Column B: Location
studentId, // Column C: School Id #
asset.Model?.Name || "Unknown Device", // Column D: Model
asset.Owner?.FullName || "Student", // Column E: Owner
asset.AssetTag || "N/A", // Column F: Tag
asset.SerialNumber || "N/A", // Column G: Serial
asset.Status?.Name || "Assigned", // Column H: Status
categoryName // Column I: Category
];
});

const ss = SpreadsheetApp.getActiveSpreadsheet();
const sheet = ss.getSheetByName(sheetName);

// Clear existing data and set new values for all 9 columns (A through I)
if (sheet.getLastRow() > 1) {
sheet.getRange(2, 1, sheet.getLastRow() - 1, 9).clearContent();
}
sheet.getRange(2, 1, allData.length, 9).setValues(allData);

// Update the sync timestamp on the Fees sheet
const feeSheet = ss.getSheetByName("Senior Fees");
const formattedDate = Utilities.formatDate(new Date(), "GMT-5", "MMMM d, yyyy 'at' h:mm a");
if (feeSheet) feeSheet.getRange("N2").setValue(formattedDate);

Logger.log(`✅ Successfully synced ${allData.length} devices.`);
}
} catch (e) {
Logger.log(`❌ Sync Error: ${e.message}`);
}
}

 


Forum|alt.badge.img+10
  • Author
  • Participant
  • April 13, 2026

@SAudette 504b2e district279 
Oh, so is the UUID still not exportable in the GUI View (export sftp) and has to be done with API?


Forum|alt.badge.img+1

@SAudette 504b2e district279 
Oh, so is the UUID still not exportable in the GUI View (export sftp) and has to be done with API?

Good question. I don’t have that answer. I haven’t had a reason to export a view in that manner (sftp).


Forum|alt.badge.img+10
  • Author
  • Participant
  • April 13, 2026

Yes, I just confirmed.  The iiQ Asset ID (UUID that can be used) is already available in the Asset Views.  We use the scheduled sftp View, ingest into a database, and use for various purposes.

 


Forum|alt.badge.img+1

Yes, I just confirmed.  The iiQ Asset ID (UUID that can be used) is already available in the Asset Views.  We use the scheduled sftp View, ingest into a database, and use for various purposes.

 

I totally misunderstood your question. I thought you were asking about the GUID for the actual view. So theoretically, you could have that database connect directly to your view via the API and pull in the same data.