Class: Webhooks::V1::FreightquoteController

Inherits:
BaseController
  • Object
show all
Includes:
ActionController::HttpAuthentication::Basic::ControllerMethods
Defined in:
app/controllers/webhooks/v1/freightquote_controller.rb

Overview

Webhook endpoint for CH Robinson Navisphere Events callbacks
(Freightquote LTL bookings).

Authentication:
CHR offers Basic Auth, OAuth 1.0/2.0, API key, or No Auth (per the
Navisphere swagger). We use HTTP Basic Auth embedded in the webhook
URL — same pattern as Webhooks::V1::ShipengineController. Credentials
come from Heatwave::Configuration.fetch(:freightquote, :webhook_*);
if they're blank the endpoint runs open (test/dev convenience), matching
ShipEngine's fallback.

Payload shape (one event per request — eventResponse schema):
{
"customer": "C8317882",
"eventTime": "2026-05-20T17:02:34.847Z",
"customerReferenceNumber": "787078",
"billToReferenceNumber": "787078",
"event": { "eventType": "LOAD CANCELLED", "loadNumber": 553933067, ... },
"time": "2026-05-20T17:02:36.798Z"
}

Instance Method Summary collapse

Instance Method Details

#createObject

POST /webhooks/v1/freightquote



35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
# File 'app/controllers/webhooks/v1/freightquote_controller.rb', line 35

def create
  payload = json_payload

  if payload.blank? || payload['event'].blank?
    Rails.logger.warn '[Freightquote Webhook] Empty or malformed payload received'
    return head :bad_request
  end

  attrs = FreightEvent.parse_payload(payload)

  if attrs[:event_type].blank? || attrs[:event_time].blank?
    Rails.logger.warn '[Freightquote Webhook] Missing required eventType/eventTime'
    return head :bad_request
  end

  delivery = resolve_delivery(attrs[:customer_reference_number])

  external_id = FreightEvent.idempotency_key_for(
    event_type: attrs[:event_type],
    event_time: attrs[:event_time],
    load_number: attrs[:load_number],
    order_number: attrs[:order_number]
  )

  webhook_log = WebhookLog.ingest!(
    provider: 'freightquote',
    category: category_for(attrs[:event_type]),
    resource_type: 'Delivery',
    resource_id: delivery&.id,
    external_id: external_id,
    data: payload,
    notes: "FQ #{attrs[:event_type]} delivery=#{delivery&.id || '?'} load=#{attrs[:load_number] || '?'} order=#{attrs[:order_number] || '?'}"
  )

  WebhookProcessorWorker.perform_async(webhook_log.id)

  head :ok
end