Back
    Automation

    Integrations — automate dispatch and billing

    Connect Pyles Ops to Zapier, n8n, Make or Pipedream to auto-assign drivers the moment a delivery lands, and to keep invoices, payments and driver payouts in sync with your accounting stack. Every example below is copy-paste ready.

    How the connection works

    Outbound: we call your automation

    Paste a platform webhook URL into your automation settings. Pyles OpsPOSTs a JSON event whenever a delivery, payout or invoice changes.

    Event: delivery.created
    {
      "event": "delivery.created",
      "delivery_id": "DL-10482",
      "client": "Northside Grocers",
      "pickup": { "lat": 33.7756, "lng": -84.3963, "address": "Midtown Hub, Atlanta GA" },
      "dropoff": { "lat": 33.9304, "lng": -84.3733, "address": "Sandy Springs, GA" },
      "courier_needs": ["refrigerated", "liftgate"],
      "value_usd": 214.5,
      "window": { "start": "2026-08-08T14:00:00Z", "end": "2026-08-08T17:00:00Z" }
    }

    Inbound: your automation calls us

    Send an authenticated POST with the X-Api-Key header to trigger auto-assignment or to acknowledge a billing sync.

    Response
    {
      "assigned_driver": { "id": "DRV-27", "name": "Driver 27", "match_score": 0.91 },
      "addons": [{ "code": "COLD_CHAIN", "revenue_usd": 35, "driver_payout_usd": 12.25 }],
      "projected_margin_usd": 88.4
    }

    Events are retried up to 3 times with exponential backoff. Treat every handler as idempotent and key it on delivery_id or invoice_id.

    Platform guides

    Fastest no-code path. Best when your team already lives in Zapier.

    Workflow 1 — Auto-assign a new delivery

    1. Trigger: Webhooks by Zapier → Catch Hook. Copy the hook URL into your Pyles Ops automation settings.
    2. Filter: only continue if courier_needs is not empty.
    3. Action: Code by Zapier with the snippet below (or a plain Webhooks POST).
    4. Action: Slack / SMS to notify the matched driver.
    Code by Zapier
    // Zapier "Code by Zapier" step (JavaScript) — auto-assign
    const res = await fetch("https://dashpilot-fleetflow.lovable.app/api/public/dispatch/auto-assign", {
      method: "POST",
      headers: {
        "Content-Type": "application/json",
        "X-Api-Key": inputData.plyesOpsApiKey,
      },
      body: JSON.stringify({
        delivery_id: inputData.deliveryId,
        courier_needs: (inputData.needs || "").split(","),
        value_usd: Number(inputData.value),
      }),
    });
    const data = await res.json();
    output = [{ driverId: data.assigned_driver?.id, score: data.assigned_driver?.match_score }];

    Workflow 2 — Billing sync

    1. Trigger: Catch Hook on invoice events.
    2. Paths: paid → create a payment in QuickBooks/Xero; overdue → send an AR reminder email.
    3. Action: append a row to a Google Sheet ledger for reconciliation.
    Posting an event to a Zap
    // Sending a Pyles Ops event into a Zap (Catch Hook trigger)
    await fetch(zapierWebhookUrl, {
      method: "POST",
      headers: { "Content-Type": "application/json" },
      mode: "no-cors",
      body: JSON.stringify({
        timestamp: new Date().toISOString(),
        triggered_from: window.location.origin,
        event: "invoice.status_changed",
        invoice_id: "INV-2026-0413",
      }),
    });

    Browser-side posts use no-cors, so the response is opaque — confirm delivery in the Zap's run history.

    Webhook setup

    Create a receiving URL on your platform, paste it into Pyles Ops, pick the events you want, then verify the signature on every request. The same endpoint can receive both auto-assign and billing events — branch on event.

    Step 1 — Create the receiving URL

    PlatformTrigger moduleURL shapeGotcha
    ZapierWebhooks by Zapier → Catch Raw Hookhttps://hooks.zapier.com/hooks/catch/123456/abcdef/Use Catch RAW Hook (not Catch Hook) so the unparsed body is available for signature verification.
    n8nWebhook node (POST, Response mode: Immediately)https://your-n8n.app/webhook/pyles-opsEnable Raw Body in node options; the test URL only listens while the canvas is open — use the Production URL.
    MakeWebhooks → Custom webhookhttps://hook.us1.make.com/abc123xyzClick Re-determine data structure and send one sample event so Make maps the nested data object.
    PipedreamHTTP / Webhook Requests (Return a static response)https://abc123.m.pipedream.netRead the raw body from steps.trigger.event.bodyRaw; store the signing secret as a secret prop.

    Step 2 — Register the endpoint in Pyles Ops

    1. Open More → Integrations → Webhook endpoints and choose Add endpoint.
    2. Paste the URL, then subscribe to delivery.created and assignment.completed for auto-assign, and invoice.status_changed plus payout.updated for billing sync.
    3. Copy the generated signing secret into your automation platform's secret store — it is shown once.
    4. Use Send test event so the platform can map the payload structure before you go live.

    Step 3 — Request format and headers

    Request line and headers
    POST /hooks/pyles-ops HTTP/1.1
    Content-Type: application/json
    User-Agent: PylesOps-Webhooks/1
    X-Pyles-Event: assignment.completed
    X-Pyles-Delivery-Id: whd_01J9Z3K7QF2M   # unique per attempt
    X-Pyles-Event-Id: evt_01J9Z3K7QF2M      # stable across retries — dedupe on this
    X-Pyles-Timestamp: 1786331051           # unix seconds
    X-Pyles-Signature: v1=9f2c...c41b       # hex HMAC-SHA256 of "{timestamp}.{rawBody}"

    Step 4 — Verify the signature

    HMAC-SHA256 verification
    // Verify X-Pyles-Signature before trusting a payload (Node.js / Pipedream / n8n Code node)
    import { createHmac, timingSafeEqual } from "node:crypto";
    
    export function verifyPylesWebhook(rawBody, headers, secret) {
      const timestamp = headers["x-pyles-timestamp"];
      const received = String(headers["x-pyles-signature"] || "").replace(/^v1=/, "");
    
      // Reject anything older than 5 minutes to block replays
      if (Math.abs(Date.now() / 1000 - Number(timestamp)) > 300) return false;
    
      const expected = createHmac("sha256", secret)
        .update(`${timestamp}.${rawBody}`)
        .digest("hex");
    
      const a = Buffer.from(received, "hex");
      const b = Buffer.from(expected, "hex");
      return a.length === b.length && timingSafeEqual(a, b);
    }

    In Zapier use a Code by Zapier step on a Catch Raw Hook; in Make add a Tools → Set variable with the sha256 HMAC function; in n8n and Pipedream paste the function above directly into a code node.

    Sample payload — auto-assign

    assignment.completed fires once a driver is matched, with the score breakdown, billable add-ons and projected margin your workflow needs to route, notify and log.

    POST body
    {
      "event": "assignment.completed",
      "event_id": "evt_01J9Z3K7QF2M",
      "occurred_at": "2026-08-08T14:04:11Z",
      "environment": "live",
      "data": {
        "delivery_id": "DL-10482",
        "client": { "id": "CL-118", "name": "Northside Grocers", "referred": true },
        "pickup": { "lat": 33.7756, "lng": -84.3963, "address": "Midtown Hub, Atlanta GA" },
        "dropoff": { "lat": 33.9304, "lng": -84.3733, "address": "Sandy Springs, GA" },
        "courier_needs": ["refrigerated", "liftgate"],
        "assignment": {
          "mode": "auto",
          "driver": { "id": "DRV-27", "name": "Driver 27", "phone": "+1404555••27" },
          "match_score": 0.91,
          "score_breakdown": {
            "capability_match": 0.40,
            "proximity": 0.27,
            "availability": 0.14,
            "on_time_history": 0.10
          },
          "eta_to_pickup_min": 12,
          "runner_up_driver_ids": ["DRV-14", "DRV-31"]
        },
        "addons": [
          { "code": "COLD_CHAIN", "label": "Refrigerated handling", "revenue_usd": 35.00, "driver_payout_usd": 12.25 },
          { "code": "LIFTGATE", "label": "Liftgate service", "revenue_usd": 20.00, "driver_payout_usd": 7.00 }
        ],
        "economics": {
          "base_revenue_usd": 214.50,
          "addon_revenue_usd": 55.00,
          "driver_payout_usd": 118.85,
          "projected_margin_usd": 88.40,
          "margin_pct": 32.8
        }
      }
    }

    Sample payload — billing sync

    invoice.status_changed carries before/after states, the line items behind the total and the queued driver payouts to release once your ledger confirms the payment.

    POST body
    {
      "event": "invoice.status_changed",
      "event_id": "evt_01J9ZB4T8HD3",
      "occurred_at": "2026-08-08T18:04:11Z",
      "environment": "live",
      "data": {
        "invoice_id": "INV-2026-0413",
        "client": { "id": "CL-118", "name": "Northside Grocers", "terms": "net_15" },
        "period": { "start": "2026-07-01", "end": "2026-07-31" },
        "before": { "status": "sent", "total_usd": 1840.00, "amount_paid_usd": 0 },
        "after": {
          "status": "paid",
          "total_usd": 1840.00,
          "amount_paid_usd": 1840.00,
          "paid_at": "2026-08-08T18:04:11Z",
          "payment_reference": "pay_9f31c2"
        },
        "line_items": [
          { "delivery_id": "DL-10482", "description": "Refrigerated run — Sandy Springs", "amount_usd": 269.50 },
          { "delivery_id": "DL-10488", "description": "Standard run — Decatur", "amount_usd": 142.00 }
        ],
        "driver_payouts": [
          { "driver_id": "DRV-27", "amount_usd": 612.50, "status": "queued", "release_on": "2026-08-09" },
          { "driver_id": "DRV-14", "amount_usd": 288.75, "status": "queued", "release_on": "2026-08-09" }
        ],
        "totals": { "revenue_usd": 1840.00, "driver_payout_usd": 901.25, "net_margin_usd": 938.75 }
      }
    }

    Step 5 — Handle retries and ordering

    Delivery schedule
    Attempt 1  immediate
    Attempt 2  +30s
    Attempt 3  +2m
    Attempt 4  +10m      (final)
    
    • Any 2xx = delivered. 410 = we disable the endpoint.
    • Timeout is 10s — acknowledge fast, process asynchronously.
    • X-Pyles-Event-Id is stable across retries; X-Pyles-Delivery-Id is not.
    • Out-of-order delivery is possible: compare occurred_at before overwriting state.

    Event reference

    EventFires whenTypical use
    delivery.createdA new delivery enters the dispatch feedAuto-assign the best-matched driver
    delivery.status_changedPickup, en route, delivered or exceptionCustomer ETA notifications
    assignment.completedA driver accepts or auto-assign resolvesUpdate your TMS or Slack channel
    payout.updatedDriver payout components recalculatePush to payroll
    invoice.status_changedInvoice sent, paid, overdue or voidBilling sync to accounting
    opportunity.status_changedReferral, upsell or training progressesCommission tracking

    Security checklist

    • Keep API keys in your automation platform's secret store — never in a step's visible body.
    • Verify the signature header on inbound events before acting on them.
    • Scope each automation to one job so a leaked key has a limited blast radius.
    • Rotate keys when a teammate with automation access leaves.
    See plansAutomation endpoints are available on Pro and Enterprise plans.