GST Verification in n8n Workflows
Build an n8n workflow that verifies GSTINs from a form, sheet or CRM using the HTTP Request node, with error handling and retries.
n8n is a good home for GST verification because it gives you what Zapier and Power Automate make you pay extra for: a plain HTTP Request node, a Code node for the one piece of logic that needs it, loops with real batching, and a proper error workflow. This guide builds the whole thing: a trigger that produces a GSTIN, a format check, the API call with the key stored as a credential, a branch on the returned status, a write-back to your sheet and a Slack alert when a supplier comes back Cancelled.
The shape of the workflow
Every GST verification workflow in n8n is the same five stages, whatever the source of the GSTIN:
- Trigger — a new sheet row, a webhook from your app, or a form submission.
- Format check — a Code or IF node that drops anything that is not a well-formed GSTIN.
- HTTP Request — the API call, one per item.
- IF on status — Active goes one way, Cancelled or Suspended another.
- Write back and alert — update the source record, notify a person when it matters.
If you have built the same thing in Zapier or Power Automate, the logic is identical. What changes is that n8n processes a list of items through each node, so the batch case is a small extension of the single-record case rather than a different design.
Step 1: pick a trigger
Pick the trigger that matches where the GSTIN first enters your process:
- Google Sheets Trigger on "Row Added" for a vendor onboarding sheet. It polls, so expect a short delay after the row appears.
- Webhook node when your own application should ask n8n to verify a GSTIN at signup or checkout. Your app POSTs a JSON body containing the GSTIN; the workflow can reply with the result using a Respond to Webhook node.
- n8n Form Trigger when you want a hosted form for suppliers or internal staff with no other system involved.
Whichever you use, add a Set (Edit Fields) node right after it that copies the GSTIN into a field with a
fixed name, say gstin, trimmed and uppercased. Every later node then references the same
field, and swapping the trigger later does not break anything downstream.
Step 2: check the GSTIN format before you spend a credit
A GSTIN is 15 characters with a fixed structure: two-digit state code, the holder's PAN, an entity
number, a literal Z and a check character. The anchored pattern, explained character by
character in GSTIN regex explained, is:
^[0-9]{2}[A-Z]{5}[0-9]{4}[A-Z][1-9A-Z]Z[0-9A-Z]$
The no-code option is an IF node with a String condition, "matches regex", against the
gstin field. The Code node option lets you tag each item instead of dropping it, which is
better when you want to write "Invalid format" back to the sheet:
// Code node, mode: Run Once for All Items
const pattern = /^[0-9]{2}[A-Z]{5}[0-9]{4}[A-Z][1-9A-Z]Z[0-9A-Z]$/;
return $input.all().map(item => {
const gstin = String(item.json.gstin || '').trim().toUpperCase();
return {
json: { ...item.json, gstin, formatOk: pattern.test(gstin) },
};
});
Follow it with an IF node on formatOk. The regex does not check the final check character;
that needs the mod-36 calculation, which you can also do in the Code node or leave to the API. Our API
rejects a GSTIN that fails format or check-digit validation without billing a credit, but filtering early
still keeps those items off your error path. Paste a few suspect values into the
GSTIN validator if you want to see which rule they break.
Step 3: the HTTP Request node
First create the credential: in Credentials, add a Header Auth credential, set the name
to X-API-Key and the value to your key from the API access
page. Then add an HTTP Request node on the "valid" branch and configure it like this:
| Setting | Value | Why |
|---|---|---|
| Method | GET | The lookup is a read; there is no request body |
| URL | https://gstinapi.com/api/get-taxpayer-info/ followed by an expression for gstin | The GSTIN goes in the path |
| Authentication | Generic Credential Type → Header Auth | Sends X-API-Key from the encrypted credential |
| Options → Timeout | 15–30 seconds | Stops an item hanging on a slow upstream response |
| Settings → Retry On Fail | On, 3 tries, a few seconds apart | Absorbs a transient 429, 502 or network drop |
| Settings → On Error | Continue (using error output) | Sends failed items down a separate branch instead of stopping the run |
If you open the node's JSON (copy the node and paste it into a text editor), the parameters look roughly like the snippet below. Treat it as an illustration of the settings, not an importable export: exact parameter names and the node's type version depend on your n8n version.
{
"name": "Verify GSTIN",
"type": "n8n-nodes-base.httpRequest",
"parameters": {
"method": "GET",
"url": "=https://gstinapi.com/api/get-taxpayer-info/{{ $json.gstin }}",
"authentication": "genericCredentialType",
"genericAuthType": "httpHeaderAuth",
"options": { "timeout": 20000 }
},
"retryOnFail": true,
"maxTries": 3,
"waitBetweenTries": 3000,
"onError": "continueErrorOutput"
}
The call answers HTTP 200 even for a GSTIN with no registration behind it, so read the body, not just
the status code. The registration sits under taxpayer_data: status_code is
1 for a live registration and 0 when none exists (with the reason in
taxpayer_data.error, and no credit charged). Alongside it come name (the legal
name), tradename, status, registrationDate,
constitution and the principal address in pradr, with GSTR filing history in
filing_data from the same response. The full schema is in the
API documentation.
Step 4: branch on status and write the result back
Add an IF node after the HTTP Request node's success output with two conditions:
{{ $json.taxpayer_data.status_code }} equals 1, and
{{ $json.taxpayer_data.status }} equals Active. A
status_code of 0 means the GSTIN is not registered at all and belongs on the
alert path too. Both outputs lead to a write-back; only one leads to an alert.
- Write back. A Google Sheets node with "Update Row" (or "Append or Update Row"),
matching on the
gstincolumn, writing status, legal name, registration date and the time of the check. Record the timestamp every time; a "verified" flag with no date is useless a month later. - Alert on Cancelled. On the false branch, add a second IF or a Switch node that separates Cancelled from Suspended, and send a Slack message for Cancelled with the GSTIN, legal name and cancellation date. Suspended usually deserves a review rather than an immediate block; the reasoning is in automated daily vendor GSTIN monitoring.
- Webhook callers. If the trigger was a Webhook node, finish with Respond to Webhook so your application gets the status back in the same request.
Why Cancelled deserves an alert: a supplier whose registration is cancelled cannot charge GST from the cancellation date, so tax on their later invoices is not something you can take input tax credit on. That is a payment decision, and it should reach a person rather than sit in a cell.
Verifying a whole list without tripping rate limits
Point the workflow at a sheet with 3,000 existing vendors and n8n will try to push every item through the HTTP Request node as fast as it can. Pace it deliberately, using one of two approaches:
- Loop Over Items (called Split In Batches in older versions) with a batch size of, say, 10 to 25, then the format check and HTTP Request inside the loop, then a Wait node before looping back. Simple to read and easy to tune.
- The HTTP Request node's own Batching option (under Options), which sends a set number of items per batch with a fixed interval between batches, without a loop.
Size the pace from the per-key limit in the API documentation, leave headroom, and let Retry On Fail handle the occasional 429. Why a steady rate beats bursts and retries is covered in GST API rate limits, retries and webhooks. For a large one-off backfill it can be simpler to upload the file to bulk verification and keep n8n for new records. If your team already lives in a spreadsheet, the Google Sheets guide covers doing it without a workflow tool at all.
Cost is the same as any other integration: ₹0.50 per verification, or ₹0.40 once a single credit purchase crosses 2,500 credits, and purchased credits do not expire. On n8n Cloud, also count executions against your plan: a sheet trigger that fires once per row uses far more executions than a scheduled workflow that reads the sheet and loops over it in one run.
Retries, error outputs and an error workflow
Three layers, each catching what the one before it cannot:
- Retry On Fail on the HTTP Request node handles transient failures: a 429, a 502 when the upstream source is briefly unavailable, a dropped connection. Our API does not bill for an upstream 502.
- The error output catches what retries could not fix. A 401 means the credential is
wrong and a 402 means the account is out of credits. Retrying these will not help, so write "Needs
manual check" and the status code to the sheet. A GSTIN that is not registered is not an error: it
comes back as a 200 with
taxpayer_data.status_codeset to 0, so route it on that field instead. - An error workflow catches the workflow itself failing: a sheet that was renamed, a Slack token that expired. Build a small workflow starting with an Error Trigger node that posts the failed workflow's name and execution link to Slack, then select it under the main workflow's Settings → Error Workflow.
Frequently asked questions
A note on accuracy. GST rules change often. This article reflects our understanding as of 23 September 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.