From fda5a77ab697c8e3eebe0bb57f236b3be3402645 Mon Sep 17 00:00:00 2001 From: tlarrain Date: Tue, 7 Jul 2026 08:29:42 -0400 Subject: [PATCH 1/2] feat(v2): add legal representative document upload Adds upload_legal_representative_document to the onboardings manager, PUTting a multipart file to the legal representative document slot path, and exposes the new legal_representatives array on the Onboarding resource. Create params move to the plural legal_representatives array the API now expects. --- lib/fintoc/v2/managers/onboardings_manager.rb | 19 +++++++++ lib/fintoc/v2/resources/onboarding.rb | 4 +- .../v2/managers/onboardings_manager_spec.rb | 39 ++++++++++++++++++- spec/lib/fintoc/v2/onboarding_spec.rb | 29 ++++++++++++++ 4 files changed, 89 insertions(+), 2 deletions(-) diff --git a/lib/fintoc/v2/managers/onboardings_manager.rb b/lib/fintoc/v2/managers/onboardings_manager.rb index d93f1d0..f27eeb1 100644 --- a/lib/fintoc/v2/managers/onboardings_manager.rb +++ b/lib/fintoc/v2/managers/onboardings_manager.rb @@ -40,6 +40,15 @@ def upload_shareholder_document(onboarding_id, shareholder_id, file:, idempotenc build_onboarding(data) end + def upload_legal_representative_document( + onboarding_id, legal_representative_id, slot_key, file:, idempotency_key: nil + ) + data = _upload_legal_representative_document( + onboarding_id, legal_representative_id, slot_key, file:, idempotency_key: + ) + build_onboarding(data) + end + private def base_path @@ -77,6 +86,16 @@ def _upload_shareholder_document(onboarding_id, shareholder_id, file:, idempoten ) end + def _upload_legal_representative_document( + onboarding_id, legal_representative_id, slot_key, file:, idempotency_key: nil + ) + @client.put(version: :v2, idempotency_key:).call( + "#{base_path}/#{onboarding_id}/legal_representatives" \ + "/#{legal_representative_id}/documents/#{slot_key}", + form: { file: } + ) + end + def build_onboarding(data) Fintoc::V2::Onboarding.new(**data, client: @client) end diff --git a/lib/fintoc/v2/resources/onboarding.rb b/lib/fintoc/v2/resources/onboarding.rb index 40cd483..4757460 100644 --- a/lib/fintoc/v2/resources/onboarding.rb +++ b/lib/fintoc/v2/resources/onboarding.rb @@ -2,7 +2,7 @@ module Fintoc module V2 class Onboarding attr_reader :object, :id, :entity_id, :status, :source, :submitted_at, :reviewed_at, - :submittable, :data, :shareholders, :documents + :submittable, :data, :legal_representatives, :shareholders, :documents def initialize( object:, @@ -14,6 +14,7 @@ def initialize( reviewed_at: nil, submittable: nil, data: nil, + legal_representatives: nil, shareholders: nil, documents: nil, client: nil, @@ -28,6 +29,7 @@ def initialize( @reviewed_at = reviewed_at @submittable = submittable @data = data + @legal_representatives = legal_representatives @shareholders = shareholders @documents = documents @client = client diff --git a/spec/lib/fintoc/v2/managers/onboardings_manager_spec.rb b/spec/lib/fintoc/v2/managers/onboardings_manager_spec.rb index 3b7439f..2bb6e81 100644 --- a/spec/lib/fintoc/v2/managers/onboardings_manager_spec.rb +++ b/spec/lib/fintoc/v2/managers/onboardings_manager_spec.rb @@ -8,6 +8,7 @@ let(:entity_id) { 'ent_12345' } let(:onboarding_id) { 'onbprc_0ujs' } let(:shareholder_id) { 'onbsh_123' } + let(:legal_representative_id) { 'onblr_123' } let(:base_path) { "entities/#{entity_id}/onboardings" } let(:manager) { described_class.new(client, entity_id) } @@ -39,6 +40,7 @@ first_onboarding_data.merge( submittable: true, data: {}, + legal_representatives: [], shareholders: [], documents: [] ) @@ -47,7 +49,7 @@ let(:create_params) do { company_information: { legal_name: 'ACME Inc.' }, - legal_representative: { first_name: 'Jane', last_name: 'Doe' }, + legal_representatives: [{ first_name: 'Jane', last_name: 'Doe' }], transactional_profile: { monthly_amount_range: '0-1000' }, shareholders: [{ type: 'natural_person', name: 'Jane', percentage: 100 }] } @@ -217,4 +219,39 @@ end end end + + describe '#upload_legal_representative_document' do + let(:slot_key) { 'identification' } + let(:file_path) { 'spec/support/fixtures/sample_document.pdf' } + + it 'puts a multipart file to the legal representative document slot path' do + manager.upload_legal_representative_document( + onboarding_id, legal_representative_id, slot_key, file: file_path + ) + + expect(client).to have_received(:put).with(version: :v2, idempotency_key: nil) + expect(put_proc).to have_received(:call).with( + "#{base_path}/#{onboarding_id}/legal_representatives" \ + "/#{legal_representative_id}/documents/#{slot_key}", + form: { file: file_path } + ) + expect(Fintoc::V2::Onboarding).to have_received(:new).with(**full_onboarding_data, client:) + end + + context 'when idempotency_key is provided' do + let(:idempotency_key) { '123e4567-e89b-12d3-a456-426614174000' } + + before do + allow(client).to receive(:put).with(version: :v2, idempotency_key:).and_return(put_proc) + end + + it 'passes idempotency_key to the PUT method' do + manager.upload_legal_representative_document( + onboarding_id, legal_representative_id, slot_key, file: file_path, idempotency_key: + ) + + expect(client).to have_received(:put).with(version: :v2, idempotency_key:) + end + end + end end diff --git a/spec/lib/fintoc/v2/onboarding_spec.rb b/spec/lib/fintoc/v2/onboarding_spec.rb index 0899018..59ab1b6 100644 --- a/spec/lib/fintoc/v2/onboarding_spec.rb +++ b/spec/lib/fintoc/v2/onboarding_spec.rb @@ -4,6 +4,28 @@ let(:api_key) { 'sk_test_SeCreT-aPi_KeY' } let(:client) { Fintoc::V2::Client.new(api_key) } + let(:legal_representative_data) do + { + id: 'onblr_123', + object: 'onboarding_legal_representative', + first_name: 'Jane', + last_name: 'Doe', + email: 'jane@acme.com', + nationality: 'mx', + identification_number: 'AAAA010101HDFAAA01', + position: 'Director General', + documents: [ + { + slot_key: 'identification', + status: 'uploaded', + filename: 'id.pdf', + uploaded_at: '2026-01-15T14:30:00Z' + }, + { slot_key: 'power_of_attorney', status: 'missing' } + ] + } + end + let(:shareholder_data) do { id: 'onbsh_123', @@ -38,6 +60,7 @@ reviewed_at: nil, submittable: false, data: { company_information: { legal_name: 'ACME Inc.' } }, + legal_representatives: [legal_representative_data], shareholders: [shareholder_data], documents: [document_data], client: client @@ -62,11 +85,16 @@ reviewed_at: nil, submittable: false, data: { company_information: { legal_name: 'ACME Inc.' } }, + legal_representatives: [legal_representative_data], shareholders: [shareholder_data], documents: [document_data] ) end + it 'keeps legal representatives as raw hashes' do + expect(onboarding.legal_representatives.first).to eq(legal_representative_data) + end + it 'keeps shareholders as raw hashes' do expect(onboarding.shareholders.first).to eq(shareholder_data) end @@ -98,6 +126,7 @@ source: 'dashboard', submittable: nil, data: nil, + legal_representatives: nil, shareholders: nil, documents: nil ) From 3a04d68f221826f5f3498ff1194107f1e734aeda Mon Sep 17 00:00:00 2001 From: tlarrain Date: Tue, 7 Jul 2026 08:30:28 -0400 Subject: [PATCH 2/2] docs(v2): document legal representative document upload Documents the legal_representatives attribute on the onboarding full shape and the upload_legal_representative_document usage, and updates the create example to the plural legal_representatives array the API now expects. --- README.md | 34 ++++++++++++++++++++++------------ 1 file changed, 22 insertions(+), 12 deletions(-) diff --git a/README.md b/README.md index 86114d0..0954096 100644 --- a/README.md +++ b/README.md @@ -407,11 +407,13 @@ entity = client.v2.entities.get('entity_id') # List the onboardings of an entity (cursor-paginated, light shape) onboardings = entity.onboardings.list -# Retrieve a single onboarding (full shape, includes shareholders and documents) +# Retrieve a single onboarding (full shape, includes legal representatives, +# shareholders and documents) onboarding = entity.onboardings.get('onboarding_id') -puts onboarding # 📋 Onboarding onbprc_0ujs... (in_progress) -onboarding.shareholders # => array of shareholder hashes -onboarding.documents # => array of document hashes +puts onboarding # 📋 Onboarding onbprc_0ujs... (in_progress) +onboarding.legal_representatives # => array of legal representative hashes +onboarding.shareholders # => array of shareholder hashes +onboarding.documents # => array of document hashes # Create an onboarding. The nested structures are passed through as-is and # validated by the API. @@ -425,14 +427,16 @@ onboarding = entity.onboardings.create( settlement_account: '1234567890', phone: '+56912345678' }, - legal_representative: { - first_name: 'Jane', - last_name: 'Doe', - email: 'jane@acme.com', - nationality: 'CL', - identification_number: '12345678-9', - position: 'CEO' - }, + legal_representatives: [ + { + first_name: 'Jane', + last_name: 'Doe', + email: 'jane@acme.com', + nationality: 'CL', + identification_number: '12345678-9', + position: 'CEO' + } + ], transactional_profile: { resource_origins: ['sales'], monthly_amount_range: '0-1000000', @@ -458,6 +462,12 @@ entity.onboardings.upload_shareholder_document( 'onboarding_id', 'shareholder_id', file: 'path/to/file.pdf' ) +# Upload a document for a specific legal representative (multipart). +# Slots: `identification` and `power_of_attorney`. +entity.onboardings.upload_legal_representative_document( + 'onboarding_id', 'legal_representative_id', 'identification', file: 'path/to/file.pdf' +) + # Submit the onboarding for review. onboarding = entity.onboardings.submit('onboarding_id') ```