CrackedRuby logo

CrackedRuby

Make Integration

Overview

Make.com (formerly Integromat) provides a visual automation platform where developers can create workflows that respond to webhook events. Ruby applications integrate with Make by sending HTTP POST requests to webhook URLs, triggering automation scenarios that can perform actions across hundreds of connected services.

The integration operates through Make's webhook system. Ruby applications send structured data to webhook endpoints, which Make processes according to predefined scenarios. These scenarios can route data to various services, transform information, send notifications, or trigger complex multi-step workflows.

Ruby interacts with Make primarily through the net/http standard library or specialized gems like integromat-ruby. The integromat-ruby gem simplifies webhook management by providing configuration helpers and request builders that handle URL construction, parameter encoding, and error responses.

require 'integromat'

# Configure webhook endpoints
Integromat.configure do |config|
  config.web_hooks = {
    user_signup: "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
    order_complete: "z9y8x7w6-v5u4-3210-zyxw-987654321fed"
  }
  config.base_uri = "https://hook.eu2.make.com"
end

Make webhooks accept JSON payloads and can process various data formats including query parameters, form data, and structured JSON objects. The webhook URLs contain unique identifiers that route requests to specific scenarios, ensuring data reaches the correct automation workflow.

Ruby applications typically trigger Make webhooks during model lifecycle events, API responses, or background job completions. The integration supports both synchronous and asynchronous webhook calls, depending on whether immediate response validation is required.

Basic Usage

Setting up Make integration requires obtaining webhook URLs from Make scenarios and configuring Ruby applications to send appropriate HTTP requests. The process involves creating webhook endpoints in Make, configuring Ruby HTTP clients, and implementing trigger mechanisms.

The integromat-ruby gem provides the most straightforward integration approach. After installation and configuration, Ruby code can trigger webhooks using simple method calls that abstract HTTP request complexity.

# Install the gem
# gem install integromat-ruby

require 'integromat'

# Basic configuration with multiple webhooks
Integromat.configure do |config|
  config.web_hooks = {
    new_user: "12345678-abcd-efgh-ijkl-123456789012",
    user_login: "87654321-zyxw-vutt-srqp-210987654321",
    purchase_made: "11223344-aabb-ccdd-eeff-112233445566"
  }
end

# Trigger a webhook with data
webhook = Integromat::Webhook.new(:new_user)
result = webhook.trigger({
  email: "user@example.com",
  name: "John Doe",
  signup_date: Time.now.iso8601,
  source: "web_form"
})

For Rails applications, webhook triggers typically integrate with model callbacks, controller actions, or background jobs. The callbacks ensure webhooks fire automatically when specific events occur, maintaining data synchronization between Ruby applications and Make workflows.

# Rails model integration
class User < ApplicationRecord
  after_create :notify_make_webhook
  after_update :check_for_important_changes

  private

  def notify_make_webhook
    Integromat::Webhook.new(:new_user).trigger({
      user_id: id,
      email: email,
      full_name: full_name,
      created_at: created_at.iso8601,
      subscription_plan: subscription_plan
    })
  rescue StandardError => e
    Rails.logger.error "Make webhook failed: #{e.message}"
  end

  def check_for_important_changes
    return unless saved_change_to_email? || saved_change_to_subscription_plan?
    
    Integromat::Webhook.new(:user_updated).trigger({
      user_id: id,
      previous_email: email_before_last_save,
      current_email: email,
      subscription_change: subscription_plan_before_last_save != subscription_plan
    })
  end
end

Direct HTTP integration without gems requires constructing POST requests manually using Ruby's net/http library. This approach provides complete control over request formatting but requires more implementation effort.

require 'net/http'
require 'uri'
require 'json'

class MakeWebhookClient
  BASE_URL = "https://hook.eu2.make.com"
  
  def self.trigger_webhook(hook_id, data)
    uri = URI("#{BASE_URL}/#{hook_id}")
    
    http = Net::HTTP.new(uri.host, uri.port)
    http.use_ssl = true
    http.read_timeout = 10
    http.open_timeout = 5
    
    request = Net::HTTP::Post.new(uri)
    request['Content-Type'] = 'application/json'
    request.body = data.to_json
    
    response = http.request(request)
    
    if response.code.to_i >= 200 && response.code.to_i < 300
      JSON.parse(response.body) if response.body && !response.body.empty?
    else
      raise "Webhook failed: #{response.code} #{response.message}"
    end
  end
end

# Usage example
MakeWebhookClient.trigger_webhook(
  "12345678-abcd-efgh-ijkl-123456789012",
  {
    event: "order_completed",
    order_id: 12345,
    total_amount: 99.99,
    customer_email: "customer@example.com",
    items: [
      { name: "Product A", quantity: 2, price: 29.99 },
      { name: "Product B", quantity: 1, price: 39.99 }
    ]
  }
)

Background job integration ensures webhook calls don't block application response times. Sidekiq, Resque, or Active Job can handle webhook delivery asynchronously, providing retry mechanisms and failure handling.

# Sidekiq background job for webhook delivery
class MakeWebhookJob < ApplicationJob
  queue_as :webhooks
  
  def perform(webhook_name, data)
    Integromat::Webhook.new(webhook_name.to_sym).trigger(data)
  rescue StandardError => e
    Rails.logger.error "Make webhook job failed: #{e.message}"
    raise # Allows Sidekiq to retry
  end
end

# Trigger from controller
class OrdersController < ApplicationController
  def create
    @order = Order.new(order_params)
    
    if @order.save
      MakeWebhookJob.perform_later('order_created', {
        order_id: @order.id,
        customer_id: @order.customer_id,
        total: @order.total,
        created_at: @order.created_at.iso8601
      })
      
      render json: { status: 'success', order_id: @order.id }
    else
      render json: { errors: @order.errors }, status: :unprocessable_entity
    end
  end
end

Error Handling & Debugging

Make webhook integration requires comprehensive error handling due to network dependencies, external service availability, and payload format requirements. Ruby applications must handle HTTP timeouts, connection failures, rate limiting, and invalid responses.

The integromat-ruby gem raises exceptions for various failure conditions. Applications should rescue these exceptions and implement appropriate retry logic or fallback mechanisms.

require 'integromat'

class RobustWebhookService
  MAX_RETRIES = 3
  RETRY_DELAY = 2 # seconds
  
  def self.trigger_with_retry(webhook_name, data)
    retries = 0
    
    begin
      webhook = Integromat::Webhook.new(webhook_name)
      response = webhook.trigger(data)
      
      Rails.logger.info "Make webhook successful: #{webhook_name}"
      response
      
    rescue Net::TimeoutError, Net::OpenTimeout => e
      retries += 1
      if retries <= MAX_RETRIES
        Rails.logger.warn "Make webhook timeout, retry #{retries}: #{e.message}"
        sleep(RETRY_DELAY * retries)
        retry
      else
        Rails.logger.error "Make webhook failed after #{MAX_RETRIES} timeouts"
        raise
      end
      
    rescue Net::HTTPError => e
      Rails.logger.error "Make webhook HTTP error: #{e.message}"
      # Don't retry for HTTP errors - they're usually permanent
      raise
      
    rescue StandardError => e
      Rails.logger.error "Make webhook unexpected error: #{e.class} - #{e.message}"
      raise
    end
  end
end

HTTP response codes from Make webhooks indicate different error conditions. Applications should inspect status codes and implement appropriate handling for each scenario.

class MakeWebhookHandler
  def self.handle_webhook_response(response)
    case response.code.to_i
    when 200..299
      # Success - process response data if present
      JSON.parse(response.body) if response.body && !response.body.empty?
      
    when 400
      # Bad Request - payload format error, don't retry
      raise MakeWebhookError, "Invalid payload format: #{response.body}"
      
    when 401
      # Unauthorized - webhook URL might be incorrect
      raise MakeWebhookError, "Webhook authentication failed"
      
    when 404
      # Not Found - webhook doesn't exist or was deleted
      raise MakeWebhookError, "Webhook endpoint not found"
      
    when 429
      # Rate Limited - implement backoff retry
      retry_after = response['Retry-After'] || '60'
      raise RateLimitError, "Rate limited, retry after #{retry_after} seconds"
      
    when 500..599
      # Server Error - temporary issue, retry with backoff
      raise TemporaryError, "Make server error: #{response.code}"
      
    else
      raise MakeWebhookError, "Unexpected response: #{response.code} #{response.message}"
    end
  end
end

# Custom exception classes
class MakeWebhookError < StandardError; end
class RateLimitError < MakeWebhookError; end
class TemporaryError < MakeWebhookError; end

Debugging webhook issues requires logging comprehensive request and response information. Applications should log webhook URLs, payload data, response codes, and execution timing.

class DebuggableWebhookClient
  def self.trigger_with_logging(webhook_name, data)
    start_time = Time.now
    webhook_url = build_webhook_url(webhook_name)
    
    Rails.logger.info "Triggering Make webhook", {
      webhook_name: webhook_name,
      url: webhook_url,
      payload_size: data.to_json.bytesize,
      started_at: start_time.iso8601
    }
    
    begin
      response = send_webhook_request(webhook_url, data)
      duration = Time.now - start_time
      
      Rails.logger.info "Make webhook completed", {
        webhook_name: webhook_name,
        status_code: response.code,
        duration_ms: (duration * 1000).round(2),
        response_size: response.body&.bytesize || 0
      }
      
      response
      
    rescue => e
      duration = Time.now - start_time
      
      Rails.logger.error "Make webhook failed", {
        webhook_name: webhook_name,
        error_class: e.class.name,
        error_message: e.message,
        duration_ms: (duration * 1000).round(2),
        backtrace: e.backtrace.first(5)
      }
      
      raise
    end
  end
  
  private
  
  def self.build_webhook_url(webhook_name)
    hook_id = Rails.application.config.make_webhooks[webhook_name]
    raise "Unknown webhook: #{webhook_name}" unless hook_id
    "https://hook.eu2.make.com/#{hook_id}"
  end
  
  def self.send_webhook_request(url, data)
    uri = URI(url)
    http = Net::HTTP.new(uri.host, uri.port)
    http.use_ssl = true
    http.read_timeout = 30
    
    request = Net::HTTP::Post.new(uri)
    request['Content-Type'] = 'application/json'
    request['User-Agent'] = "RubyApp/1.0"
    request.body = data.to_json
    
    http.request(request)
  end
end

Make scenarios can fail or produce unexpected results even when webhook requests succeed. Applications should validate Make responses and implement fallback mechanisms for critical workflows.

class ValidatedWebhookService
  def self.trigger_order_webhook(order)
    webhook_data = {
      order_id: order.id,
      customer_email: order.customer.email,
      items: order.items.map(&:to_webhook_hash),
      total: order.total.to_f,
      currency: order.currency
    }
    
    # Validate data before sending
    validate_order_data!(webhook_data)
    
    response = RobustWebhookService.trigger_with_retry(:order_created, webhook_data)
    
    # Validate Make's response
    if response && response['status'] == 'processed'
      order.update!(webhook_sent: true, webhook_response: response)
    else
      # Make didn't process correctly - trigger fallback
      Rails.logger.warn "Make webhook unclear response", { 
        order_id: order.id, 
        response: response 
      }
      trigger_fallback_notification(order)
    end
    
  rescue => e
    Rails.logger.error "Order webhook completely failed", {
      order_id: order.id,
      error: e.message
    }
    trigger_fallback_notification(order)
  end
  
  private
  
  def self.validate_order_data!(data)
    required_fields = [:order_id, :customer_email, :total]
    missing = required_fields.select { |field| data[field].nil? }
    
    if missing.any?
      raise ArgumentError, "Missing required webhook fields: #{missing.join(', ')}"
    end
    
    if data[:total] <= 0
      raise ArgumentError, "Invalid order total: #{data[:total]}"
    end
  end
  
  def self.trigger_fallback_notification(order)
    # Send email notification or queue manual processing
    OrderProcessingMailer.webhook_failed(order).deliver_now
  end
end

Testing Strategies

Testing Make webhook integration requires mocking HTTP requests, validating payload structure, and simulating various response scenarios. Ruby applications should test webhook triggering logic separately from HTTP communication concerns.

WebMock and VCR provide powerful tools for mocking webhook requests during test execution. WebMock intercepts HTTP calls, allowing tests to specify exact request expectations and response behavior.

# spec/support/make_webhook_helpers.rb
module MakeWebhookHelpers
  def stub_make_webhook(webhook_name, response_body: nil, status: 200)
    hook_id = Rails.application.config.make_webhooks[webhook_name]
    url = "https://hook.eu2.make.com/#{hook_id}"
    
    stub = stub_request(:post, url)
    stub = stub.with(headers: { 'Content-Type' => 'application/json' }) if status == 200
    
    if response_body
      stub.to_return(status: status, body: response_body.to_json, headers: { 'Content-Type' => 'application/json' })
    else
      stub.to_return(status: status)
    end
  end
  
  def expect_make_webhook(webhook_name, payload)
    hook_id = Rails.application.config.make_webhooks[webhook_name]
    url = "https://hook.eu2.make.com/#{hook_id}"
    
    expect(WebMock).to have_requested(:post, url)
                      .with(body: payload.to_json,
                            headers: { 'Content-Type' => 'application/json' })
                      .once
  end
end

RSpec.configure do |config|
  config.include MakeWebhookHelpers
end

Model callback testing ensures webhook triggers fire correctly during record lifecycle events. Tests should verify payload content, handle callback failures, and validate conditional triggering logic.

# spec/models/user_spec.rb
require 'rails_helper'

RSpec.describe User, type: :model do
  describe 'Make webhook integration' do
    before do
      stub_make_webhook(:new_user, response_body: { status: 'received' })
    end
    
    it 'triggers webhook after user creation' do
      user = create(:user, email: 'test@example.com', name: 'Test User')
      
      expected_payload = {
        user_id: user.id,
        email: 'test@example.com',
        full_name: 'Test User',
        created_at: user.created_at.iso8601,
        subscription_plan: user.subscription_plan
      }
      
      expect_make_webhook(:new_user, expected_payload)
    end
    
    it 'logs error when webhook fails' do
      stub_make_webhook(:new_user, status: 500)
      
      expect(Rails.logger).to receive(:error).with(/Make webhook failed/)
      
      create(:user)
    end
    
    it 'does not trigger webhook for system users' do
      create(:user, system_user: true)
      
      expect(WebMock).not_to have_requested(:post, /hook\.eu2\.make\.com/)
    end
  end
  
  describe 'webhook payload validation' do
    it 'includes all required user data' do
      user = build(:user, 
        email: 'user@test.com',
        name: 'John Doe',
        subscription_plan: 'premium'
      )
      
      stub_make_webhook(:new_user)
      user.save!
      
      expected_payload = hash_including({
        user_id: user.id,
        email: 'user@test.com',
        full_name: 'John Doe',
        subscription_plan: 'premium',
        created_at: match(/\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}/)
      })
      
      expect_make_webhook(:new_user, expected_payload)
    end
  end
end

Integration testing validates complete webhook workflows by testing controller actions, background jobs, and error handling mechanisms. These tests verify webhook behavior in realistic application scenarios.

# spec/requests/orders_spec.rb
require 'rails_helper'

RSpec.describe '/api/orders', type: :request do
  describe 'POST /api/orders' do
    let(:valid_params) do
      {
        customer_id: create(:customer).id,
        items: [
          { product_id: create(:product).id, quantity: 2 },
          { product_id: create(:product).id, quantity: 1 }
        ]
      }
    end
    
    before do
      stub_make_webhook(:order_created, response_body: { status: 'processed', id: 'make-12345' })
    end
    
    it 'creates order and triggers Make webhook' do
      post '/api/orders', params: valid_params, as: :json
      
      expect(response).to have_http_status(:created)
      
      order = Order.last
      expected_webhook_data = {
        order_id: order.id,
        customer_id: order.customer_id,
        total: order.total.to_f,
        created_at: order.created_at.iso8601
      }
      
      # Webhook should be triggered asynchronously
      expect(MakeWebhookJob).to have_been_enqueued.with('order_created', expected_webhook_data)
    end
    
    it 'handles webhook failure gracefully' do
      stub_make_webhook(:order_created, status: 500)
      
      expect {
        post '/api/orders', params: valid_params, as: :json
      }.not_to raise_error
      
      expect(response).to have_http_status(:created)
      expect(Order.count).to eq(1)
    end
  end
end

Error scenario testing ensures applications handle various webhook failure conditions appropriately. Tests should cover network timeouts, HTTP errors, rate limiting, and payload validation failures.

# spec/services/robust_webhook_service_spec.rb
require 'rails_helper'

RSpec.describe RobustWebhookService do
  describe '.trigger_with_retry' do
    let(:webhook_data) { { user_id: 123, email: 'test@example.com' } }
    
    context 'when webhook succeeds' do
      before do
        stub_make_webhook(:user_signup, response_body: { status: 'ok' })
      end
      
      it 'returns response data' do
        result = RobustWebhookService.trigger_with_retry(:user_signup, webhook_data)
        expect(result).to eq({ 'status' => 'ok' })
      end
    end
    
    context 'when webhook times out' do
      before do
        stub_request(:post, /hook\.eu2\.make\.com/)
          .to_timeout
          .then
          .to_return(status: 200, body: '{"status": "ok"}')
      end
      
      it 'retries after timeout and eventually succeeds' do
        expect(Rails.logger).to receive(:warn).with(/timeout, retry 1/)
        
        result = RobustWebhookService.trigger_with_retry(:user_signup, webhook_data)
        expect(result).to eq({ 'status' => 'ok' })
      end
    end
    
    context 'when webhook consistently fails' do
      before do
        stub_request(:post, /hook\.eu2\.make\.com/).to_timeout
      end
      
      it 'raises error after max retries' do
        expect(Rails.logger).to receive(:warn).exactly(3).times
        expect(Rails.logger).to receive(:error).with(/failed after 3 timeouts/)
        
        expect {
          RobustWebhookService.trigger_with_retry(:user_signup, webhook_data)
        }.to raise_error(Net::TimeoutError)
      end
    end
    
    context 'when webhook returns HTTP error' do
      before do
        stub_make_webhook(:user_signup, status: 400)
      end
      
      it 'does not retry HTTP errors' do
        expect(Rails.logger).to receive(:error).with(/HTTP error/)
        
        expect {
          RobustWebhookService.trigger_with_retry(:user_signup, webhook_data)
        }.to raise_error(Net::HTTPError)
      end
    end
  end
end

VCR cassettes can record real webhook interactions for replay during testing, ensuring tests validate against actual Make.com response formats and behavior.

# spec/integration/make_webhook_integration_spec.rb
require 'rails_helper'

RSpec.describe 'Make webhook integration', :vcr do
  it 'successfully sends webhook to real Make endpoint' do
    VCR.use_cassette('make_webhook_success') do
      webhook_data = {
        test_event: 'user_signup',
        user_id: 12345,
        email: 'integration@test.com',
        timestamp: Time.now.iso8601
      }
      
      result = Integromat::Webhook.new(:integration_test).trigger(webhook_data)
      
      # Validate actual Make response structure
      expect(result).to be_a(Hash)
      expect(result).to have_key('status')
    end
  end
end

# spec/vcr_setup.rb
VCR.configure do |config|
  config.cassette_library_dir = 'spec/vcr_cassettes'
  config.hook_into :webmock
  config.configure_rspec_metadata!
  
  # Filter sensitive webhook URLs
  config.filter_sensitive_data('<WEBHOOK_URL>') do |interaction|
    interaction.request.uri if interaction.request.uri.include?('hook.eu2.make.com')
  end
end

Production Patterns

Production Make webhook integration requires careful consideration of reliability, monitoring, performance, and maintenance concerns. Ruby applications must handle webhook failures gracefully while maintaining system performance and data consistency.

Queue-based webhook delivery provides reliability and performance benefits by decoupling webhook requests from user-facing operations. Background job processors can retry failed webhooks, implement exponential backoff, and handle rate limiting automatically.

# app/jobs/make_webhook_delivery_job.rb
class MakeWebhookDeliveryJob < ApplicationJob
  queue_as :webhooks
  
  retry_on Net::TimeoutError, wait: :exponentially_longer, attempts: 5
  retry_on RateLimitError, wait: 60.seconds, attempts: 10
  
  def perform(webhook_name, payload, metadata = {})
    start_time = Time.now
    
    begin
      response = deliver_webhook(webhook_name, payload)
      
      # Log successful delivery
      Rails.logger.info "Make webhook delivered", {
        webhook: webhook_name,
        execution_time: Time.now - start_time,
        payload_size: payload.to_json.bytesize,
        response_status: response&.dig('status'),
        metadata: metadata
      }
      
      # Store delivery confirmation if needed
      if metadata[:record_delivery]
        WebhookDelivery.create!(
          webhook_name: webhook_name,
          payload: payload,
          delivered_at: Time.now,
          response: response
        )
      end
      
    rescue StandardError => e
      Rails.logger.error "Make webhook delivery failed", {
        webhook: webhook_name,
        error_class: e.class.name,
        error_message: e.message,
        execution_time: Time.now - start_time,
        metadata: metadata
      }
      
      # Re-raise to trigger retry mechanism
      raise
    end
  end
  
  private
  
  def deliver_webhook(webhook_name, payload)
    webhook = Integromat::Webhook.new(webhook_name)
    webhook.trigger(payload)
  rescue RateLimitError => e
    # Extract retry delay from error if available
    retry_after = extract_retry_delay(e.message) || 60
    raise RateLimitError, "Rate limited, retry after #{retry_after} seconds"
  end
  
  def extract_retry_delay(error_message)
    match = error_message.match(/retry after (\d+)/)
    match ? match[1].to_i : nil
  end
end

Circuit breaker patterns protect applications from Make.com outages by temporarily disabling webhook delivery when repeated failures occur. This prevents cascading failures and reduces unnecessary load on both systems.

# app/services/make_webhook_circuit_breaker.rb
class MakeWebhookCircuitBreaker
  include Singleton
  
  FAILURE_THRESHOLD = 10
  TIMEOUT_DURATION = 300 # 5 minutes
  
  def initialize
    reset!
  end
  
  def call(webhook_name, payload)
    if circuit_open?
      Rails.logger.warn "Make webhook circuit breaker open, skipping delivery", {
        webhook: webhook_name,
        failures: @failure_count,
        next_attempt_at: @next_attempt_time
      }
      return false
    end
    
    begin
      result = deliver_webhook(webhook_name, payload)
      on_success
      result
    rescue => e
      on_failure(e)
      raise
    end
  end
  
  private
  
  def circuit_open?
    @failure_count >= FAILURE_THRESHOLD && Time.now < @next_attempt_time
  end
  
  def deliver_webhook(webhook_name, payload)
    Integromat::Webhook.new(webhook_name).trigger(payload)
  end
  
  def on_success
    reset!
  end
  
  def on_failure(error)
    @failure_count += 1
    
    if @failure_count >= FAILURE_THRESHOLD
      @next_attempt_time = Time.now + TIMEOUT_DURATION
      Rails.logger.error "Make webhook circuit breaker opened", {
        failures: @failure_count,
        last_error: error.message,
        timeout_until: @next_attempt_time
      }
    end
  end
  
  def reset!
    @failure_count = 0
    @next_attempt_time = nil
  end
end

# Usage in webhook delivery
class ReliableMakeWebhookService
  def self.deliver(webhook_name, payload)
    circuit_breaker = MakeWebhookCircuitBreaker.instance
    
    if circuit_breaker.call(webhook_name, payload)
      Rails.logger.info "Webhook delivered via circuit breaker", webhook: webhook_name
    else
      # Queue for later delivery when circuit closes
      MakeWebhookDeliveryJob.set(wait: 10.minutes).perform_later(webhook_name, payload, retry_after_circuit_break: true)
    end
  end
end

Webhook delivery monitoring provides visibility into integration health and performance. Applications should track delivery success rates, response times, and error patterns to identify issues before they impact users.

# app/models/webhook_metric.rb
class WebhookMetric < ApplicationRecord
  scope :recent, -> { where(created_at: 1.day.ago..) }
  scope :for_webhook, ->(name) { where(webhook_name: name) }
  scope :successful, -> { where(success: true) }
  scope :failed, -> { where(success: false) }
  
  def self.record_delivery(webhook_name, success, response_time, error = nil)
    create!(
      webhook_name: webhook_name,
      success: success,
      response_time_ms: response_time * 1000,
      error_message: error&.message,
      error_class: error&.class&.name
    )
  end
  
  def self.success_rate_for(webhook_name, period = 1.day)
    metrics = where(webhook_name: webhook_name, created_at: period.ago..)
    return 0.0 if metrics.count.zero?
    
    successful_count = metrics.successful.count
    (successful_count.to_f / metrics.count * 100).round(2)
  end
  
  def self.average_response_time_for(webhook_name, period = 1.day)
    metrics = where(webhook_name: webhook_name, created_at: period.ago...).successful
    return 0.0 if metrics.count.zero?
    
    metrics.average(:response_time_ms).to_f.round(2)
  end
end

# Instrumented webhook delivery service
class InstrumentedWebhookService
  def self.deliver_with_metrics(webhook_name, payload)
    start_time = Time.now
    
    begin
      result = Integromat::Webhook.new(webhook_name).trigger(payload)
      response_time = Time.now - start_time
      
      WebhookMetric.record_delivery(webhook_name, true, response_time)
      
      # Alert if response time is unusually high
      if response_time > 5.0
        Rails.logger.warn "Slow Make webhook response", {
          webhook: webhook_name,
          response_time: response_time,
          threshold: 5.0
        }
      end
      
      result
      
    rescue => e
      response_time = Time.now - start_time
      WebhookMetric.record_delivery(webhook_name, false, response_time, e)
      
      # Check if error rate is concerning
      recent_success_rate = WebhookMetric.success_rate_for(webhook_name, 1.hour)
      if recent_success_rate < 80.0
        alert_webhook_degradation(webhook_name, recent_success_rate)
      end
      
      raise
    end
  end
  
  private
  
  def self.alert_webhook_degradation(webhook_name, success_rate)
    Rails.logger.error "Make webhook success rate degraded", {
      webhook: webhook_name,
      success_rate: success_rate,
      threshold: 80.0
    }
    
    # Send alert to monitoring system
    # SlackNotifier.ping("Make webhook #{webhook_name} success rate: #{success_rate}%")
  end
end

Configuration management for production environments requires secure handling of webhook URLs, proper environment separation, and flexible configuration updates without application restarts.

# config/initializers/make_integration.rb
Rails.application.configure do
  config.make_webhooks = {
    user_created: ENV['MAKE_WEBHOOK_USER_CREATED'],
    user_updated: ENV['MAKE_WEBHOOK_USER_UPDATED'],
    order_completed: ENV['MAKE_WEBHOOK_ORDER_COMPLETED'],
    payment_failed: ENV['MAKE_WEBHOOK_PAYMENT_FAILED'],
    subscription_cancelled: ENV['MAKE_WEBHOOK_SUBSCRIPTION_CANCELLED']
  }
  
  # Validate required webhooks are configured
  missing_webhooks = config.make_webhooks.select { |_, url| url.blank? }
  if missing_webhooks.any?
    missing_names = missing_webhooks.keys.join(', ')
    Rails.logger.warn "Missing Make webhook configuration: #{missing_names}"
  end
  
  # Configure integromat-ruby gem
  if defined?(Integromat)
    Integromat.configure do |integromat_config|
      integromat_config.web_hooks = config.make_webhooks.transform_values { |url|
        url&.match(%r{/([a-f0-9\-]{36})/?$})&.[](1)
      }.compact
      
      # Use appropriate Make region
      integromat_config.base_uri = ENV.fetch('MAKE_BASE_URI', 'https://hook.eu2.make.com')
    end
  end
end

# Environment-specific webhook configuration
# config/environments/production.rb
Rails.application.configure do
  # Enable webhook delivery in production
  config.enable_make_webhooks = true
  
  # Production webhook timeout settings
  config.make_webhook_timeout = 30
  config.make_webhook_open_timeout = 10
end

# config/environments/staging.rb  
Rails.application.configure do
  # Use staging-specific webhook URLs
  config.enable_make_webhooks = true
  config.make_webhook_timeout = 60 # Longer timeout for debugging
end

# config/environments/development.rb
Rails.application.configure do
  # Disable webhooks in development unless explicitly enabled
  config.enable_make_webhooks = ENV['ENABLE_MAKE_WEBHOOKS'] == 'true'
end

# app/services/configurable_webhook_service.rb
class ConfigurableWebhookService
  def self.deliver(webhook_name, payload)
    return unless Rails.application.config.enable_make_webhooks
    
    webhook_url = Rails.application.config.make_webhooks[webhook_name]
    unless webhook_url.present?
      Rails.logger.warn "Make webhook not configured: #{webhook_name}"
      return
    end
    
    # Deliver webhook with environment-specific settings
    timeout = Rails.application.config.make_webhook_timeout || 30
    
    Integromat::Webhook.new(webhook_name).trigger(payload, timeout: timeout)
  end
end

Reference

Integromat-Ruby Gem Methods

Method Parameters Returns Description
Integromat.configure block nil Configure webhook URLs and base URI settings
Integromat::Webhook.new(name) name (Symbol/String) Webhook Create webhook instance for specified endpoint
#trigger(data, **options) data (Hash), options (Hash) Hash or nil Send data to Make webhook endpoint

Configuration Options

Setting Type Default Description
web_hooks Hash {} Map of webhook names to hook IDs
base_uri String "https://hook.eu2.make.com" Make webhook base URL
timeout Integer 30 HTTP request timeout in seconds
open_timeout Integer 10 Connection timeout in seconds

HTTP Response Codes

Code Meaning Action
200-299 Success Process response data
400 Bad Request Check payload format, don't retry
401 Unauthorized Verify webhook URL
404 Not Found Webhook doesn't exist
429 Rate Limited Implement backoff retry
500-599 Server Error Retry with exponential backoff

Webhook Data Formats

Format Content-Type Example
JSON application/json {"user_id": 123, "email": "user@example.com"}
Form Data application/x-www-form-urlencoded user_id=123&email=user@example.com
Query String N/A ?user_id=123&email=user@example.com

Environment Variables

Variable Purpose Example
MAKE_WEBHOOK_USER_CREATED User registration webhook URL https://hook.eu2.make.com/abc123...
MAKE_BASE_URI Regional Make endpoint https://hook.us1.make.com
ENABLE_MAKE_WEBHOOKS Enable/disable webhooks true or false

Error Classes

Class Inheritance Description
Net::TimeoutError StandardError HTTP request timeout
Net::OpenTimeout Net::TimeoutError Connection establishment timeout
Net::HTTPError StandardError HTTP protocol errors

Rails Integration Patterns

Pattern Implementation Use Case
Model Callbacks after_create :webhook_notify Automatic webhook triggers
Background Jobs MakeWebhookJob.perform_later Asynchronous delivery
Controller Actions Direct webhook calls Immediate event notification
Observer Pattern External webhook observers Decoupled webhook logic

Monitoring Metrics

Metric Calculation Purpose
Success Rate successful_deliveries / total_attempts * 100 Integration health
Average Response Time sum(response_times) / delivery_count Performance monitoring
Error Rate failed_deliveries / total_attempts * 100 Failure tracking
Circuit Breaker Status Boolean open/closed state Fault tolerance