Class: Webhooks::V1::ShipengineController

Inherits:
BaseController
  • Object
show all
Defined in:
app/controllers/webhooks/v1/shipengine_controller.rb

Overview

Controller for ShipEngine tracking webhooks

Authentication:
ShipEngine webhooks can be authenticated via:

  1. HTTP Basic Auth credentials embedded in the webhook URL
  2. User-Agent header verification (ShipEngine sends "ShipEngine/v1")

Note: ShipEngine does NOT send an API-Key header in webhooks.
The API key is only used for making requests TO ShipEngine, not for
receiving webhooks FROM ShipEngine.

Instance Method Summary collapse

Instance Method Details

#createObject

POST /webhooks/v1/shipengine



25
26
27
28
29
30
31
32
33
34
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
# File 'app/controllers/webhooks/v1/shipengine_controller.rb', line 25

def create
  raw_payload = request.raw_post
  payload = parse_payload(raw_payload)

  if payload.blank?
    Rails.logger.warn '[ShipEngine Webhook] Empty or invalid payload received'
    return head :bad_request
  end

  tracking_number = payload.dig('data', 'tracking_number')
  status_code = payload.dig('data', 'status_code')
  resource_type = payload['resource_type'] # e.g., "API_TRACK"

  Rails.logger.info "[ShipEngine Webhook] Received #{resource_type} for tracking: #{tracking_number}, status: #{status_code}"

  # Find shipment or RMA by tracking number to get resource_id
  resource = find_shipment_by_tracking(tracking_number)

  webhook_log = WebhookLog.ingest!(
    provider: 'shipengine',
    category: 'tracking_update',
    resource_type: resource&.class&.name || 'Shipment',
    resource_id: resource&.id,
    external_id: "#{tracking_number}_#{status_code}_#{payload.dig('data', 'events', 0, 'occurred_at')}",
    data: payload,
    notes: "ShipEngine tracking update: #{tracking_number} -> #{status_code}"
  )

  WebhookProcessorWorker.perform_async(webhook_log.id)

  head :ok
rescue JSON::ParserError => e
  Rails.logger.error "[ShipEngine Webhook] Failed to parse JSON payload: #{e.message}"
  head :bad_request
rescue StandardError => e
  Rails.logger.error "[ShipEngine Webhook] Error processing webhook: #{e.message}"
  head :internal_server_error
end