Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions lib/fintoc/v1/client/client.rb
Original file line number Diff line number Diff line change
@@ -1,12 +1,17 @@
require 'fintoc/base_client'
require 'fintoc/v1/managers/links_manager'
require 'fintoc/v1/managers/webhook_endpoints_manager'

module Fintoc
module V1
class Client < BaseClient
def links
@links ||= Managers::LinksManager.new(self)
end

def webhook_endpoints
@webhook_endpoints ||= Managers::WebhookEndpointsManager.new(self)
end
end
end
end
77 changes: 77 additions & 0 deletions lib/fintoc/v1/managers/webhook_endpoints_manager.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
require 'fintoc/v1/resources/webhook_endpoint'

module Fintoc
module V1
module Managers
class WebhookEndpointsManager
def initialize(client)
@client = client
end

def create(url:, enabled_events:, idempotency_key: nil, **params)
data = _create_webhook_endpoint(
url:, enabled_events:, idempotency_key:, **params
)
build_webhook_endpoint(data)
end

def get(webhook_endpoint_id)
data = _get_webhook_endpoint(webhook_endpoint_id)
build_webhook_endpoint(data)
end

def list(**params)
_list_webhook_endpoints(**params).map { |data| build_webhook_endpoint(data) }
end

def update(webhook_endpoint_id, idempotency_key: nil, **params)
data = _update_webhook_endpoint(webhook_endpoint_id, idempotency_key:, **params)
build_webhook_endpoint(data)
end

def delete(webhook_endpoint_id)
_delete_webhook_endpoint(webhook_endpoint_id)
end

def test(webhook_endpoint_id, type:)
data = _test_webhook_endpoint(webhook_endpoint_id, type:)
build_webhook_endpoint(data)
end

private

def _create_webhook_endpoint(url:, enabled_events:, idempotency_key: nil, **params)
request_params = { url:, enabled_events: }
request_params.merge!(params)

@client.post(version: :v1, idempotency_key:).call('webhook_endpoints', **request_params)
end

def _get_webhook_endpoint(webhook_endpoint_id)
@client.get(version: :v1).call("webhook_endpoints/#{webhook_endpoint_id}")
end

def _list_webhook_endpoints(**params)
@client.get(version: :v1).call('webhook_endpoints', **params)
end

def _update_webhook_endpoint(webhook_endpoint_id, idempotency_key: nil, **params)
@client.patch(version: :v1, idempotency_key:)
.call("webhook_endpoints/#{webhook_endpoint_id}", **params)
end

def _delete_webhook_endpoint(webhook_endpoint_id)
@client.delete(version: :v1).call("webhook_endpoints/#{webhook_endpoint_id}")
end

def _test_webhook_endpoint(webhook_endpoint_id, type:)
@client.post(version: :v1).call("webhook_endpoints/#{webhook_endpoint_id}/test", type:)
end

def build_webhook_endpoint(data)
Fintoc::V1::WebhookEndpoint.new(**data, client: @client)
end
end
end
end
end
38 changes: 38 additions & 0 deletions lib/fintoc/v1/resources/webhook_endpoint.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
module Fintoc
module V1
class WebhookEndpoint
attr_reader :id, :object, :url, :mode, :enabled_events, :secret, :disabled, :created_at

def initialize(
id:,
object:,
url:,
mode:,
enabled_events:,
secret:,
disabled:,
created_at:,
client: nil,
**
)
@id = id
@object = object
@url = url
@mode = mode
@enabled_events = enabled_events
@secret = secret
@disabled = disabled
@created_at = created_at
@client = client
end

def to_s
"🔔 #{@url} (#{@id})"
end

def disabled?
@disabled
end
end
end
end
2 changes: 2 additions & 0 deletions spec/lib/fintoc/v1/client_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -26,4 +26,6 @@
end

it_behaves_like 'a client with links manager'

it_behaves_like 'a client with webhook endpoints manager'
end
159 changes: 159 additions & 0 deletions spec/lib/fintoc/v1/managers/webhook_endpoints_manager_spec.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,159 @@
require 'fintoc/v1/managers/webhook_endpoints_manager'

RSpec.describe Fintoc::V1::Managers::WebhookEndpointsManager do
let(:client) { instance_double(Fintoc::BaseClient) }
let(:get_proc) { instance_double(Proc) }
let(:post_proc) { instance_double(Proc) }
let(:patch_proc) { instance_double(Proc) }
let(:manager) { described_class.new(client) }
let(:webhook_endpoint_id) { 'we_123' }
let(:url) { 'https://example.com/webhook' }
let(:enabled_events) { ['account.refresh_intent.succeeded'] }
let(:type) { 'account.refresh_intent.succeeded' }
let(:first_webhook_endpoint_data) do
{
id: webhook_endpoint_id,
object: 'webhook_endpoint',
url: url,
mode: 'test',
enabled_events: enabled_events,
secret: 'whsec_abc123',
disabled: false,
created_at: '2026-05-15T12:00:00.000Z'
}
end
let(:second_webhook_endpoint_data) do
{
id: 'we_456',
object: 'webhook_endpoint',
url: 'https://example.com/other-webhook',
mode: 'test',
enabled_events: enabled_events,
secret: 'whsec_def456',
disabled: false,
created_at: '2026-05-15T12:01:00.000Z'
}
end
let(:updated_webhook_endpoint_data) do
first_webhook_endpoint_data.merge(url: 'https://example.com/updated')
end

before do
allow(client).to receive(:get).with(version: :v1).and_return(get_proc)
allow(client).to receive(:post).with(version: :v1, idempotency_key: nil).and_return(post_proc)
allow(client).to receive(:post).with(version: :v1).and_return(post_proc)
allow(client).to receive(:patch).with(version: :v1, idempotency_key: nil).and_return(patch_proc)

allow(get_proc)
.to receive(:call)
.with("webhook_endpoints/#{webhook_endpoint_id}")
.and_return(first_webhook_endpoint_data)
allow(get_proc)
.to receive(:call)
.with('webhook_endpoints')
.and_return([first_webhook_endpoint_data, second_webhook_endpoint_data])
allow(post_proc)
.to receive(:call)
.with('webhook_endpoints', url:, enabled_events:)
.and_return(first_webhook_endpoint_data)
allow(post_proc)
.to receive(:call)
.with("webhook_endpoints/#{webhook_endpoint_id}/test", type:)
.and_return(first_webhook_endpoint_data)
allow(patch_proc)
.to receive(:call)
.with("webhook_endpoints/#{webhook_endpoint_id}", url: 'https://example.com/updated')
.and_return(updated_webhook_endpoint_data)

allow(Fintoc::V1::WebhookEndpoint).to receive(:new)
end

describe '#create' do
it 'calls build_webhook_endpoint with the response' do
manager.create(url:, enabled_events:)
expect(Fintoc::V1::WebhookEndpoint)
.to have_received(:new).with(**first_webhook_endpoint_data, client:)
end

context 'when idempotency_key is provided' do
let(:idempotency_key) { '123e4567-e89b-12d3-a456-426614174000' }

before do
allow(client).to receive(:post).with(version: :v1, idempotency_key:).and_return(post_proc)
end

it 'passes idempotency_key to the POST method' do
manager.create(url:, enabled_events:, idempotency_key:)

expect(client).to have_received(:post).with(version: :v1, idempotency_key:)
expect(Fintoc::V1::WebhookEndpoint)
.to have_received(:new).with(**first_webhook_endpoint_data, client:)
end
end
end

describe '#get' do
it 'calls build_webhook_endpoint with the response' do
manager.get(webhook_endpoint_id)
expect(Fintoc::V1::WebhookEndpoint)
.to have_received(:new).with(**first_webhook_endpoint_data, client:)
end
end

describe '#list' do
it 'calls build_webhook_endpoint for each response' do
manager.list
expect(Fintoc::V1::WebhookEndpoint)
.to have_received(:new).with(**first_webhook_endpoint_data, client:)
expect(Fintoc::V1::WebhookEndpoint)
.to have_received(:new).with(**second_webhook_endpoint_data, client:)
end
end

describe '#update' do
it 'calls build_webhook_endpoint with the response' do
manager.update(webhook_endpoint_id, url: 'https://example.com/updated')
expect(Fintoc::V1::WebhookEndpoint)
.to have_received(:new).with(**updated_webhook_endpoint_data, client:)
end

context 'when idempotency_key is provided' do
let(:idempotency_key) { '123e4567-e89b-12d3-a456-426614174000' }

before do
allow(client).to receive(:patch).with(version: :v1, idempotency_key:).and_return(patch_proc)
end

it 'passes idempotency_key to the PATCH method' do
manager.update(webhook_endpoint_id, url: 'https://example.com/updated', idempotency_key:)

expect(client).to have_received(:patch).with(version: :v1, idempotency_key:)
end
end
end

describe '#delete' do
let(:delete_proc) { instance_double(Proc) }

before do
allow(client).to receive(:delete).with(version: :v1).and_return(delete_proc)
allow(delete_proc)
.to receive(:call)
.with("webhook_endpoints/#{webhook_endpoint_id}")
.and_return(true)
end

it 'calls delete on the client' do
expect(manager.delete(webhook_endpoint_id)).to be true
end
end

describe '#test' do
it 'calls build_webhook_endpoint with the response' do
manager.test(webhook_endpoint_id, type:)

expect(Fintoc::V1::WebhookEndpoint)
.to have_received(:new).with(**first_webhook_endpoint_data, client:)
end
end
end
62 changes: 62 additions & 0 deletions spec/lib/fintoc/v1/webhook_endpoint_spec.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
require 'fintoc/v1/resources/webhook_endpoint'

RSpec.describe Fintoc::V1::WebhookEndpoint do
subject(:webhook_endpoint) { described_class.new(**data) }

let(:api_key) { 'sk_test_SeCreT-aPi_KeY' }
let(:client) { Fintoc::V1::Client.new(api_key) }

let(:data) do
{
id: 'we_Kasf91034gj1AD',
object: 'webhook_endpoint',
url: 'https://example.com/webhook',
mode: 'test',
enabled_events: ['account.refresh_intent.succeeded'],
secret: 'whsec_abc123',
disabled: false,
created_at: '2026-05-15T12:00:00.000Z',
client: client
}
end

describe '#initialize' do
it 'assigns all attributes correctly' do
expect(webhook_endpoint).to have_attributes(
id: 'we_Kasf91034gj1AD',
object: 'webhook_endpoint',
url: 'https://example.com/webhook',
mode: 'test',
enabled_events: ['account.refresh_intent.succeeded'],
secret: 'whsec_abc123',
disabled: false,
created_at: '2026-05-15T12:00:00.000Z'
)
end
end

describe '#to_s' do
it 'returns a string representation' do
expected = '🔔 https://example.com/webhook (we_Kasf91034gj1AD)'
expect(webhook_endpoint.to_s).to eq(expected)
end
end

describe '#disabled?' do
context 'when disabled is true' do
let(:data) do
super().merge(disabled: true)
end

it 'returns true' do
expect(webhook_endpoint.disabled?).to be true
end
end

context 'when disabled is false' do
it 'returns false' do
expect(webhook_endpoint.disabled?).to be false
end
end
end
end
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
RSpec.shared_examples 'a client with webhook endpoints manager' do
it 'responds to webhook_endpoints-specific methods' do
expect(client).to respond_to(:webhook_endpoints)
expect(client.webhook_endpoints).to be_a(Fintoc::V1::Managers::WebhookEndpointsManager)
expect(client.webhook_endpoints)
.to respond_to(:create)
.and respond_to(:get)
.and respond_to(:list)
.and respond_to(:update)
.and respond_to(:delete)
.and respond_to(:test)
end
end
Loading