Hey everyone — we've pushed API v2.1 to production this morning. If you're building integrations or just tired of polling for changes, this one's for you.

What's New

At-least-once delivery guarantees

Yeah, this one tripped me up too when I first looked at it. Previously our webhooks were "best effort," which... worked most of the time, but you probably noticed occasional gaps during high-traffic periods. v2.1 adds delivery receipts and automatic retries with exponential backoff. If your endpoint returns a 2xx, we mark it delivered. If not, we retry up to 5 times over ~15 minutes before giving up and surfacing a failure in the dashboard.

New webhook event types

workorder.status_changed
inventory.stock_adjusted
customer.updated
invoice.finalized
technician.availability_changed

These were the most requested events from folks building custom dashboards and ERP syncs. The payload structure is documented here — I kept it flat intentionally so you don't have to drill through nested objects to get at the data you actually need.

Webhook signing (finally)

You can now verify webhook authenticity using HMAC-SHA256 signatures. Pass ?include_signature=true when creating your webhook subscription and we'll include an X-FieldPulse-Signature header on every POST. The secret is per-subscription, not global, so rotating one integration doesn't break others.

Raw payload toggle

By default we wrap payloads in a standard envelope with metadata. Some of you (looking at you, middleware parsers) wanted the raw entity directly. Add ?format=raw to your webhook URL and you get just the work order / customer / whatever object, no wrapper.

API Changes

Nothing breaking in v2.1, but three additions worth noting:

  • GET /v2.1/workorders?include_checklist_responses=true — if you've ever made two separate calls to get a work order and then its checklist data, this one's for you
  • PATCH /v2.1/inventory/{id} — partial updates instead of full PUT replacements
  • Rate limit headers now include X-RateLimit-Reset with an ISO 8601 timestamp instead of just seconds-remaining

Migration from v2.0

v2.0 stays available — no sunset date yet. When you're ready, change your base URL from /api/v2.0/ to /api/v2.1/. If you're using the official Node SDK, bump to @fieldpulse/sdk@^2.1.0 and the version header gets handled automatically.

One edge case we hit during beta: if you're filtering webhooks by technician_id, make sure you're using the new UUID format we rolled out in March. The old integer IDs still work in v2.0 but v2.1 is stricter about validation and will 400 on numeric technician IDs.

Docs are updated at developers.fieldpulse.com. If something's unclear or the examples don't run, ping me here or open an issue — I triage those directly.

  • Confirmed on the secret — it's write-only after creation, same pattern as API keys. I'll flag the UX team about a copy-to-clipboard step before the dismiss.

    And yeah, API Gateway's request templates are picky about body schemas. If you're using raw mode, you'll probably need to disable request validation or set up a catch-all model. Here's what worked for me in the beta:

    "requestBody": {
      "content": {
        "application/json": {
          "schema": {"type": "object"}
        }
      }
    }
  • Heads up: the HMAC secret only shows once at creation time, yeah? Accidentally closed the dialog and had to rotate. Might be worth noting more prominently in the UI.

    Also worth noting for anyone using AWS API Gateway — the raw payload toggle breaks their default request validation since the body shape changes. YMMV.

  • Good catch — it's exponential with full jitter. Base 1s, doubles each retry, then random 0–100% multiplier. So retry intervals are roughly 1s, 2s, 4s, 8s, 16s but fuzzed so you don't get thundering herds.

    If you're still hitting 429s, your endpoint is probably faster than our max retry window. We don't queue beyond the 5 attempts — you'd need to poll the events API as fallback for anything that slips through.

  • Retry logic include jitter or fixed backoff? Seeing 429s on our endpoint during spikes, wondering if we need to add our own throttling.