Skip to content

WebhookNotifier

Built-in outbound webhook driver. Each connector sends to one fixed URL; a flavor config key reshapes the payload for popular targets so scripts can call a uniform notify(title, body, level) regardless of where the message ends up.

For the broader picture see the Notifications guide.

Properties

PropertyTypeAccessDescription
urlstringRTarget URL (fixed at config time)
flavorstringRPayload flavor: generic | ntfy | discord | slack
sendCountintRTotal successful sends
failCountintRTotal failed sends
lastErrorstringRError message of the most recent failed send
lastSentAtstringRISO-8601 timestamp of the most recent successful send

Actions

ActionArgsDescription
notify{ title, body, level?, image?, click?, tags? }Send a structured notification, reshaped per flavor
post / sendpayload (string or object)POST a raw payload — string → text/plain, object → JSON

level is one of info (default), warn, error, success.

image is optional. Accepts a base64 string (with or without a data: prefix), or an absolute file path that exists on disk. The camera drivers' snapshot() output (base64 JPEG) works directly.

click is an optional URL — ntfy and Discord make the notification clickable.

tags is ntfy-specific: a comma-separated list of emoji shortcodes (e.g. "warning,robot").

Always use notify() — never post() — for ntfy

post() bypasses flavor reshaping and arrives in the ntfy app as raw JSON. If the body looks like JSON in your phone, you're calling post() (or your flavor is set to generic against an ntfy URL).

Streams

StreamDescription
deliveryPer-send outcome: { outcome, summary, status, body, timestamp }

Config Options

OptionTypeDefaultDescription
urlstringTarget URL (required)
methodstring"POST"HTTP method
flavorstring"generic"generic | ntfy | discord | slack
markdownboolfalsentfy only — adds Markdown: yes header so the body renders as markdown
headersobjectExtra request headers (pinned across every send)
timeoutMsint10000Request timeout in milliseconds

Flavors

generic

JSON body, drop-in for n8n, Zapier, Make, or your own backend:

json
{ "title": "...", "body": "...", "level": "info", "timestamp": "2026-04-30T..." }

ntfy

ntfy.sh is a free pub/sub notification service. Pick any unique topic, subscribe with the ntfy app, and POSTs land as push notifications on every subscribed device.

javascript
// workspace/connectors/webhook-ntfy.js
export default {
  driver: "WebhookNotifier",
  config: {
    flavor: "ntfy",
    url: "https://ntfy.sh/muxit-lab-alerts-CHANGEME",
  },
};

The driver sends the body as text/plain and maps level → ntfy Priority header:

levelPriority
infodefault
successlow
warnhigh
errorurgent

Pin extra headers via config (e.g. headers: { "Tags": "test_tube,robot" }).

Markdown

Set markdown: true in config to send the body as markdown. ntfy renders headings, links, lists, and code blocks. The flag is ignored when an image is attached (ntfy doesn't render markdown alongside attachments).

javascript
config: { flavor: "ntfy", url: "...", markdown: true },
javascript
wh.notify(
  "Build report",
  "## Status\n\n- ✅ Tests\n- ⚠️ Lint\n- ❌ Deploy\n\n[Details](http://muxit.local)",
  "warn"
);

Snapshots

Pass image to attach a snapshot to the push notification — ntfy renders it inline. The driver switches to PUT-binary mode under the hood (image bytes as the body, message text moves to the Message header).

javascript
const wh = connector("webhook-ntfy");
const cam = connector("webcam");

// snapshot() returns base64 JPEG — feed directly
wh.notify("Robot status", "Voor inspectie", "info", {
  image: cam.snapshot(),
});

// Or a file on disk
wh.notify("Bench", "End-of-day", "success", {
  image: "C:/muxit/workspace/runs/2026-04-30.jpg",
});

Tags & click URL

javascript
wh.notify("Camera drift", "Drift > 0.5 mm", "warn", {
  tags:  "warning,camera",       // emoji shortcodes — see ntfy.sh/docs/emojis/
  click: "http://muxit.local:8765",
});

discord

In Discord: Server Settings → Integrations → Webhooks → New Webhook. Copy the URL into config.

javascript
// workspace/connectors/webhook-discord.js
export default {
  driver: "WebhookNotifier",
  config: {
    flavor: "discord",
    url: "https://discord.com/api/webhooks/REPLACE/WITH-YOUR-WEBHOOK-URL",
  },
};

notify() builds a Discord embed with a color matching the level (info=blue, warn=orange, error=red, success=green). For richer messages (multiple fields, mentions) call .post(...) with a full Discord webhook body.

Pass image to attach a snapshot — Discord renders it inline in the embed. The driver builds a multipart/form-data request with payload_json + files[0] and references the file via attachment://<filename>:

javascript
connector("webhook-discord").notify(
  "Robot status",
  "Voor inspectie",
  "info",
  { image: connector("webcam").snapshot() }
);

slack

Slack Incoming Webhook URL goes in config.url. notify() builds a text + colored attachment. For block-kit messages, use .post(...) with a full Slack body.

Example

Minimal

javascript
export default {
  driver: "WebhookNotifier",
  config: {
    flavor: "generic",
    url: "https://example.com/muxit-webhook",
  },
};

Script usage

javascript
const wh = connector("webhook");

// Structured notification — flavor-aware
wh.notify("Run klaar", "Calibratie voltooid in 12m04s", "success");

// Low-level — full control over the payload
wh.post({
  username: "Muxit",
  embeds: [{
    title: "Run klaar",
    description: "Calibratie voltooid",
    color: 0x2ECC71,
    fields: [
      { name: "Duur", value: "12m04s", inline: true },
      { name: "Resultaat", value: "OK", inline: true },
    ],
  }],
});

Muxit — Hardware Orchestration Platform