-
Notifications
You must be signed in to change notification settings - Fork 3
n8n Companion Workflows
Setup Manager HUD should remain the real-time dashboard. n8n is a good companion for automation: receive the same Setup Manager webhook, store a copy, and notify a team when a finished enrollment has failed actions.
Use one of these workflows:
- Slack workflow: store every webhook and post failed-action alerts to Slack.
- Teams workflow: store every webhook and post failed-action alerts to Microsoft Teams.
The two workflows are intentionally separate so a customer can import or build only the notification target they use.
For n8n reference, see the official docs for the Webhook node, Data Table node, HTTP Request node, and workflow import/export.
Create one n8n Data Table named setup_manager_events with these columns:
| Column | Type | Notes |
|---|---|---|
event_id |
String | Stable event identifier generated by n8n |
received_at |
Date/time or String | When n8n received the webhook |
event |
String | Setup Manager event name |
serial_number |
String | Device serial number |
model_name |
String | Device model |
macos_version |
String | macOS version |
started_at |
String | Setup Manager started timestamp |
finished_at |
String | Setup Manager finished timestamp, if present |
duration_seconds |
Number | Finished enrollment duration, if present |
failed_action_count |
Number | Number of failed enrollment actions |
failed_action_labels |
String | Comma-separated failed action names |
payload_json |
String | Full webhook payload copy |
Create a separate token for n8n, for example N8N_WEBHOOK_TOKEN, and save it securely. Do not reuse a live customer token in public examples.
Important
Setup Manager sends the token value as the raw Authorization header. In the n8n Webhook node, use Header Auth with header name Authorization and the exact token value.
There are two safe patterns:
- Sidecar: Setup Manager sends events to Setup Manager HUD and n8n if your Setup Manager version and profile structure support multiple destinations.
- Forwarding layer: Setup Manager sends events to n8n, then n8n stores, alerts, and forwards the unchanged payload to Setup Manager HUD.
Do not accidentally replace Setup Manager HUD with n8n unless that is your intent. Setup Manager HUD should still receive the webhook if you want the dashboard, D1 history, and live view to stay current.
Example n8n webhook target values:
<key>webhooks</key>
<dict>
<key>started</key>
<dict>
<key>url</key>
<string>https://your-n8n.example.com/webhook/setup-manager-hud-slack</string>
<key>token</key>
<string>your-n8n-webhook-token-here</string>
</dict>
<key>finished</key>
<dict>
<key>url</key>
<string>https://your-n8n.example.com/webhook/setup-manager-hud-slack</string>
<key>token</key>
<string>your-n8n-webhook-token-here</string>
</dict>
</dict>For the Teams workflow, use the Teams path instead:
https://your-n8n.example.com/webhook/setup-manager-hud-teams
Use this Code node after the Webhook node in both workflows.
const input = $input.first().json;
const payload = input.body ?? input;
const required = [
"name",
"event",
"timestamp",
"started",
"modelName",
"modelIdentifier",
"macOSBuild",
"macOSVersion",
"serialNumber",
"setupManagerVersion",
];
for (const field of required) {
if (typeof payload[field] !== "string" || payload[field].trim() === "") {
throw new Error(`Invalid Setup Manager payload: missing ${field}`);
}
}
if (
payload.event === "com.jamf.setupmanager.started" &&
payload.name !== "Started"
) {
throw new Error('Invalid Setup Manager payload: started event must use name "Started"');
}
if (
payload.event === "com.jamf.setupmanager.finished" &&
payload.name !== "Finished"
) {
throw new Error('Invalid Setup Manager payload: finished event must use name "Finished"');
}
if (payload.event === "com.jamf.setupmanager.finished") {
if (typeof payload.finished !== "string" || payload.finished.trim() === "") {
throw new Error("Invalid Setup Manager payload: finished events require finished");
}
if (typeof payload.duration !== "number" || payload.duration < 0) {
throw new Error("Invalid Setup Manager payload: finished events require numeric duration");
}
}
const failedActions = Array.isArray(payload.enrollmentActions)
? payload.enrollmentActions.filter((action) => action?.status === "failed")
: [];
const failedLabels = failedActions
.map((action) => action.label)
.filter(Boolean);
const isFinished = payload.event === "com.jamf.setupmanager.finished";
const shouldAlert = isFinished && failedActions.length > 0;
const eventId = [
payload.event,
payload.serialNumber,
payload.timestamp,
].join(":");
const summary = [
`Device: ${payload.computerName || payload.serialNumber}`,
`Serial: ${payload.serialNumber}`,
`Model: ${payload.modelName}`,
`macOS: ${payload.macOSVersion} (${payload.macOSBuild})`,
`Failed actions: ${failedLabels.join(", ") || "None"}`,
].join("\n");
return [
{
json: {
event_id: eventId,
received_at: new Date().toISOString(),
event: payload.event,
name: payload.name,
serial_number: payload.serialNumber,
model_name: payload.modelName,
model_identifier: payload.modelIdentifier,
macos_version: payload.macOSVersion,
macos_build: payload.macOSBuild,
setup_manager_version: payload.setupManagerVersion,
started_at: payload.started,
finished_at: payload.finished ?? "",
duration_seconds: payload.duration ?? null,
computer_name: payload.computerName ?? "",
failed_action_count: failedActions.length,
failed_action_labels: failedLabels.join(", "),
payload_json: JSON.stringify(payload),
should_alert: shouldAlert,
slack_payload: {
text: shouldAlert
? `Setup Manager enrollment failed actions\n${summary}`
: `Setup Manager event received: ${payload.name} ${payload.serialNumber}`,
},
teams_payload: {
type: "message",
attachments: [
{
contentType: "application/vnd.microsoft.card.adaptive",
content: {
$schema: "http://adaptivecards.io/schemas/adaptive-card.json",
type: "AdaptiveCard",
version: "1.4",
body: [
{
type: "TextBlock",
text: "Setup Manager failed actions",
weight: "Bolder",
size: "Medium",
},
{
type: "TextBlock",
text: summary,
wrap: true,
},
],
},
},
],
},
},
},
];Node order:
-
Webhook
- HTTP Method:
POST - Path:
setup-manager-hud-slack - Authentication: Header Auth
- Header name:
Authorization - Header value:
your-n8n-webhook-token-here - Respond: immediately with
200
- HTTP Method:
-
Code
- Paste the shared normalization code above.
-
Data Table
- Resource: Row
- Operation: Insert or Upsert
- Table:
setup_manager_events - Map each Data Table column to the matching field from the Code node output.
- If using Upsert, use
event_idas the unique key.
-
Optional HTTP Request: Forward to Setup Manager HUD
- Use this only when n8n is acting as the forwarding layer.
- Method:
POST - URL: your Setup Manager HUD
/webhookURL - Header:
Authorization: your-setupmanagerhud-webhook-token - Send body as JSON:
={{JSON.parse($json.payload_json)}}-
If
- Continue only when
should_alertistrue.
- Continue only when
-
HTTP Request
- Method:
POST - URL: your Slack incoming webhook URL
- Send body as JSON:
- Method:
{
"text": "={{$json.slack_payload.text}}"
}Note
Slack incoming webhook URLs are secrets. Store them in n8n credentials or variables where possible, and do not paste real URLs into shared workflow exports.
Node order:
-
Webhook
- HTTP Method:
POST - Path:
setup-manager-hud-teams - Authentication: Header Auth
- Header name:
Authorization - Header value:
your-n8n-webhook-token-here - Respond: immediately with
200
- HTTP Method:
-
Code
- Paste the shared normalization code above.
-
Data Table
- Resource: Row
- Operation: Insert or Upsert
- Table:
setup_manager_events - Map each Data Table column to the matching field from the Code node output.
- If using Upsert, use
event_idas the unique key.
-
Optional HTTP Request: Forward to Setup Manager HUD
- Use this only when n8n is acting as the forwarding layer.
- Method:
POST - URL: your Setup Manager HUD
/webhookURL - Header:
Authorization: your-setupmanagerhud-webhook-token - Send body as JSON:
={{JSON.parse($json.payload_json)}}-
If
- Continue only when
should_alertistrue.
- Continue only when
-
HTTP Request
- Method:
POST - URL: your Microsoft Teams incoming webhook or Teams workflow webhook URL
- Send body as JSON:
- Method:
={{$json.teams_payload}}Microsoft's current Teams guidance uses incoming webhooks through Teams Workflows and Adaptive Card JSON payloads. See Microsoft's Teams incoming webhook guidance.
Use the started and finished curl examples in Security#verifying-token-setup, but replace the URL with your n8n webhook URL and the token with your n8n webhook token.
The started test should store a row but not notify Slack or Teams.
The finished test should notify only when at least one enrollmentActions item has:
{
"status": "failed"
}Example failed action:
{
"label": "Install Apps",
"status": "failed"
}- Keep n8n alerting separate from Setup Manager HUD's
WEBHOOK_TOKEN. - Treat Slack and Teams webhook URLs as secrets.
- Store every webhook, but alert only on finished events with failed actions.
- Keep Setup Manager HUD as the dashboard source of truth; use n8n for copies, notifications, and downstream automation.
- If n8n is down, Setup Manager HUD should still receive its own webhook directly.