Webhooks · Pro plan

Webhooks Reference

Subscribe to RunTight events and receive real-time HTTP POST notifications. Ideal for connecting to Zapier, Make, n8n, or your own integration services.

Setup

Go to Settings → Webhooks in your RunTight dashboard (admin role, Pro plan required). Click Add Webhook, enter a name and URL, optionally set a secret for HMAC verification, and check the events you want to receive.

Events

wo.created

A new work order is created (via the app, API, or cron PM generation).

wo.completed

A work order's status transitions to completed.

wo.overdue

An open or in-progress work order crosses its due date. Fires once per WO.

pm.due

A PM template auto-generates a new work order via the daily cron.

asset.created

New equipment is added to your tenant.

Payload format

Every webhook delivers a JSON body with four top-level fields.

{
  "event": "wo.completed",
  "tenant_id": "tenant-uuid",
  "timestamp": "2026-04-11T18:45:12.123Z",
  "data": {
    "work_order_id": "wo-uuid",
    "title": "Weekly Hydraulic Press Inspection",
    "priority": "high",
    "due_date": "2026-04-11",
    "completed_at": "2026-04-11T18:45:10.567Z",
    "time_spent_minutes": 35,
    "asset_id": "asset-uuid"
  }
}

The data field varies by event type:

  • wo.created: work_order_id, title, priority, status, wo_type, due_date, asset_id
  • wo.completed: work_order_id, title, priority, due_date, completed_at, time_spent_minutes, asset_id
  • wo.overdue: work_order_id, title, priority, due_date, asset_id
  • pm.due: work_order_id, template_id, title, priority, due_date, asset_id
  • asset.created: asset_id, name, category, criticality

Request headers

Content-Type: application/json
User-Agent: RunTight-Webhooks/1.0
X-Webhook-Event: wo.completed
X-Webhook-Signature: sha256=HEX_HMAC      (only if secret configured)

Signature verification

If you configure a secret on a webhook, every request includes an X-Webhook-Signature header containing an HMAC-SHA256 hex digest of the raw request body.

Node.js example

import crypto from "crypto";

function verifySignature(body, signatureHeader, secret) {
  const expected = "sha256=" + crypto
    .createHmac("sha256", secret)
    .update(body)
    .digest("hex");
  return crypto.timingSafeEqual(
    Buffer.from(expected),
    Buffer.from(signatureHeader)
  );
}

// In your webhook handler:
const rawBody = await request.text();
const signature = request.headers.get("x-webhook-signature");
if (!verifySignature(rawBody, signature, process.env.WEBHOOK_SECRET)) {
  return new Response("Invalid signature", { status: 401 });
}
const payload = JSON.parse(rawBody);

Delivery semantics

  • Timing: Events are delivered by a daily cron job scan, not real-time. Latency is typically under 24 hours. For real-time, poll the REST API.
  • Idempotency: Each event fires at most once per work order using internal fired_at timestamps. If your endpoint is flaky, you may miss the event entirely — log every delivery on your side.
  • Timeout: RunTight waits up to 10 seconds for your endpoint to respond. Return a 2xx quickly and process asynchronously if you need more time.
  • History: Every delivery attempt is logged and visible under Settings → Webhooks with status code and response body snippet. Use this to debug.
  • Pause: You can pause a webhook without deleting it. No delivery attempts are made while paused.

Common integrations

  • Zapier — create a “Catch Hook” trigger, paste the Webhook URL into RunTight. Chain into Slack, Google Sheets, Trello, ClickUp, etc.
  • Make (formerly Integromat) — add a “Custom webhook” module, use it as a trigger.
  • n8n — add a Webhook node, select POST method. Self-host for zero ongoing cost.
  • Your own code — any HTTPS endpoint that accepts POST with JSON body will work.

See also