GST Number Verification in Google Sheets with Apps Script
A step-by-step Apps Script guide to build a custom function that verifies GSTINs live inside Google Sheets.
You can verify a GST number in Google Sheets with an Apps Script custom function that calls the API through
UrlFetchApp and returns a value straight into a cell. For anything beyond a few dozen lookups,
though, a menu-driven bulk script that runs once on demand is a better fit than a custom function that
Sheets recalculates automatically on nearly every edit.
A custom function with UrlFetchApp
Open Extensions → Apps Script from your sheet and add a function that calls the GST
verification API. Any function without a leading underscore becomes usable as a formula, so
=VERIFYGSTIN(A2) works exactly like a built-in Sheets function once this is saved.
function VERIFYGSTIN(gstin) {
if (!gstin) return "";
var apiKey = PropertiesService.getScriptProperties().getProperty("GSTINAPI_KEY");
var url = "https://gstinapi.com/api/get-taxpayer-info/" + gstin;
var response = UrlFetchApp.fetch(url, {
method: "get",
headers: { "X-API-Key": apiKey },
muteHttpExceptions: true,
});
if (response.getResponseCode() !== 200) {
return "Error " + response.getResponseCode();
}
var data = JSON.parse(response.getContentText());
return data.status + " – " + data.legal_name;
}
This is enough for occasional lookups — checking a handful of GSTINs while reviewing a document. It is intentionally not yet the version you want running across a whole column; see the caching and quota sections below before you scale it up.
Caching results with CacheService
Google Sheets recalculates custom functions far more often than most people expect — on almost any edit
anywhere in the sheet, not only when the referenced cell changes. Without a cache, an active spreadsheet can
silently re-run VERIFYGSTIN for the same GSTIN dozens of times in a session, burning through
verification credits for lookups you already have the answer to.
function VERIFYGSTIN(gstin) {
if (!gstin) return "";
var cache = CacheService.getScriptCache();
var cached = cache.get(gstin);
if (cached) return cached;
var apiKey = PropertiesService.getScriptProperties().getProperty("GSTINAPI_KEY");
var url = "https://gstinapi.com/api/get-taxpayer-info/" + gstin;
var response = UrlFetchApp.fetch(url, {
method: "get",
headers: { "X-API-Key": apiKey },
muteHttpExceptions: true,
});
if (response.getResponseCode() !== 200) {
return "Error " + response.getResponseCode();
}
var data = JSON.parse(response.getContentText());
var result = data.status + " – " + data.legal_name;
cache.put(gstin, result, 21600); // cache for up to 6 hours
return result;
}
Storing the API key with PropertiesService
Never hardcode the API key inside the function body — anyone with edit access to the script (or a copy of the sheet, if the code is duplicated) can read it. Store it once in Script Properties instead, from the Apps Script editor's Project Settings → Script Properties, or set it programmatically the first time:
function setApiKey() {
PropertiesService.getScriptProperties().setProperty("GSTINAPI_KEY", "YOUR_API_KEY");
}
Run setApiKey once from the Apps Script editor, then delete or comment out the line with the
literal key so it is not sitting in the script's source. Script Properties are attached to the script
project, not visible in the spreadsheet cells, and are not copied automatically if someone makes a copy of
the sheet — which is also a reason to re-set the key deliberately on any copy rather than assuming it carries
over.
The 30-second timeout and quota limits
Two Apps Script limits matter for this pattern. First, a custom function has roughly a 30-second execution
ceiling — if UrlFetchApp.fetch is slow or the API is temporarily degraded, the cell will show an
error rather than waiting indefinitely. Second, UrlFetchApp calls count against Apps Script's
own daily quota (which varies by account type — a free Gmail account has a materially lower daily allowance
than a Google Workspace account), separate from your GST verification API credits. A sheet with custom
functions in hundreds of cells can exhaust that quota before it exhausts your API credits.
A menu-driven bulk-verify script
For a whole column of GSTINs — the common case when checking a vendor list or a batch of customer records — add a custom menu item that runs once, loops through the range, and writes plain values (not live formulas) into the sheet. This gives you a predictable number of API calls and avoids the recalculation problem entirely.
function onOpen() {
SpreadsheetApp.getUi()
.createMenu("GST Tools")
.addItem("Bulk verify GSTIN column", "bulkVerifyGstins")
.addToUi();
}
function bulkVerifyGstins() {
var sheet = SpreadsheetApp.getActiveSheet();
var apiKey = PropertiesService.getScriptProperties().getProperty("GSTINAPI_KEY");
var lastRow = sheet.getLastRow();
var gstins = sheet.getRange(2, 1, lastRow - 1, 1).getValues();
for (var i = 0; i < gstins.length; i++) {
var gstin = gstins[i][0];
if (!gstin) continue;
var response = UrlFetchApp.fetch(
"https://gstinapi.com/api/get-taxpayer-info/" + gstin,
{ method: "get", headers: { "X-API-Key": apiKey }, muteHttpExceptions: true }
);
var row = i + 2;
if (response.getResponseCode() === 200) {
var data = JSON.parse(response.getContentText());
sheet.getRange(row, 2).setValue(data.status);
sheet.getRange(row, 3).setValue(data.legal_name);
} else {
sheet.getRange(row, 2).setValue("Error " + response.getResponseCode());
}
Utilities.sleep(300); // be polite to the rate limit on large ranges
}
SpreadsheetApp.getUi().alert("Bulk GSTIN verification complete.");
}
This writes a static status and legal name into each row once, rather than a formula that could re-fire later. For anything larger than a few hundred rows, or a check that needs to run on a schedule rather than a click, a proper backend integration is usually the better long-term fit — see our bulk GSTIN verification guide and rate limits guide for the limits to plan around.
A quick sanity check worth adding before the API call: a GSTIN's final character is a checksum over the first fourteen, so a script can reject an obviously malformed entry (wrong length, invalid state code) without spending a credit on it. That checksum only confirms the string is well-formed, though — it cannot tell you whether the number was ever actually registered. Only the live lookup above answers that. See GSTIN format explained for the full breakdown.
Frequently asked questions
A note on accuracy. GST rules change often. This article reflects our understanding as of 30 August 2026 and is general information, not tax or legal advice. For the authoritative position, check gst.gov.in and cbic-gst.gov.in, or speak to a qualified tax professional about your specific situation.
Check a GSTIN right now, free
Five lookups a day, no account required. Status, filing history, e-invoicing and jurisdiction.
Free GST search toolBuild it into your product
One REST call, JSON back. Get an API key and 20 free verification credits in under a minute.
Start freeMore on developer integration guides
Browse every guide in the GST API blog.