n8n workflow template
Package Tracking Sub-workflow
Called as a tool by an AI agent. Validates the tracking number, applies a per-user rate limit, calls your tracking API, and formats the result (or a specific, user-facing error) for the agent to relay verbatim.
Intermediate20-30 minutesn8nCustom Tracking API
01
What this workflow handles
- Real-time shipment status inside a chat conversation
- Built-in rate limiting to prevent abuse
- Clear, specific error messages per failure type (404, 429, timeout, etc.)
02
Setup steps
- 1Set the TRACKING_API_TOKEN environment variable in n8n
- 2Replace URL_TO_YOUR_TRACKING_WEBSITE with your real tracking endpoint
- 3Adjust the rate-limit thresholds to your needs
- 4Remove the leftover debug console.error line before going live
03
Values to replace
Review every placeholder below before activating this workflow. Public downloads should never include live credentials or client data.
- Tracking API base URL
- TRACKING_API_TOKEN env var
Workflow JSON preview
Review before downloading or importing.
{
"name": "TRACK_PACKAGE",
"nodes": [
{
"parameters": {
"workflowInputs": {
"values": [
{
"name": "tracking_number"
}
]
}
},
"id": "c055762a-8fe7-4141-a639-df2372f30060",
"typeVersion": 1.1,
"name": "When Executed by Another Workflow",
"type": "n8n-nodes-base.executeWorkflowTrigger",
"position": [
272,
352
]
},
{
"parameters": {
"jsCode": "//USED TO SEND REQUEST TO YOUR DB FOR PACKAGE INFO\n\nconst RATE_LIMIT_MAX = 5;\nconst RATE_LIMIT_WINDOW_MS = 60 * 1000;\nconst trackingNumber = $input.first().json.tracking_number;\nconst userId = $json.user_id || 'anonymous';\n\nconst token = $env.TRACKING_API_TOKEN;\nconst staticData = $getWorkflowStaticData('node');\nif (!staticData.rateLimits) staticData.rateLimits = {};\n\nif (!trackingNumber) {\n return [{ json: { error: true, errorMessage: 'Please enter a valid tracking number.', packageSummary: null } }];\n}\n\nconst now = Date.now();\nconst rl = staticData.rateLimits[userId] || { count: 0, windowStart: now };\nif (now - rl.windowStart > RATE_LIMIT_WINDOW_MS) {\n rl.count = 0;\n rl.windowStart = now;\n}\nif (rl.count >= RATE_LIMIT_MAX) {\n const retryAfterSec = Math.ceil((rl.windowStart + RATE_LIMIT_WINDOW_MS - now) / 1000);\n staticData.rateLimits[userId] = rl;\n return [{ json: { error: true, errorMessage: `You're tracking too many packages too quickly. Please wait ${retryAfterSec}s and try again.`, packageSummary: null } }];\n}\nrl.count += 1;\nstaticData.rateLimits[userId] = rl;\n\nif (!token) {\n return [{ json: { error: true, errorMessage: 'Tracking service is not configured. Please contact support.', packageSummary: null } }];\n}\n\ntry {\n const response = await this.helpers.httpRequest({\n method: 'GET',\n url: `URL_TO_YOUR_TRACKING_WEBSITE=${encodeURIComponent(trackingNumber)}`,\n headers: { Authorization: `Bearer ${token}`, Accept: 'application/json' },\n timeout: 15000,\n json: true\n });\n\n const pkg = response?.data;\n if (!pkg) {\n return [{ json: { error: true, errorMessage: 'No package data was returned. Please try again later.', packageSummary: null } }];\n }\n\n const packageSummary = [\n `📦 Tracking Number: ${pkg.tracking_number || trackingNumber}`,\n `🚚 Status: ${pkg.status || 'Not available'}`,\n `📍 Branch: ${pkg.branch || 'Not available'}`,\n `🚛 Courier: ${pkg.courier || 'Not available'}`,\n `💳 Payment Status: ${pkg.payment_status || 'Not available'}`,\n `💰 Price: ${pkg.price || 'Not available'}`,\n `📦 Quantity: ${pkg.quantity || 'Not available'}`,\n `⚖️ Weight: ${pkg.weight || 'Not available'}`,\n `🚢 Shipping Mode: ${pkg.shipping_mode || 'Not available'}`\n ].join('\\n');\n\n return [{ json: { error: false, errorMessage: '', packageSummary } }];\n\n} catch (error) {\n const status = error.statusCode || error.httpCode || error.response?.status;\n let errorMessage;\n switch (Number(status)) {\n case 400: errorMessage = 'The tracking request was malformed. Please try again.'; break;\n case 401: case 403: errorMessage = 'The tracking service authentication failed. Please contact support.'; break;\n case 404: errorMessage = 'I could not find a package with that tracking number. Please verify the number and try again.'; break;\n case 422: errorMessage = 'The tracking number format is invalid. Please check and try again.'; break;\n case 429: errorMessage = 'Too many tracking requests. Please wait a moment and try again.'; break;\n case 500: case 502: case 503: case 504: errorMessage = 'The tracking service is temporarily unavailable. Please try again shortly.'; break;\n default:\n errorMessage = error.code === 'ECONNABORTED' || /timeout/i.test(error.message || '')\n ? 'The tracking request took too long. Please try again.'\n : (!status ? 'I cannot connect to the tracking system right now. Please try again later.' : 'I was unable to retrieve your package information right now. Please try again later.');\n }\n\n return [{ json: { error: true, errorMessage, packageSummary: null } }];\n}"
},
"type": "n8n-nodes-base.code",
"typeVersion": 2,
"position": [
736,
352
],
"id": "ae4ac40f-95f5-4e15-997b-d7a22547f2ba",
"name": "Code in JavaScript"
},
{
"parameters": {
"assignments": {
"assignments": [
{
"id": "c07d57a2-8fdf-42ab-b7b2-f980f159bf84",
"name": "tracking_number",
"value": "={{ $json.tracking_number }}",
"type": "string"
}
]
},
"options": {}
},
"type": "n8n-nodes-base.set",
"typeVersion": 3.5,
"position": [
496,
352
],
"id": "59b05ae2-5d34-4f5b-9a86-22fe53fe21a2",
"name": "Edit Fields"
},
{
"parameters": {
"assignments": {
"assignments": [
{
"id": "919ad6d1-4fa8-4969-a327-7b7e2f7ef245",
"name": "packageSummary",
"value": "=Pass the message exactly to the user as-is below. Do not alter or rewrite: {{ $json.packageSummary }}",
"type": "string"
}
]
},
"options": {}
},
"type": "n8n-nodes-base.set",
"typeVersion": 3.5,
"position": [
960,
352
],
"id": "39f33ff2-97f9-47a9-99f5-fca56ff68fa2",
"name": "Edit Fields1"
}
],
"pinData": {},
"connections": {
"When Executed by Another Workflow": {
"main": [
[
{
"node": "Edit Fields",
"type": "main",
"index": 0
}
]
]
},
"Code in JavaScript": {
"main": [
[
{
"node": "Edit Fields1",
"type": "main",
"index": 0
}
]
]
},
"Edit Fields": {
"main": [
[
{
"node": "Code in JavaScript",
"type": "main",
"index": 0
}
]
]
}
},
"active": false,
"settings": {
"executionOrder": "v1",
"binaryMode": "separate"
},
"versionId": "9305c692-99ae-4933-8ce0-e6861f6f3cdb",
"nodeGroups": [],
"id": "gPfw39v8Yy6r0xz1",
"tags": []
}