This workflow corresponds to n8n.io template #5836 — we link there as the canonical source.
The workflow JSON
Copy or download the full n8n JSON below. Paste it into a new n8n workflow, add your credentials, activate. Full import guide →
{
"id": "OcAQrF91wzWH3rOw",
"name": "Generate and Decode DIGIPIN",
"tags": [],
"nodes": [
{
"id": "882aa556-8ea2-4582-8230-7b0e13ad2fd1",
"name": "Respond to Webhook - Success",
"type": "n8n-nodes-base.respondToWebhook",
"position": [
340,
-140
],
"parameters": {
"options": {
"responseCode": 200
},
"respondWith": "json",
"responseBody": "={\n \"status\": \"Success\",\n \"lat\": \"{{ $json.query.lat }}\",\n \"lon\": \"{{ $json.query.lon }}\",\n \"digipin\": \"{{ $json.digipin }}\"\n} "
},
"typeVersion": 1.4
},
{
"id": "368240b0-cecf-46e7-9509-bfcb1afe7610",
"name": "Respond to Webhook - Error",
"type": "n8n-nodes-base.respondToWebhook",
"position": [
340,
60
],
"parameters": {
"options": {
"responseCode": 422
},
"respondWith": "json",
"responseBody": "={\n \"status\": \"Failed\",\n \"lat\": \"{{ $json.query.lat }}\",\n \"lon\": \"{{ $json.query.lon }}\",\n \"error\": \"{{ $json.error }}\"\n} "
},
"typeVersion": 1.4
},
{
"id": "b6c70cd6-3d5f-4215-989c-8a5e6a896564",
"name": "Switch - Check for Success",
"type": "n8n-nodes-base.switch",
"position": [
120,
-40
],
"parameters": {
"rules": {
"values": [
{
"outputKey": "digipin",
"conditions": {
"options": {
"version": 2,
"leftValue": "",
"caseSensitive": true,
"typeValidation": "strict"
},
"combinator": "and",
"conditions": [
{
"id": "3656e246-523a-4611-b563-8e66ae078d67",
"operator": {
"type": "string",
"operation": "exists",
"singleValue": true
},
"leftValue": "={{ $json.digipin }}",
"rightValue": ""
}
]
},
"renameOutput": true
},
{
"conditions": {
"options": {
"version": 2,
"leftValue": "",
"caseSensitive": true,
"typeValidation": "strict"
},
"combinator": "and",
"conditions": [
{
"id": "9b5ef11d-7833-41c3-8611-56cf11df2dcc",
"operator": {
"type": "string",
"operation": "exists",
"singleValue": true
},
"leftValue": "={{ $json.error }}",
"rightValue": ""
}
]
}
}
]
},
"options": {}
},
"typeVersion": 3.2
},
{
"id": "3a7dc7a2-9d19-467c-b651-143187d852d9",
"name": "DIGIPIN_Generation_Code",
"type": "n8n-nodes-base.code",
"position": [
-100,
-40
],
"parameters": {
"jsCode": "// --- DIGIPIN Generation Logic ---\n\n// Constants for DIGIPIN generation\nconst DIGIPIN_GRID = [\n ['F', 'C', '9', '8'],\n ['J', '3', '2', '7'],\n ['K', '4', '5', '6'],\n ['L', 'M', 'P', 'T']\n];\n\nconst BOUNDS = {\n minLat: 2.5,\n maxLat: 38.5,\n minLon: 63.5,\n maxLon: 99.5\n};\n\n/**\n * Encodes latitude and longitude into a DIGIPIN.\n * @param {number} lat The latitude.\n * @param {number} lon The longitude.\n * @returns {string} The generated DIGIPIN.\n * @throws {Error} If coordinates are out of bounds.\n */\nfunction generateDigiPin(lat, lon) {\n if (lat < BOUNDS.minLat || lat > BOUNDS.maxLat || lon < BOUNDS.minLon || lon > BOUNDS.maxLon) {\n throw new Error(`Coordinates (Lat: ${lat}, Lon: ${lon}) are out of the valid range.`);\n }\n\n let minLat = BOUNDS.minLat, maxLat = BOUNDS.maxLat;\n let minLon = BOUNDS.minLon, maxLon = BOUNDS.maxLon;\n let digiPin = '';\n\n for (let level = 1; level <= 10; level++) {\n const latDiv = (maxLat - minLat) / 4;\n const lonDiv = (maxLon - minLon) / 4;\n let row = 3 - Math.floor((lat - minLat) / latDiv);\n let col = Math.floor((lon - minLon) / lonDiv);\n row = Math.max(0, Math.min(row, 3));\n col = Math.max(0, Math.min(col, 3));\n digiPin += DIGIPIN_GRID[row][col];\n if (level === 3 || level === 6) {\n digiPin += '-';\n }\n maxLat = minLat + latDiv * (4 - row);\n minLat = minLat + latDiv * (3 - row);\n minLon = minLon + lonDiv * col;\n maxLon = minLon + lonDiv;\n }\n return digiPin;\n}\n\n\n// --- n8n Item Processing ---\n// Loop through each input item provided to the node.\nfor (const item of items) {\n try {\n // Get latitude and longitude from the input item's JSON data.\n // Assumes the previous node provides these fields.\n const lat = $input.first().json.query.lat;\n const lon = $input.first().json.query.lon;\n\n if (lat === undefined || lon === undefined) {\n throw new Error(\"Input item is missing 'latitude' or 'longitude' field.\");\n }\n\n // Generate the DIGIPIN.\n const digipinResult = generateDigiPin(lat, lon);\n\n // Add the result to a new field called 'digipin' in the item's JSON.\n item.json.digipin = digipinResult;\n\n } catch (error) {\n // If an error occurs, add an 'error' field to the item.\n // This helps with debugging in the n8n UI.\n item.json.error = error.message;\n }\n}\n\n// Return all the modified items to the next node in the workflow.\nreturn items;\n"
},
"typeVersion": 2
},
{
"id": "33aab4da-4b77-44fa-85c4-0ed165b416d3",
"name": "DIGIPIN_Decode_Code",
"type": "n8n-nodes-base.code",
"position": [
-100,
420
],
"parameters": {
"jsCode": "/**\n * Decodes a DIGIPIN into latitude and longitude coordinates.\n * @param {string} digiPin The DIGIPIN to decode.\n * @returns {{latitude: string, longitude: string}} An object containing the latitude and longitude,\n * each formatted to 6 decimal places.\n * @throws {Error} If the DIGIPIN is invalid or contains invalid characters.\n */\nconst DIGIPIN_GRID = [\n ['F', 'C', '9', '8'],\n ['J', '3', '2', '7'],\n ['K', '4', '5', '6'],\n ['L', 'M', 'P', 'T']\n];\n\n\nconst BOUNDS = {\n minLat: 2.5,\n maxLat: 38.5,\n minLon: 63.5,\n maxLon: 99.5\n};\nfunction getLatLngFromDigiPin(digiPin) {\n const pin = digiPin.replace(/-/g, ''); // Remove hyphens for processing\n if (pin.length !== 10) throw new Error('Invalid DIGIPIN: Must be 10 characters long after removing hyphens.');\n\n let minLat = BOUNDS.minLat;\n let maxLat = BOUNDS.maxLat;\n let minLon = BOUNDS.minLon;\n let maxLon = BOUNDS.minLon; // Corrected initial value here, should be BOUNDS.minLon\n\n // Recalculate maxLon for accurate initial bounds\n // Based on the original DIGIPIN generation, it should cover the whole range initially.\n maxLon = BOUNDS.maxLon;\n\n\n for (let i = 0; i < 10; i++) {\n const char = pin[i];\n let found = false;\n let ri = -1, ci = -1;\n\n for (let r = 0; r < 4; r++) {\n for (let c = 0; c < 4; c++) {\n if (DIGIPIN_GRID[r][c] === char) {\n ri = r;\n ci = c;\n found = true;\n break;\n }\n }\n if (found) break;\n }\n\n if (!found) throw new Error(`Invalid character '${char}' in DIGIPIN.`);\n\n const latDiv = (maxLat - minLat) / 4;\n const lonDiv = (maxLon - minLon) / 4;\n\n const lat1 = maxLat - latDiv * (ri + 1);\n const lat2 = maxLat - latDiv * ri;\n const lon1 = minLon + lonDiv * ci;\n const lon2 = minLon + lonDiv * (ci + 1);\n\n minLat = lat1;\n maxLat = lat2;\n minLon = lon1;\n maxLon = lon2;\n }\n\n const centerLat = (minLat + maxLat) / 2;\n const centerLon = (minLon + maxLon) / 2;\n\n return {\n latitude: centerLat.toFixed(6),\n longitude: centerLon.toFixed(6)\n };\n}\n\n\nconst MY_DIGIPIN = $input.first().json.query.digipin; // <--- REPLACE THIS with your desired DIGIPIN\n\n// Ensure there's at least one item to process, or create a dummy one\nlet outputItems = [];\nif (items.length === 0) {\n // If no items come into the node, create a blank one to attach results to\n outputItems.push({ json: {} });\n} else {\n // If items exist, clone them to add results\n outputItems = JSON.parse(JSON.stringify(items));\n}\n\nfor (const item of outputItems) {\n try {\n const digipinToProcess = MY_DIGIPIN;\n\n if (!digipinToProcess) {\n throw new Error(\"No DIGIPIN specified for processing.\");\n }\n\n // Decode the DIGIPIN\n const decodedCoords = getLatLngFromDigiPin(digipinToProcess);\n\n // Add the result to new fields in the item's JSON\n item.json.processedDigipin = digipinToProcess; // Optional: To see which digipin was processed\n item.json.decodedLatitude = decodedCoords.latitude;\n item.json.decodedLongitude = decodedCoords.longitude;\n\n } catch (error) {\n // If an error occurs, add an 'error' field to the item.\n item.json.error = error.message;\n }\n}\n\n// Return all the modified items to the next node in the workflow.\nreturn outputItems;"
},
"typeVersion": 2
},
{
"id": "6da5b090-caf7-4a8b-a254-a90ac9b97610",
"name": "Encode_Webhook",
"type": "n8n-nodes-base.webhook",
"position": [
-320,
-40
],
"parameters": {
"path": "generate-digipin",
"options": {},
"responseMode": "responseNode"
},
"typeVersion": 2
},
{
"id": "99a30d16-696a-4c2c-941d-7b66a6591d54",
"name": "Decode_Webhook",
"type": "n8n-nodes-base.webhook",
"position": [
-320,
420
],
"parameters": {
"path": "decode-digipin",
"options": {},
"responseMode": "responseNode"
},
"typeVersion": 2
},
{
"id": "ab871baf-aae7-4060-83af-7794974dce18",
"name": "Switch 2 - Check for Success1",
"type": "n8n-nodes-base.switch",
"position": [
120,
420
],
"parameters": {
"rules": {
"values": [
{
"outputKey": "coordinates",
"conditions": {
"options": {
"version": 2,
"leftValue": "",
"caseSensitive": true,
"typeValidation": "strict"
},
"combinator": "and",
"conditions": [
{
"id": "3656e246-523a-4611-b563-8e66ae078d67",
"operator": {
"type": "string",
"operation": "exists",
"singleValue": true
},
"leftValue": "={{ $json.decodedLatitude }}",
"rightValue": ""
}
]
},
"renameOutput": true
},
{
"conditions": {
"options": {
"version": 2,
"leftValue": "",
"caseSensitive": true,
"typeValidation": "strict"
},
"combinator": "and",
"conditions": [
{
"id": "9b5ef11d-7833-41c3-8611-56cf11df2dcc",
"operator": {
"type": "string",
"operation": "exists",
"singleValue": true
},
"leftValue": "={{ $json.error }}",
"rightValue": ""
}
]
}
}
]
},
"options": {}
},
"typeVersion": 3.2
},
{
"id": "64409e6c-e4aa-41b2-abcf-a016e729ea37",
"name": "Respond to Webhook - Success 2",
"type": "n8n-nodes-base.respondToWebhook",
"position": [
340,
320
],
"parameters": {
"options": {
"responseCode": 200
},
"respondWith": "json",
"responseBody": "={\n \"status\": \"Success\",\n \"digipin\": \"{{ $json.query.digipin }}\",\n \"lat\": \"{{ $json.decodedLatitude }}\",\n \"lon\": \"{{ $json.decodedLongitude }}\"\n} "
},
"typeVersion": 1.4
},
{
"id": "d37184ce-7060-4d06-b039-dd8572e7d3e8",
"name": "Respond to Webhook - Error 2",
"type": "n8n-nodes-base.respondToWebhook",
"position": [
340,
520
],
"parameters": {
"options": {
"responseCode": 422
},
"respondWith": "json",
"responseBody": "={\n \"status\": \"Failed\",\n \"digipin\": \"{{ $json.query.digipin }}\",\n \"error\": \"{{ $json.error }}\"\n} "
},
"typeVersion": 1.4
},
{
"id": "8d745b4f-f993-4865-a96f-e3f1e28a0cc2",
"name": "Sticky Note",
"type": "n8n-nodes-base.stickyNote",
"position": [
660,
360
],
"parameters": {
"color": 4,
"width": 920,
"height": 320,
"content": "## Example usage \n\nGenerate a DIGIPIN:\n```\ncurl --request GET \\\n --url 'https://n8n.example.in/webhook/generate-digipin?lat=27.175063&lon=78.042169'\n```\n\nDecode a DIGIPIN:\n```\ncurl --request GET \\\n --url 'https://n8n.example.in/webhook/decode-digipin?digipin=32C-849-5CJ6'\n```"
},
"typeVersion": 1
},
{
"id": "3cb47a09-ce41-4d2d-a413-885510ebda96",
"name": "Sticky Note1",
"type": "n8n-nodes-base.stickyNote",
"position": [
660,
-160
],
"parameters": {
"width": 920,
"height": 440,
"content": "## DIGIPIN Generator and Decoder\n\nThis n8n workflow lets you **generate and decode DIGIPINs** using only JavaScript - no external APIs involved.\n\nDIGIPIN is India Post\u2019s geolocation code system that encodes latitude and longitude into a 10-character alphanumeric string, like `32C-849-5CJ6`. It helps simplify precise location sharing across India.\n\n### \ud83d\udd27 What it does\n- `/generate-digipin?lat=...&lon=...` \u2192 returns the DIGIPIN for given coordinates\n- `/decode-digipin?digipin=...` \u2192 returns the coordinates for a given DIGIPIN\n\nUseful for: check-in systems, last-mile delivery, digital address verification, or simple location sharing.\n\n### \u2699\ufe0f How to use\n- Add your own webhook URLs or run locally\n- Pass query parameters to trigger either route\n- Both encode/decode logic is handled inside Function nodes\n\nNo credentials, APIs, or setup required.\n"
},
"typeVersion": 1
}
],
"active": true,
"settings": {
"executionOrder": "v1"
},
"versionId": "9226c009-d942-4f3c-b982-9f7dbb73d710",
"connections": {
"Decode_Webhook": {
"main": [
[
{
"node": "DIGIPIN_Decode_Code",
"type": "main",
"index": 0
}
]
]
},
"Encode_Webhook": {
"main": [
[
{
"node": "DIGIPIN_Generation_Code",
"type": "main",
"index": 0
}
]
]
},
"DIGIPIN_Decode_Code": {
"main": [
[
{
"node": "Switch 2 - Check for Success1",
"type": "main",
"index": 0
}
]
]
},
"DIGIPIN_Generation_Code": {
"main": [
[
{
"node": "Switch - Check for Success",
"type": "main",
"index": 0
}
]
]
},
"Switch - Check for Success": {
"main": [
[
{
"node": "Respond to Webhook - Success",
"type": "main",
"index": 0
}
],
[
{
"node": "Respond to Webhook - Error",
"type": "main",
"index": 0
}
]
]
},
"Switch 2 - Check for Success1": {
"main": [
[
{
"node": "Respond to Webhook - Success 2",
"type": "main",
"index": 0
}
],
[
{
"node": "Respond to Webhook - Error 2",
"type": "main",
"index": 0
}
]
]
}
}
}
For the full experience including quality scoring and batch install features for each workflow upgrade to Pro
About this workflow
This workflow contains community nodes that are only compatible with the self-hosted version of n8n.
Source: https://n8n.io/workflows/5836/ — original creator credit. Request a take-down →
Related workflows
Workflows that share integrations, category, or trigger type with this one. All free to copy and import.
A production-ready authentication workflow implementing secure user registration, login, token verification, and refresh token mechanisms. Perfect for adding authentication to any application without
Portfolio Orchestrator. Uses httpRequest. Webhook trigger; 59 nodes.
This n8n template demonstrates how a simple Multi-Layer Perceptron (MLP) neural network can predict housing prices. The prediction is based on four key features, processed through a three-layer model.
github code Try yourself
This workflow contains community nodes that are only compatible with the self-hosted version of n8n.