class Attio::Webhook
Represents a webhook configuration in Attio
def self.resource_path
-
(String)
- The API path
def self.resource_path "webhooks" end
def active?
def active? active == true end
def create(**kwargs)
def create(**kwargs) opts = {} opts[:api_key] = kwargs.delete(:api_key) if kwargs.key?(:api_key) prepared_params = prepare_params_for_create(kwargs) response = execute_request(:POST, resource_path, prepared_params, opts) new(response["data"] || response, opts) end
def delete(id, **opts)
def delete(id, **opts) webhook_id = Util::IdExtractor.extract_for_resource(id, :webhook) execute_request(:DELETE, "#{resource_path}/#{webhook_id}", {}, opts) true end
def deliveries(params = {}, **opts)
def deliveries(params = {}, **opts) raise InvalidRequestError, "Cannot get deliveries for a webhook without an ID" unless persisted? response = self.class.send(:execute_request, :GET, "#{resource_path}/deliveries", params, opts) response[:data] || [] end
def destroy(**opts)
def destroy(**opts) raise InvalidRequestError, "Cannot destroy a webhook without an ID" unless persisted? webhook_id = Util::IdExtractor.extract_for_resource(id, :webhook) self.class.delete(webhook_id, **opts) freeze true end
def initialize(attributes = {}, opts = {})
def initialize(attributes = {}, opts = {}) super normalized_attrs = normalize_attributes(attributes) @secret = normalized_attrs[:secret] @last_event_at = parse_timestamp(normalized_attrs[:last_event_at]) @created_by_actor = normalized_attrs[:created_by_actor] # Map status to active for convenience if status == "active" instance_variable_set(:@active, true) elsif status == "paused" instance_variable_set(:@active, false) end end
def pause(**opts)
def pause(**opts) self.active = false save(**opts) end
def paused?
def paused? !active? end
def prepare_params_for_create(params)
def prepare_params_for_create(params) # Handle both url and target_url parameters for convenience target_url = params[:target_url] || params["target_url"] || params[:url] || params["url"] validate_target_url!(target_url) subscriptions = params[:subscriptions] || params["subscriptions"] validate_subscriptions!(subscriptions) { data: { target_url: target_url, subscriptions: Array(subscriptions).map do |sub| # Ensure each subscription has a filter sub = sub.is_a?(Hash) ? sub : {"event_type" => sub} sub["filter"] ||= {"$and" => []} # Default empty filter sub end } } end
def prepare_params_for_update(params)
def prepare_params_for_update(params) { data: params } end
def resource_path
def resource_path raise InvalidRequestError, "Cannot generate path without an ID" unless persisted? webhook_id = Util::IdExtractor.extract_for_resource(id, :webhook) "#{self.class.resource_path}/#{webhook_id}" end
def resume(**opts)
def resume(**opts) self.active = true save(**opts) end
def retrieve(id, **opts)
def retrieve(id, **opts) webhook_id = Util::IdExtractor.extract_for_resource(id, :webhook) response = execute_request(:GET, "#{resource_path}/#{webhook_id}", {}, opts) new(response["data"] || response, opts) end
def save(**)
def save(**) raise InvalidRequestError, "Cannot save a webhook without an ID" unless persisted? return self unless changed? webhook_id = Util::IdExtractor.extract_for_resource(id, :webhook) self.class.update(webhook_id, changed_attributes, **) end
def test(**opts)
def test(**opts) raise InvalidRequestError, "Cannot test a webhook without an ID" unless persisted? self.class.send(:execute_request, :POST, "#{resource_path}/test", {}, opts) true end
def to_h
-
(Hash)
- Webhook data as a hash
def to_h super.merge( target_url: target_url, subscriptions: subscriptions, status: status, secret: secret, last_event_at: last_event_at&.iso8601, created_by_actor: created_by_actor ).compact end
def validate_subscriptions!(subscriptions)
def validate_subscriptions!(subscriptions) raise ArgumentError, "subscriptions are required" if subscriptions.nil? || subscriptions.empty? raise ArgumentError, "subscriptions must be an array" unless subscriptions.is_a?(Array) subscriptions.each do |sub| event_type = if sub.is_a?(Hash) sub[:event_type] || sub["event_type"] else sub # sub is a string representing the event type end raise ArgumentError, "Each subscription must have an event_type" unless event_type end end
def validate_target_url!(url)
def validate_target_url!(url) raise BadRequestError, "target_url or url is required" if url.nil? || url.empty? uri = URI.parse(url) unless uri.scheme == "https" raise BadRequestError, "Webhook target_url must use HTTPS" end rescue URI::InvalidURIError raise BadRequestError, "Invalid webhook target_url" end