Space is the most regulated industry most software companies never think about — until they're in it.
If your SaaS operates satellites, provides mission-critical software to a launch provider, sells data from space assets, or processes ITAR-controlled technical data for a space company, you're navigating FCC Part 25 (satellite licensing), ITAR 22 CFR Parts 120-130 (space technology as a US Munitions List item), NASA Procedural Requirements (NPR 8715.3, NPR 7120.5), FAA 14 CFR Part 460 (commercial space transportation), and potentially ESA/ECSS standards for European mission contracts.
Miss a license renewal and the FCC can terminate your satellite authorization. Let an ITAR export authorization lapse and you're looking at civil penalties up to $1.3M per violation. Let a NASA NPR review deadline slip and your program office gets a non-conformance that delays the whole mission.
Here are 5 n8n workflows that keep your SpaceTech ops inside the fence — with full import-ready JSON.
Why self-hosted n8n fits SpaceTech compliance
Space technology is almost always ITAR-controlled. The USML (US Munitions List) covers:
- Category IV — Launch vehicles, guided missiles, rockets
- Category XV — Spacecraft, satellites, ground control systems
- Category XI — Military electronics (often applies to satcom payload components)
Running automation workflows through Zapier or Make.com creates a ITAR data flow problem: technical parameters, orbital slot coordinates, telemetry thresholds, and spacecraft configuration data are ITAR-controlled technical data. Routing them through a commercial SaaS that isn't State Department-authorized as a cloud storage provider for ITAR data creates an unlicensed export risk.
Self-hosted n8n in a controlled environment keeps controlled technical data on-premises or in a government-compliant cloud (AWS GovCloud, Azure Government, Oracle Government Cloud).
Workflow 1: FCC Part 25 Satellite License Renewal Monitor
Regulation: FCC Part 25 — Space Station & Earth Station Licensing
FCC satellite licenses (space station authorizations and earth station licenses) have fixed expiration dates. There's no grace period — an expired authorization means you're operating an unlicensed transmitter, which is an FCC violation regardless of whether you were "just about to renew."
This workflow runs every morning, loads your satellite license registry from Google Sheets, calculates days remaining for each call sign, and routes alerts through CRITICAL (≤30d) → URGENT (≤60d) → WARNING (≤90d) → NOTICE (≤120d) tiers to your #regulatory-team Slack channel.
{
"name": "FCC Part 25 Satellite License Renewal Monitor",
"nodes": [
{
"parameters": {
"rule": {
"interval": [
{
"field": "cronExpression",
"expression": "0 8 * * *"
}
]
}
},
"id": "aa1b2c3d-1601-1601-1601-160100000001",
"name": "Daily 8AM",
"type": "n8n-nodes-base.scheduleTrigger",
"typeVersion": 1.2,
"position": [
250,
300
]
},
{
"parameters": {
"documentId": {
"__rl": true,
"value": "YOUR_SHEETS_ID",
"mode": "id"
},
"sheetName": {
"__rl": true,
"value": "satellite_licenses",
"mode": "name"
},
"options": {}
},
"id": "aa1b2c3d-1601-1601-1601-160100000002",
"name": "Load License Registry",
"type": "n8n-nodes-base.googleSheets",
"typeVersion": 4.4,
"position": [
470,
300
]
},
{
"parameters": {
"jsCode": "const today = new Date();\nconst results = [];\nfor (const item of $input.all()) {\n const row = item.json;\n if (!row.expiry_date || row.status === 'SURRENDERED') continue;\n const expiry = new Date(row.expiry_date);\n const daysLeft = Math.floor((expiry - today) / (1000 * 60 * 60 * 24));\n let urgency = null;\n if (daysLeft < 0) urgency = 'OVERDUE';\n else if (daysLeft <= 30) urgency = 'CRITICAL';\n else if (daysLeft <= 60) urgency = 'URGENT';\n else if (daysLeft <= 90) urgency = 'WARNING';\n else if (daysLeft <= 120) urgency = 'NOTICE';\n if (urgency) {\n results.push({ json: {\n callSign: row.call_sign,\n licenseType: row.license_type,\n orbitSlot: row.orbital_slot || 'N/A',\n frequency: row.frequency_band || 'N/A',\n expiryDate: row.expiry_date,\n daysLeft,\n urgency,\n fccUrl: 'https://licensing.fcc.gov/myibfs/',\n regulation: 'FCC Part 25 \u2014 Space Station & Earth Station Licensing',\n renewalLead: row.regulatory_counsel || 'regulatory@yourcompany.com'\n }});\n }\n}\nreturn results.length > 0 ? results : [{ json: { noAlertsNeeded: true } }];"
},
"id": "aa1b2c3d-1601-1601-1601-160100000003",
"name": "Classify License Risk",
"type": "n8n-nodes-base.code",
"typeVersion": 2,
"position": [
690,
300
]
},
{
"parameters": {
"conditions": {
"options": {
"caseSensitive": true,
"leftValue": "",
"typeValidation": "strict"
},
"conditions": [
{
"id": "cond1",
"leftValue": "={{ $json.noAlertsNeeded }}",
"rightValue": true,
"operator": {
"type": "boolean",
"operation": "notEqual"
}
}
],
"combinator": "and"
}
},
"id": "aa1b2c3d-1601-1601-1601-160100000004",
"name": "IF Alert Needed",
"type": "n8n-nodes-base.if",
"typeVersion": 2,
"position": [
910,
300
]
},
{
"parameters": {
"method": "POST",
"url": "https://hooks.slack.com/services/YOUR_SLACK_WEBHOOK",
"sendBody": true,
"bodyParameters": {
"parameters": [
{
"name": "text",
"value": "=:satellite: *{{ $json.urgency }} \u2014 FCC License Renewal*\n*Call Sign:* {{ $json.callSign }} ({{ $json.licenseType }})\n*Orbital Slot:* {{ $json.orbitSlot }} | *Band:* {{ $json.frequency }}\n*Expires:* {{ $json.expiryDate }} ({{ $json.daysLeft }} days)\n*Regulation:* {{ $json.regulation }}\n*FCC IBFS Portal:* {{ $json.fccUrl }}\n*Regulatory Counsel:* {{ $json.renewalLead }}\n*Note:* License lapses are not self-correcting \u2014 FCC may terminate authorization."
}
]
}
},
"id": "aa1b2c3d-1601-1601-1601-160100000005",
"name": "Slack #regulatory-team",
"type": "n8n-nodes-base.httpRequest",
"typeVersion": 4.2,
"position": [
1130,
200
]
}
],
"connections": {
"Daily 8AM": {
"main": [
[
{
"node": "Load License Registry",
"type": "main",
"index": 0
}
]
]
},
"Load License Registry": {
"main": [
[
{
"node": "Classify License Risk",
"type": "main",
"index": 0
}
]
]
},
"Classify License Risk": {
"main": [
[
{
"node": "IF Alert Needed",
"type": "main",
"index": 0
}
]
]
},
"IF Alert Needed": {
"main": [
[
{
"node": "Slack #regulatory-team",
"type": "main",
"index": 0
}
],
[]
]
}
},
"settings": {
"executionOrder": "v1"
}
}
Setup:
- Create a Sheets tab
satellite_licenseswith columns:call_sign,license_type(SPACE_STATION/EARTH_STATION/VSAT),orbital_slot,frequency_band,expiry_date,status,regulatory_counsel - Replace
YOUR_SLACK_WEBHOOKwith your#regulatory-teamSlack webhook - FCC license renewals are filed through IBFS:
https://licensing.fcc.gov/myibfs/ - For ITU coordination (non-US orbital slots), add a branch to route to your ITU coordinator
FCC Part 25.121(a): Fixed-satellite service space station licenses are issued for 15-year terms. Non-geostationary (NGSO) mega-constellation licenses follow a 15-year term with milestone requirements (bond posting, partial deployment).
Workflow 2: ITAR Part 121 Space Technology Export Authorization Monitor
Regulation: ITAR 22 CFR Parts 120-130 — State Department DDTC
Space technology is one of the most heavily ITAR-controlled categories. Launch vehicles (Cat IV), spacecraft and satellites (Cat XV), and space electronics (Cat XI) require State Department authorization (DSP-5, Technical Assistance Agreement, Manufacturing License Agreement) before any export — including cloud access by a foreign national.
This workflow monitors your export authorization register, escalates expiring authorizations with specific DDTC renewal portal links, and emails your export-control counsel directly for CRITICAL and EXPIRED items.
{
"name": "ITAR Part 121 Space Technology Export Authorization Monitor",
"nodes": [
{
"parameters": {
"rule": {
"interval": [
{
"field": "cronExpression",
"expression": "0 7 * * *"
}
]
}
},
"id": "bb2c3d4e-1602-1602-1602-160200000001",
"name": "Daily 7AM",
"type": "n8n-nodes-base.scheduleTrigger",
"typeVersion": 1.2,
"position": [
250,
300
]
},
{
"parameters": {
"documentId": {
"__rl": true,
"value": "YOUR_SHEETS_ID",
"mode": "id"
},
"sheetName": {
"__rl": true,
"value": "itar_authorizations",
"mode": "name"
},
"options": {}
},
"id": "bb2c3d4e-1602-1602-1602-160200000002",
"name": "Load Export Authorizations",
"type": "n8n-nodes-base.googleSheets",
"typeVersion": 4.4,
"position": [
470,
300
]
},
{
"parameters": {
"jsCode": "const today = new Date();\nconst results = [];\nfor (const item of $input.all()) {\n const row = item.json;\n if (!row.expiry_date || row.status === 'CLOSED') continue;\n const expiry = new Date(row.expiry_date);\n const daysLeft = Math.floor((expiry - today) / (1000 * 60 * 60 * 24));\n let urgency = null;\n if (daysLeft < 0) urgency = 'EXPIRED';\n else if (daysLeft <= 14) urgency = 'CRITICAL';\n else if (daysLeft <= 45) urgency = 'URGENT';\n else if (daysLeft <= 90) urgency = 'WARNING';\n else if (daysLeft <= 120) urgency = 'NOTICE';\n if (urgency) {\n const umlCategory = row.usml_category || 'Category XV (Spacecraft)';\n results.push({ json: {\n authorizationNumber: row.authorization_number,\n authType: row.authorization_type,\n umlCategory,\n destinationCountry: row.destination_country,\n technology: row.technology_description,\n expiryDate: row.expiry_date,\n daysLeft,\n urgency,\n renewalPortal: 'https://deccs.pmdtc.state.gov',\n regulation: 'ITAR 22 CFR Parts 120-130 \u2014 ' + umlCategory,\n penalty: 'Civil: up to $1.3M/violation | Criminal: up to $1M + 20yr'\n }});\n }\n}\nreturn results.length > 0 ? results : [{ json: { noAlertsNeeded: true } }];"
},
"id": "bb2c3d4e-1602-1602-1602-160200000003",
"name": "Calculate Expiry Risk",
"type": "n8n-nodes-base.code",
"typeVersion": 2,
"position": [
690,
300
]
},
{
"parameters": {
"conditions": {
"options": {
"caseSensitive": true,
"leftValue": "",
"typeValidation": "strict"
},
"conditions": [
{
"id": "cond1",
"leftValue": "={{ $json.noAlertsNeeded }}",
"rightValue": true,
"operator": {
"type": "boolean",
"operation": "notEqual"
}
}
],
"combinator": "and"
}
},
"id": "bb2c3d4e-1602-1602-1602-160200000004",
"name": "IF Alert Needed",
"type": "n8n-nodes-base.if",
"typeVersion": 2,
"position": [
910,
300
]
},
{
"parameters": {
"method": "POST",
"url": "https://hooks.slack.com/services/YOUR_SLACK_WEBHOOK",
"sendBody": true,
"bodyParameters": {
"parameters": [
{
"name": "text",
"value": "=:rotating_light: *{{ $json.urgency }} \u2014 ITAR Export Authorization*\n*Auth #:* {{ $json.authorizationNumber }} ({{ $json.authType }})\n*USML:* {{ $json.regulation }}\n*Technology:* {{ $json.technology }}\n*Destination:* {{ $json.destinationCountry }}\n*Expires:* {{ $json.expiryDate }} ({{ $json.daysLeft }} days)\n*Renewal:* {{ $json.renewalPortal }}\n*Penalty exposure:* {{ $json.penalty }}\n*Action:* Begin DSP-5/TAA/MLA renewal 90+ days before expiry."
}
]
}
},
"id": "bb2c3d4e-1602-1602-1602-160200000005",
"name": "Slack #export-control",
"type": "n8n-nodes-base.httpRequest",
"typeVersion": 4.2,
"position": [
1130,
200
]
},
{
"parameters": {
"sendTo": "export-control@yourcompany.com",
"subject": "=ACTION {{ $json.urgency }}: ITAR Auth {{ $json.authorizationNumber }} expires {{ $json.expiryDate }}",
"message": "=ITAR Authorization Alert\n\nAuthorization: {{ $json.authorizationNumber }}\nType: {{ $json.authType }}\nUSML Category: {{ $json.regulation }}\nTechnology: {{ $json.technology }}\nDestination Country: {{ $json.destinationCountry }}\nExpiry: {{ $json.expiryDate }} ({{ $json.daysLeft }} days remaining)\nUrgency: {{ $json.urgency }}\n\nRenewal Portal (DDTC D-Trade): {{ $json.renewalPortal }}\n\nPenalty exposure for operating under an expired authorization:\n{{ $json.penalty }}\n\nBegin renewal immediately. DDTC processing times are 30-60 days for DSP-5 renewals.\n\n-- Automated alert from n8n compliance system",
"options": {}
},
"id": "bb2c3d4e-1602-1602-1602-160200000006",
"name": "Email Export Control Team",
"type": "n8n-nodes-base.gmail",
"typeVersion": 2.1,
"position": [
1130,
400
]
}
],
"connections": {
"Daily 7AM": {
"main": [
[
{
"node": "Load Export Authorizations",
"type": "main",
"index": 0
}
]
]
},
"Load Export Authorizations": {
"main": [
[
{
"node": "Calculate Expiry Risk",
"type": "main",
"index": 0
}
]
]
},
"Calculate Expiry Risk": {
"main": [
[
{
"node": "IF Alert Needed",
"type": "main",
"index": 0
}
]
]
},
"IF Alert Needed": {
"main": [
[
{
"node": "Slack #export-control",
"type": "main",
"index": 0
},
{
"node": "Email Export Control Team",
"type": "main",
"index": 0
}
],
[]
]
}
},
"settings": {
"executionOrder": "v1"
}
}
Setup:
- Create a Sheets tab
itar_authorizationswith columns:authorization_number,authorization_type(DSP-5/TAA/MLA/STA),usml_category,technology_description,destination_country,expiry_date,status,renewal_contact - DSP-5 permanent export licenses renew at:
https://deccs.pmdtc.state.gov - Add a column
foreign_national_access— if any foreign nationals have cloud access to ITAR data, this is a deemed export that also needs authorization
Key fact: ITAR processing at DDTC averages 30-60 days. Set your WARNING threshold to 90 days to leave time for back-and-forth with DDTC reviewers.
Workflow 3: NASA NPR Program Milestone & Compliance Tracker
Regulation: NPR 8715.3 (Safety), NPR 7120.5 (Project Management), NPR 2200.2 (Technical Standards), FAA 14 CFR Part 460
NASA programs are governed by a dense web of Procedural Requirements. NPR 7120.5 defines the project lifecycle reviews (SRR, PDR, CDR, SAR, ORR, FRR). NPR 8715.3 mandates safety reviews at each phase. FAA 14 CFR Part 460 governs commercial human spaceflight. ECSS standards apply to ESA mission contracts.
This workflow loads your program milestone tracker from Sheets every weekday morning and posts classified alerts (OVERDUE → CRITICAL → URGENT → WARNING → NOTICE) to #mission-management, grouped by regulation type.
{
"name": "NASA NPR Program Milestone & Compliance Tracker",
"nodes": [
{
"parameters": {
"rule": {
"interval": [
{
"field": "cronExpression",
"expression": "0 8 * * 1-5"
}
]
}
},
"id": "cc3d4e5f-1603-1603-1603-160300000001",
"name": "Weekdays 8AM",
"type": "n8n-nodes-base.scheduleTrigger",
"typeVersion": 1.2,
"position": [
250,
300
]
},
{
"parameters": {
"documentId": {
"__rl": true,
"value": "YOUR_SHEETS_ID",
"mode": "id"
},
"sheetName": {
"__rl": true,
"value": "nasa_milestones",
"mode": "name"
},
"options": {}
},
"id": "cc3d4e5f-1603-1603-1603-160300000002",
"name": "Load Program Milestones",
"type": "n8n-nodes-base.googleSheets",
"typeVersion": 4.4,
"position": [
470,
300
]
},
{
"parameters": {
"jsCode": "const today = new Date();\nconst overdue = [], critical = [], urgent = [], warning = [], notice = [];\nfor (const item of $input.all()) {\n const row = item.json;\n if (row.status === 'COMPLETE' || !row.due_date) continue;\n const due = new Date(row.due_date);\n const daysLeft = Math.floor((due - today) / (1000 * 60 * 60 * 24));\n const nprTypes = {\n 'NPR_8715_3': 'NPR 8715.3 \u2014 Safety & Mission Assurance',\n 'NPR_8715_5': 'NPR 8715.5 \u2014 Range Safety',\n 'NPR_7120_5': 'NPR 7120.5 \u2014 Project Management',\n 'NPR_2200_2': 'NPR 2200.2 \u2014 Technical Standards',\n 'FAA_460': 'FAA 14 CFR Part 460 \u2014 Commercial Space',\n 'ESA_ECSS': 'ECSS \u2014 European Cooperation for Space Standardization'\n };\n const rec = {\n program: row.program_name,\n milestone: row.milestone_name,\n regulation: nprTypes[row.npr_type] || row.npr_type,\n dueDate: row.due_date,\n owner: row.owner,\n daysLeft\n };\n if (daysLeft < 0) overdue.push(rec);\n else if (daysLeft <= 7) critical.push(rec);\n else if (daysLeft <= 21) urgent.push(rec);\n else if (daysLeft <= 45) warning.push(rec);\n else if (daysLeft <= 60) notice.push(rec);\n}\nconst total = overdue.length + critical.length + urgent.length + warning.length + notice.length;\nreturn [{ json: { overdue, critical, urgent, warning, notice, total, timestamp: today.toISOString() } }];"
},
"id": "cc3d4e5f-1603-1603-1603-160300000003",
"name": "Classify Milestone Risk",
"type": "n8n-nodes-base.code",
"typeVersion": 2,
"position": [
690,
300
]
},
{
"parameters": {
"conditions": {
"options": {
"caseSensitive": true,
"leftValue": "",
"typeValidation": "strict"
},
"conditions": [
{
"id": "cond1",
"leftValue": "={{ $json.total }}",
"rightValue": 0,
"operator": {
"type": "number",
"operation": "gt"
}
}
],
"combinator": "and"
}
},
"id": "cc3d4e5f-1603-1603-1603-160300000004",
"name": "IF Milestones At Risk",
"type": "n8n-nodes-base.if",
"typeVersion": 2,
"position": [
910,
300
]
},
{
"parameters": {
"method": "POST",
"url": "https://hooks.slack.com/services/YOUR_SLACK_WEBHOOK",
"sendBody": true,
"bodyParameters": {
"parameters": [
{
"name": "text",
"value": "=:rocket: *NASA NPR Milestone Alert \u2014 {{ $json.total }} item(s) require attention*\n{{ $json.overdue.length > 0 ? ':red_circle: OVERDUE (' + $json.overdue.length + '):\\n' + $json.overdue.map(m => `\u2022 ${m.program}: ${m.milestone} (${m.regulation}) \u2014 Owner: ${m.owner}`).join('\\n') + '\\n' : '' }}{{ $json.critical.length > 0 ? ':orange_circle: CRITICAL \u22647d (' + $json.critical.length + '):\\n' + $json.critical.map(m => `\u2022 ${m.program}: ${m.milestone} \u2014 ${m.daysLeft}d \u2014 ${m.owner}`).join('\\n') + '\\n' : '' }}{{ $json.urgent.length > 0 ? ':yellow_circle: URGENT \u226421d (' + $json.urgent.length + '):\\n' + $json.urgent.map(m => `\u2022 ${m.program}: ${m.milestone} \u2014 ${m.daysLeft}d`).join('\\n') + '\\n' : '' }}"
}
]
}
},
"id": "cc3d4e5f-1603-1603-1603-160300000005",
"name": "Slack #mission-management",
"type": "n8n-nodes-base.httpRequest",
"typeVersion": 4.2,
"position": [
1130,
300
]
}
],
"connections": {
"Weekdays 8AM": {
"main": [
[
{
"node": "Load Program Milestones",
"type": "main",
"index": 0
}
]
]
},
"Load Program Milestones": {
"main": [
[
{
"node": "Classify Milestone Risk",
"type": "main",
"index": 0
}
]
]
},
"Classify Milestone Risk": {
"main": [
[
{
"node": "IF Milestones At Risk",
"type": "main",
"index": 0
}
]
]
},
"IF Milestones At Risk": {
"main": [
[
{
"node": "Slack #mission-management",
"type": "main",
"index": 0
}
],
[]
]
}
},
"settings": {
"executionOrder": "v1"
}
}
Setup:
- Create a Sheets tab
nasa_milestoneswith columns:program_name,milestone_name,npr_type(NPR_8715_3/NPR_7120_5/NPR_2200_2/FAA_460/ESA_ECSS),due_date,owner,status - Pre-populate with Phase A/B/C/D reviews from your program plan
- Add a Gmail send node to email program managers for OVERDUE and CRITICAL items
Workflow 4: Space Asset Telemetry Anomaly Pipeline
Standards: CCSDS (Consultative Committee for Space Data Systems) telemetry packets, ITU-R radio regulations
When a satellite or spacecraft reports an anomaly, the mission operations center needs immediate, structured notification — not a raw telemetry dump. This webhook-based pipeline receives alerts from your ground station software (or CCSDS packet processor), classifies severity (CRITICAL → ANOMALY → DEGRADED → WATCH), notifies #mission-ops in Slack, and logs every incident to a structured anomaly register.
{
"name": "Space Asset Telemetry Anomaly Pipeline",
"nodes": [
{
"parameters": {
"httpMethod": "POST",
"path": "space-anomaly",
"responseMode": "responseNode",
"options": {}
},
"id": "dd4e5f60-1604-1604-1604-160400000001",
"name": "Webhook \u2014 Telemetry Anomaly",
"type": "n8n-nodes-base.webhook",
"typeVersion": 2,
"position": [
250,
300
]
},
{
"parameters": {
"jsCode": "const body = $input.first().json;\nconst anomalyType = body.anomaly_type || 'UNKNOWN';\nconst asset = body.asset_id || 'Unknown Asset';\nconst missionPhase = body.mission_phase || 'OPERATIONS';\nconst telemetry = body.telemetry_values || {};\nconst severityMap = {\n 'TOTAL_LOSS_OF_CONTACT': 'CRITICAL',\n 'THRUSTER_ANOMALY': 'CRITICAL',\n 'POWER_SYSTEM_CRITICAL': 'CRITICAL',\n 'ATTITUDE_CONTROL_ANOMALY': 'ANOMALY',\n 'PAYLOAD_ANOMALY': 'ANOMALY',\n 'THERMAL_OUT_OF_RANGE': 'DEGRADED',\n 'COMM_LINK_DEGRADED': 'DEGRADED',\n 'BATTERY_VOLTAGE_LOW': 'DEGRADED',\n 'SENSOR_FAULT': 'WATCH'\n};\nconst severity = severityMap[anomalyType] || 'WATCH';\nconst ccsdsPacketId = body.ccsds_apid ? `APID: ${body.ccsds_apid}` : 'CCSDS APID not provided';\nreturn [{ json: {\n incidentId: `SA-${Date.now()}`,\n asset,\n anomalyType,\n severity,\n missionPhase,\n ccsdsPacketId,\n telemetry,\n detectedAt: new Date().toISOString(),\n escalate: ['CRITICAL','ANOMALY'].includes(severity)\n} }];"
},
"id": "dd4e5f60-1604-1604-1604-160400000002",
"name": "Classify Anomaly",
"type": "n8n-nodes-base.code",
"typeVersion": 2,
"position": [
470,
300
]
},
{
"parameters": {
"method": "POST",
"url": "https://hooks.slack.com/services/YOUR_SLACK_WEBHOOK",
"sendBody": true,
"bodyParameters": {
"parameters": [
{
"name": "text",
"value": "=:satellite: *{{ $json.severity }} \u2014 {{ $json.anomalyType }}*\n*Asset:* {{ $json.asset }}\n*Phase:* {{ $json.missionPhase }}\n*Detected:* {{ $json.detectedAt }}\n*{{ $json.ccsdsPacketId }}*\n*Incident ID:* {{ $json.incidentId }}\n{{ $json.escalate ? ':rotating_light: ESCALATE \u2014 Wake on-call mission controller immediately.' : ':eyes: MONITOR \u2014 Review telemetry trend.' }}"
}
]
}
},
"id": "dd4e5f60-1604-1604-1604-160400000003",
"name": "Slack #mission-ops",
"type": "n8n-nodes-base.httpRequest",
"typeVersion": 4.2,
"position": [
690,
200
]
},
{
"parameters": {
"operation": "upsert",
"documentId": {
"__rl": true,
"value": "YOUR_SHEETS_ID",
"mode": "id"
},
"sheetName": {
"__rl": true,
"value": "anomaly_log",
"mode": "name"
},
"columns": {
"mappingMode": "defineBelow",
"value": {
"incident_id": "={{ $json.incidentId }}",
"asset": "={{ $json.asset }}",
"anomaly_type": "={{ $json.anomalyType }}",
"severity": "={{ $json.severity }}",
"detected_at": "={{ $json.detectedAt }}",
"status": "OPEN"
}
},
"options": {}
},
"id": "dd4e5f60-1604-1604-1604-160400000004",
"name": "Log to Anomaly Register",
"type": "n8n-nodes-base.googleSheets",
"typeVersion": 4.4,
"position": [
690,
400
]
}
],
"connections": {
"Webhook \u2014 Telemetry Anomaly": {
"main": [
[
{
"node": "Classify Anomaly",
"type": "main",
"index": 0
}
]
]
},
"Classify Anomaly": {
"main": [
[
{
"node": "Slack #mission-ops",
"type": "main",
"index": 0
},
{
"node": "Log to Anomaly Register",
"type": "main",
"index": 0
}
]
]
}
},
"settings": {
"executionOrder": "v1"
}
}
Setup:
- Activate the webhook and note the production URL
- Wire your ground station software (COSMOS, OpenMCT, YAMCS, or custom) to POST anomaly events to this webhook
- Add a Wait node + second Slack alert for CRITICAL items that haven't been acknowledged within 15 minutes
- For CCSDS APID reference, maintain a mapping table in Sheets:
apid_map(apid_hex → subsystem_name → alert_owner)
Workflow 5: Weekly SpaceTech Platform KPI Dashboard
Covers: Platform health, MRR/ARR trends, ITAR review queue depth, FCC license risk, compliance incident count
Every Monday morning, this workflow loads your platform metrics and compliance event log, builds a color-coded HTML dashboard, and emails it to the CEO with a BCC to the CISO. The CISO BCC is intentional — it creates a documented governance loop where compliance status is reviewed at the executive level weekly, which is exactly what ITAR regulations expect of a Registered Exporter.
{
"name": "Weekly SpaceTech Platform KPI Dashboard",
"nodes": [
{
"parameters": {
"rule": {
"interval": [
{
"field": "cronExpression",
"expression": "0 8 * * 1"
}
]
}
},
"id": "ee5f6071-1605-1605-1605-160500000001",
"name": "Monday 8AM",
"type": "n8n-nodes-base.scheduleTrigger",
"typeVersion": 1.2,
"position": [
250,
300
]
},
{
"parameters": {
"documentId": {
"__rl": true,
"value": "YOUR_SHEETS_ID",
"mode": "id"
},
"sheetName": {
"__rl": true,
"value": "platform_metrics",
"mode": "name"
},
"options": {}
},
"id": "ee5f6071-1605-1605-1605-160500000002",
"name": "Load Platform Metrics",
"type": "n8n-nodes-base.googleSheets",
"typeVersion": 4.4,
"position": [
470,
300
]
},
{
"parameters": {
"documentId": {
"__rl": true,
"value": "YOUR_SHEETS_ID",
"mode": "id"
},
"sheetName": {
"__rl": true,
"value": "compliance_events",
"mode": "name"
},
"options": {}
},
"id": "ee5f6071-1605-1605-1605-160500000003",
"name": "Load Compliance Events",
"type": "n8n-nodes-base.googleSheets",
"typeVersion": 4.4,
"position": [
470,
500
]
},
{
"parameters": {
"jsCode": "const metrics = $('Load Platform Metrics').all()[0]?.json || {};\nconst compEvents = $('Load Compliance Events').all();\nconst thisWeek = compEvents.filter(e => {\n const d = new Date(e.json.event_date);\n const now = new Date();\n return (now - d) <= 7 * 24 * 60 * 60 * 1000;\n});\nconst itarPending = compEvents.filter(e => e.json.event_type === 'ITAR_REVIEW' && e.json.status === 'PENDING').length;\nconst fccAtRisk = compEvents.filter(e => e.json.event_type === 'FCC_LICENSE' && ['CRITICAL','URGENT'].includes(e.json.urgency)).length;\nconst mrrWoW = metrics.mrr_wow_pct ? parseFloat(metrics.mrr_wow_pct).toFixed(1) : '0.0';\nconst statusColor = parseFloat(mrrWoW) >= 0 ? '#27ae60' : '#e74c3c';\nconst html = `\n<html><body style=\"font-family:Arial,sans-serif;max-width:720px;margin:auto\">\n<h2 style=\"color:#1a237e\">SpaceTech Platform KPI \u2014 Week of ${new Date().toISOString().split('T')[0]}</h2>\n<table border=\"1\" cellpadding=\"8\" style=\"border-collapse:collapse;width:100%\">\n<tr style=\"background:#1a237e;color:white\"><th>Metric</th><th>This Week</th><th>Status</th></tr>\n<tr><td>MRR</td><td>$${parseFloat(metrics.mrr||0).toLocaleString()}</td><td style=\"color:${statusColor}\">${mrrWoW}% WoW</td></tr>\n<tr><td>Active Platform Users</td><td>${metrics.active_users||0}</td><td>${metrics.active_users_wow ? metrics.active_users_wow+'% WoW' : '-'}</td></tr>\n<tr><td>API Calls This Week</td><td>${parseFloat(metrics.api_calls||0).toLocaleString()}</td><td>-</td></tr>\n<tr><td>Compliance Incidents (7d)</td><td>${thisWeek.length}</td><td>${thisWeek.length > 0 ? '<span style=\"color:#c0392b\">REVIEW</span>' : '<span style=\"color:#27ae60\">CLEAR</span>'}</td></tr>\n<tr><td>ITAR Reviews Pending</td><td>${itarPending}</td><td>${itarPending > 0 ? '<span style=\"color:#c0392b\">ACTION NEEDED</span>' : '<span style=\"color:#27ae60\">CLEAR</span>'}</td></tr>\n<tr><td>FCC Licenses At Risk</td><td>${fccAtRisk}</td><td>${fccAtRisk > 0 ? '<span style=\"color:#e74c3c\">AT RISK</span>' : '<span style=\"color:#27ae60\">CLEAR</span>'}</td></tr>\n</table>\n<p style=\"color:#888;font-size:11px\">n8n \u2014 FlowKit | ITAR 22 CFR Parts 120-130 | FCC Part 25 | NASA NPR 8715.3</p>\n</body></html>`;\nreturn [{ json: { html, mrrWoW, itarPending, fccAtRisk, timestamp: new Date().toISOString() } }];"
},
"id": "ee5f6071-1605-1605-1605-160500000004",
"name": "Build KPI Dashboard",
"type": "n8n-nodes-base.code",
"typeVersion": 2,
"position": [
710,
400
]
},
{
"parameters": {
"sendTo": "ceo@yourcompany.com",
"subject": "=Weekly SpaceTech KPI \u2014 {{ $json.timestamp.split('T')[0] }}{{ $json.itarPending > 0 || $json.fccAtRisk > 0 ? ' \u26a0\ufe0f ACTION NEEDED' : '' }}",
"message": "={{ $json.html }}",
"options": {
"appendAttribution": false,
"bccList": "ciso@yourcompany.com"
}
},
"id": "ee5f6071-1605-1605-1605-160500000005",
"name": "Email CEO + BCC CISO",
"type": "n8n-nodes-base.gmail",
"typeVersion": 2.1,
"position": [
950,
400
]
}
],
"connections": {
"Monday 8AM": {
"main": [
[
{
"node": "Load Platform Metrics",
"type": "main",
"index": 0
},
{
"node": "Load Compliance Events",
"type": "main",
"index": 0
}
]
]
},
"Load Platform Metrics": {
"main": [
[
{
"node": "Build KPI Dashboard",
"type": "main",
"index": 0
}
]
]
},
"Load Compliance Events": {
"main": [
[
{
"node": "Build KPI Dashboard",
"type": "main",
"index": 0
}
]
]
},
"Build KPI Dashboard": {
"main": [
[
{
"node": "Email CEO + BCC CISO",
"type": "main",
"index": 0
}
]
]
}
},
"settings": {
"executionOrder": "v1"
}
}
Setup:
- Create two Sheets tabs:
platform_metrics(mrr, active_users, api_calls, mrr_wow_pct, active_users_wow) andcompliance_events(event_type, event_date, urgency, status) - Replace email addresses with your CEO, CISO, and compliance team
- Add a Slack node to post a one-liner summary to
#leadershipalongside the email
n8n vs Zapier/Make for SpaceTech
| Requirement | n8n (self-hosted) | Zapier | Make.com |
|---|---|---|---|
| ITAR technical data stays on-premises | ✅ Yes | ❌ Flows through Zapier cloud | ❌ Flows through Make cloud |
| Deemed export risk (foreign nationals) | ✅ Controlled environment | ❌ Potential unlicensed access | ❌ Potential unlicensed access |
| Offline / air-gapped operation | ✅ Possible | ❌ No | ❌ No |
| Git-versionable workflows (NPR 2200.2 documentation) | ✅ JSON export | ❌ No | ❌ No |
| NASA NPR audit trail | ✅ Execution log + Git | ❌ No | ❌ No |
| CCSDS / ground station integration | ✅ Any HTTP webhook | Limited | Limited |
Bottom line: SpaceTech companies that handle ITAR-controlled technical data have a compliance obligation to control where that data flows. Self-hosted n8n is the only automation option that keeps your workflows inside your authorized enclave.
Get the workflows
These workflows and 14 others are available at FlowKit — n8n Automation Templates.
Topics covered: Email auto-responder, social cross-poster, invoice generator, AI customer support bot, lead capture to CRM, content repurposer, price monitor, daily report generator, webhook to database, appointment reminder, and more.
Individual templates: $12–$29. Full bundle (15 templates): $97.
Building space mission ops automation or compliance tracking? Drop a comment — happy to discuss specific NPR requirements or ITAR workflow design.
Top comments (0)