conexa 0.0.6 → 0.0.8

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
data/README.md CHANGED
@@ -1,640 +1,404 @@
1
- # Conexa Ruby Gem
1
+ # Conexa Ruby
2
2
 
3
- Conexa Ruby library
3
+ [![Gem Version](https://badge.fury.io/rb/conexa.svg)](https://badge.fury.io/rb/conexa)
4
+ [![CI](https://github.com/guilhermegazzinelli/conexa-ruby/actions/workflows/main.yml/badge.svg)](https://github.com/guilhermegazzinelli/conexa-ruby/actions)
4
5
 
5
- **[Versão em Português](README_pt-BR.md)**
6
-
7
- ## Documentation
8
-
9
- - [Conexa Website](https://conexa.app/)
10
- - [API Documentation](https://conexa.app/api-docs)
11
- - [Conexa API Postman Collection](https://web.postman.co/workspace/8e1887b1-bef9-4e36-848f-2b6774a81022/collection/33452984-58f4d7ab-d280-4aac-8578-8366988ff7af)
12
-
13
- ## Getting Started
6
+ Ruby client for the [Conexa API](https://conexa.app/) - Billing and subscription management platform.
14
7
 
15
- ### Install
8
+ **[Versão em Português](README_pt-BR.md)**
16
9
 
17
- ```shell
18
- gem install conexa-ruby
19
- ```
10
+ ## Installation
20
11
 
21
- Or add the following line to your `Gemfile`:
12
+ Add to your Gemfile:
22
13
 
23
14
  ```ruby
24
- gem 'conexa-ruby'
15
+ gem 'conexa'
25
16
  ```
26
17
 
27
- Then run `bundle install` from your shell.
18
+ Or install directly:
28
19
 
29
- ### Configure Your API Key
20
+ ```shell
21
+ gem install conexa
22
+ ```
30
23
 
31
- You can set your API credentials in Ruby:
24
+ ## Configuration
32
25
 
33
26
  ```ruby
34
27
  Conexa.configure do |config|
35
- config.api_token = ENV['API_TOKEN']
36
- config.api_host = ENV['API_HOST']
28
+ config.subdomain = 'YOUR_SUBDOMAIN' # your-company.conexa.app
29
+ config.api_token = 'YOUR_API_TOKEN' # Application Token from Conexa
37
30
  end
38
31
  ```
39
32
 
40
- Ensure that you have set the environment variables `API_TOKEN` and `API_HOST` with your Conexa API token and host URL.
41
-
42
- ## Usage
43
-
44
- After configuration, you can start using the gem to interact with Conexa API resources.
45
-
46
- ### Available Resources
47
-
48
- - `Bill`
49
- - `Charge`
50
- - `Company`
51
- - `Contract`
52
- - `CreditCard`
53
- - `Customer`
54
- - `InvoicingMethod`
55
- - `LegalPerson`
56
- - `Person`
57
- - `Plan`
58
- - `Product`
59
- - `RecurringSale`
60
- - `Sale`
61
- - `Supplier`
62
-
63
- ### Method Patterns
64
-
65
- Each resource follows a consistent set of method patterns:
66
-
67
- - `Conexa::<ResourceName>.new(params).create` - Create a new resource.
68
- - `Conexa::<ResourceName>.all(params)` - Find all entities of the parameter.
69
- - `Conexa::<ResourceName>.find(id)` - Retrieve a resource by ID.
70
- - `Conexa::<ResourceName>.find(filter_hash, page, size)` - Retrieve resources matching filters with pagination.
71
- - `Conexa::<ResourceName>.destroy(id)` - Delete a resource by ID.
72
- - `Conexa::<ResourceName>.find(id).destroy` - Find and delete a resource.
73
-
74
- ### Pagination
75
-
76
- The API uses `page` and `size` parameters for pagination with the following defaults:
77
-
78
- - **page**: Current page number (default: `1`)
79
- - **size**: Number of items per page (default: `100`)
80
-
81
- #### Calling with Pagination
82
-
83
- ```ruby
84
- # Default pagination (page 1, 100 items)
85
- Conexa::Customer.all
86
-
87
- # Positional arguments (page, size)
88
- Conexa::Customer.all(2, 50) # page 2, 50 items per page
89
-
90
- # Named parameters
91
- Conexa::Customer.all(page: 3, size: 25)
92
-
93
- # Using the `where` alias
94
- Conexa::Customer.where(page: 2, size: 10)
95
- ```
96
-
97
- ### Result Object
98
-
99
- When listing resources, the API returns a `Conexa::Result` object containing:
100
-
101
- - **data**: Array of resource objects
102
- - **pagination**: `Conexa::Pagination` object with pagination metadata
103
-
104
- ```ruby
105
- result = Conexa::Customer.all
106
-
107
- # Access the data array
108
- result.data # => Array of Conexa::Customer objects
109
-
110
- # Access pagination info
111
- result.pagination # => Conexa::Pagination object
112
- ```
33
+ ### Authentication Methods
113
34
 
114
- #### Method Delegation to Data
35
+ 1. **Application Token** (recommended): Created in Conexa at **Config > Integrações > API / Token**
36
+ 2. **Username/Password**: Use the `/auth` endpoint to get a JWT token
115
37
 
116
- The `Result` object automatically delegates Array methods to the `data` attribute. This means you can call methods like `first`, `second`, `last`, `length`, `count`, `each`, `map`, etc. directly on the result:
38
+ ## Quick Start
117
39
 
118
40
  ```ruby
119
- result = Conexa::Customer.all
120
-
121
- # These methods are delegated to result.data
122
- result.first # => First Conexa::Customer (same as result.data.first)
123
- result.second # => Second Conexa::Customer
124
- result.last # => Last Conexa::Customer
125
- result.length # => Number of items in current page
126
- result.count # => Number of items in current page
127
- result.empty? # => true if no results
128
-
129
- # Direct iteration
130
- result.each { |customer| puts customer.name }
131
-
132
- # Transformations
133
- result.map(&:name) # => Array of customer names
134
- result.select { |c| c.active } # => Filter active customers
135
- ```
41
+ require 'conexa'
136
42
 
137
- ### Filtering
43
+ Conexa.configure do |config|
44
+ config.subdomain = 'mycompany'
45
+ config.api_token = ENV['CONEXA_API_TOKEN']
46
+ end
138
47
 
139
- You can filter results by passing parameters along with pagination. The available filters vary by resource.
48
+ # List customers
49
+ customers = Conexa::Customer.list
50
+ customers.data.each do |customer|
51
+ puts "#{customer.customer_id}: #{customer.name}"
52
+ end
140
53
 
141
- #### Common Filter Patterns
54
+ # Get a specific customer
55
+ customer = Conexa::Customer.retrieve(127)
56
+ puts customer.name
57
+ puts customer.address.city
58
+ ```
59
+
60
+ ## Convention
61
+
62
+ This gem follows Ruby conventions:
63
+
64
+ - **Parameters**: Use `snake_case` when calling methods - the gem automatically converts to `camelCase` for the API
65
+ - **Responses**: API responses are converted from `camelCase` to `snake_case`
66
+ - **Backwards compatibility**: `camelCase` methods are aliased (e.g., `customer.customer_id` and `customer.customerId` both work)
67
+
68
+ ## Resources
69
+
70
+ ### Customer
71
+
72
+ ```ruby
73
+ # Create a customer (Legal Person - PJ)
74
+ customer = Conexa::Customer.create(
75
+ company_id: 3,
76
+ name: 'Empresa ABC Ltda',
77
+ trade_name: 'ABC',
78
+ cell_number: '11999998888',
79
+ has_login_access: false,
80
+ legal_person: {
81
+ cnpj: '99.557.155/0001-90',
82
+ foundation_date: '2020-06-12'
83
+ },
84
+ address: {
85
+ zip_code: '13058-111',
86
+ state: 'SP',
87
+ city: 'Campinas',
88
+ street: 'Rua Principal',
89
+ number: '100',
90
+ neighborhood: 'Centro'
91
+ },
92
+ phones: ['(11) 3333-4444'],
93
+ emails_message: ['contato@empresa.com'],
94
+ emails_financial_messages: ['financeiro@empresa.com']
95
+ )
96
+ puts customer.id # => 114
97
+
98
+ # Create a customer (Natural Person - PF)
99
+ customer = Conexa::Customer.create(
100
+ company_id: 3,
101
+ name: 'João Silva',
102
+ natural_person: {
103
+ cpf: '516.079.209-05',
104
+ birth_date: '1990-05-15',
105
+ profession: 'Developer'
106
+ },
107
+ has_login_access: true,
108
+ login: 'joao.silva',
109
+ password: 'SecurePass123!'
110
+ )
142
111
 
143
- ```ruby
144
- # Filter by name
145
- Conexa::Customer.all(name: "John", page: 1, size: 10)
146
-
147
- # Filter by multiple IDs (array syntax)
148
- Conexa::Customer.all("id[]": [102, 103])
149
-
150
- # Filter by company
151
- Conexa::Customer.all("companyId[]": [3])
152
- Conexa::Contract.all("companyId[]": [540], page: 2, size: 5)
153
-
154
- # Multiple filters combined
155
- Conexa::Company.all(
156
- "id[]": [3, 4],
157
- trade_name: "Acme",
158
- legal_name: "Acme Corp",
159
- cnpj: "17.992.846/0001-58",
160
- city: "São Paulo",
161
- active: 1,
112
+ # Retrieve customer
113
+ customer = Conexa::Customer.retrieve(127)
114
+ customer.name # => "Empresa ABC Ltda"
115
+ customer.company_id # => 3
116
+ customer.is_active # => true
117
+ customer.address.city # => "Campinas"
118
+ customer.legal_person['cnpj'] # => "99.557.155/0001-90"
119
+
120
+ # Update customer
121
+ Conexa::Customer.update(127, name: 'New Name', cell_number: '11888887777')
122
+
123
+ # List customers with filters
124
+ customers = Conexa::Customer.list(
125
+ company_id: [3],
126
+ is_active: true,
162
127
  page: 1,
163
- size: 5
128
+ size: 20
164
129
  )
165
-
166
- # Filter bills by status
167
- Conexa::Bill.all(status: "pending", page: 1, size: 20)
168
-
169
- # Filter sales by date range
170
- Conexa::Sale.all(page: 2, size: 6)
171
- ```
172
-
173
- #### Resource-Specific Filters
174
-
175
- | Resource | Common Filters |
176
- |----------|---------------|
177
- | Customer | `name`, `id[]`, `companyId[]` |
178
- | Company | `id[]`, `tradeName`, `legalName`, `cnpj`, `city`, `active` |
179
- | Contract | `companyId[]`, `active` |
180
- | Bill | `status`, `companyId[]` |
181
- | Plan | `id[]` |
182
- | Sale | `date` |
183
- | InvoicingMethod | `id[]`, `companyId[]`, `isActive`, `type` |
184
-
185
- ### Resource-Specific Operations (Sub-processes)
186
-
187
- Some resources have additional operations beyond CRUD:
188
-
189
- #### Charge Operations
190
-
191
- ```ruby
192
- # Settle (pay) a charge
193
- charge = Conexa::Charge.find(charge_id)
194
- charge.settle(payment_params)
195
-
196
- # Or directly by ID
197
- Conexa::Charge.settle(charge_id, payment_params)
198
-
199
- # Get PIX QR Code for a charge
200
- pix_data = Conexa::Charge.pix(charge_id)
201
- # Returns QR code data for payment
202
- ```
203
-
204
- #### Contract Operations
205
-
206
- ```ruby
207
- # End/terminate a contract
208
- contract = Conexa::Contract.find(contract_id)
209
- contract.end_contract(end_date: "2024-12-31", reason: "Customer request")
210
-
211
- # Or directly by ID
212
- Conexa::Contract.end_contract(contract_id, end_date: "2024-12-31")
213
- ```
214
-
215
- #### Recurring Sale Operations
216
-
217
- ```ruby
218
- # End a recurring sale
219
- recurring_sale = Conexa::RecurringSale.find(recurring_sale_id)
220
- recurring_sale.end_recurring_sale(end_date: "2024-12-31")
221
-
222
- # Or directly by ID
223
- Conexa::RecurringSale.end_recurring_sale(recurring_sale_id, end_date: "2024-12-31")
224
- ```
225
-
226
- #### Invoicing Method
227
-
228
- ```ruby
229
- # List invoicing methods with filters
230
- Conexa::InvoicingMethod.all("companyId[]": [3], is_active: 1, type: "billet")
231
-
232
- # Find by ID
233
- Conexa::InvoicingMethod.find(invoicing_method_id)
234
- ```
235
-
236
- #### Credit Card
237
-
238
- ```ruby
239
- # Create a credit card for a customer
240
- Conexa::CreditCard.new(
241
- customer_id: customer_id,
242
- card_number: "4111111111111111",
243
- card_holder_name: "John Doe",
244
- expiration_date: "12/25",
245
- cvv: "123"
246
- ).create
247
- ```
248
-
249
- #### Supplier
250
-
251
- ```ruby
252
- # Create a supplier (legal person)
253
- Conexa::Supplier.new(
254
- company_id: company_id,
255
- legal_name: "Supplier Corp",
256
- trade_name: "Supplier",
257
- cnpj: "12.345.678/0001-90"
258
- ).create
259
-
260
- # Create a supplier (natural person)
261
- Conexa::Supplier.new(
262
- company_id: company_id,
263
- name: "John Supplier",
264
- cpf: "123.456.789-00"
265
- ).create
266
- ```
267
-
268
- ### Navigating Between Pages
269
-
270
- ```ruby
271
- # Fetch first page
272
- page1 = Conexa::Customer.all(page: 1, size: 10)
273
- puts "Page 1: #{page1.data.count} customers"
274
-
275
- # Fetch next page
276
- page2 = Conexa::Customer.all(page: 2, size: 10)
277
- puts "Page 2: #{page2.data.count} customers"
278
-
279
- # Check pagination metadata
280
- pagination = page1.pagination
281
- # pagination contains total records, total pages, etc.
282
- ```
283
-
284
- #### Iterating Through All Pages
285
-
286
- ```ruby
287
- page = 1
288
- size = 100
289
-
290
- loop do
291
- result = Conexa::Customer.all(page: page, size: size)
292
-
293
- break if result.data.empty?
294
-
295
- result.each do |customer|
296
- # Process each customer
297
- puts customer.name
298
- end
299
-
300
- page += 1
301
- end
302
- ```
303
-
304
- ### Examples
305
-
306
- #### Customers
307
-
308
- ##### Creating a Customer
309
-
310
- ```ruby
311
- customer = Conexa::Customer.new(
312
- name: 'John Doe',
313
- email: 'john.doe@example.com',
314
- phone: '555-1234'
315
- ).create
316
- ```
317
-
318
- ##### Retrieving a Customer
319
-
320
- ```ruby
321
- customer = Conexa::Customer.find(customer_id)
322
- ```
323
-
324
- ##### Updating a Customer
325
-
326
- ```ruby
327
- customer = Conexa::Customer.find(customer_id)
328
- customer.email = 'new.email@example.com'
329
- customer.save
330
- ```
331
-
332
- ##### Deleting a Customer
333
-
334
- ```ruby
335
- Conexa::Customer.destroy(customer_id)
336
- ```
337
-
338
- Or:
339
-
340
- ```ruby
341
- customer = Conexa::Customer.find(customer_id)
342
- customer.destroy
343
- ```
344
-
345
- ##### Listing Customers
346
-
347
- ```ruby
348
- customers = Conexa::Customer.find({ name: 'John Doe' }, 1, 20)
349
- ```
350
-
351
- #### Bills
352
-
353
- ##### Creating a Bill
354
-
355
- ```ruby
356
- bill = Conexa::Bill.new(
357
- customer_id: customer_id,
358
- amount: 1000, # in cents
359
- due_date: '2024-12-31'
360
- ).create
361
- ```
362
-
363
- ##### Retrieving a Bill
364
-
365
- ```ruby
366
- bill = Conexa::Bill.find(bill_id)
367
- ```
368
-
369
- ##### Deleting a Bill
370
-
371
- ```ruby
372
- Conexa::Bill.destroy(bill_id)
373
130
  ```
374
131
 
375
- ##### Listing Bills
132
+ ### Contract
376
133
 
377
134
  ```ruby
378
- bills = Conexa::Bill.find({ status: 'pending' }, 1, 20)
379
- ```
380
-
381
- #### Charges
382
-
383
- ##### Creating a Charge
384
-
385
- ```ruby
386
- charge = Conexa::Charge.new(
387
- customer_id: customer_id,
388
- amount: 1000, # in cents
389
- payment_method: 'credit_card',
390
- card_number: '4111111111111111',
391
- card_holder_name: 'John Doe',
392
- card_expiration_date: '12/25',
393
- card_cvv: '123'
394
- ).create
395
- ```
396
-
397
- ##### Retrieving a Charge
135
+ # Create a contract
136
+ contract = Conexa::Contract.create(
137
+ customer_id: 127,
138
+ plan_id: 5,
139
+ start_date: '2024-01-01',
140
+ payment_day: 10,
141
+ invoicing_method_id: 1
142
+ )
398
143
 
399
- ```ruby
400
- charge = Conexa::Charge.find(charge_id)
401
- ```
144
+ # Create contract with custom items
145
+ contract = Conexa::Contract.create_with_products(
146
+ customer_id: 127,
147
+ start_date: '2024-01-01',
148
+ payment_day: 10,
149
+ items: [
150
+ { product_id: 101, quantity: 1, amount: 299.90 },
151
+ { product_id: 102, quantity: 2, amount: 49.90 }
152
+ ]
153
+ )
402
154
 
403
- ##### Deleting a Charge
155
+ # Retrieve contract
156
+ contract = Conexa::Contract.retrieve(456)
404
157
 
405
- ```ruby
406
- Conexa::Charge.destroy(charge_id)
158
+ # Cancel contract
159
+ Conexa::Contract.cancel(456, cancel_date: '2024-12-31')
407
160
  ```
408
161
 
409
- ##### Listing Charges
162
+ ### Sale (One-time)
410
163
 
411
164
  ```ruby
412
- charges = Conexa::Charge.find({ status: 'paid' }, 1, 20)
413
- ```
414
-
415
- #### Plans
165
+ # Create a one-time sale
166
+ sale = Conexa::Sale.create(
167
+ customer_id: 450,
168
+ requester_id: 458,
169
+ product_id: 2521,
170
+ quantity: 1,
171
+ amount: 80.99,
172
+ reference_date: '2024-09-24T17:24:00-03:00',
173
+ notes: 'WhatsApp order'
174
+ )
175
+ puts sale.id # => 188481
176
+
177
+ # Retrieve sale
178
+ sale = Conexa::Sale.retrieve(188510)
179
+ sale.status # => "notBilled"
180
+ sale.amount # => 80.99
181
+ sale.discount_value # => 69.21
182
+
183
+ # List sales
184
+ sales = Conexa::Sale.list(
185
+ customer_id: [450, 216],
186
+ status: 'notBilled',
187
+ date_from: '2024-01-01',
188
+ date_to: '2024-12-31',
189
+ page: 1,
190
+ size: 20
191
+ )
416
192
 
417
- ##### Creating a Plan
193
+ # Update sale
194
+ Conexa::Sale.update(188510, quantity: 2, amount: 150.00)
418
195
 
419
- ```ruby
420
- plan = Conexa::Plan.new(
421
- name: 'Premium Plan',
422
- amount: 4990, # in cents
423
- billing_cycle: 'monthly'
424
- ).create
196
+ # Delete sale (only if not billed)
197
+ Conexa::Sale.delete(188510)
425
198
  ```
426
199
 
427
- ##### Retrieving a Plan
200
+ ### Recurring Sale
428
201
 
429
202
  ```ruby
430
- plan = Conexa::Plan.find(plan_id)
431
- ```
432
-
433
- ##### Deleting a Plan
203
+ # Create recurring sale
204
+ recurring = Conexa::RecurringSale.create(
205
+ customer_id: 127,
206
+ product_id: 101,
207
+ quantity: 1,
208
+ start_date: '2024-01-01'
209
+ )
434
210
 
435
- ```ruby
436
- Conexa::Plan.destroy(plan_id)
211
+ # List recurring sales for a contract
212
+ Conexa::RecurringSale.list(contract_id: 456)
437
213
  ```
438
214
 
439
- ##### Listing Plans
215
+ ### Charge
440
216
 
441
217
  ```ruby
442
- plans = Conexa::Plan.find({}, 1, 20)
443
- ```
218
+ # Retrieve charge
219
+ charge = Conexa::Charge.retrieve(789)
220
+ charge.status # => "paid"
221
+ charge.amount # => 299.90
222
+ charge.due_date # => "2024-02-10"
444
223
 
445
- #### Contracts
446
-
447
- ##### Creating a Contract
448
-
449
- ```ruby
450
- contract = Conexa::Contract.new(
451
- customer_id: customer_id,
452
- plan_id: plan_id,
453
- start_date: '2024-01-01',
454
- end_date: '2024-12-31'
455
- ).create
456
- ```
224
+ # List charges
225
+ charges = Conexa::Charge.list(
226
+ customer_id: [127],
227
+ status: 'pending',
228
+ due_date_from: '2024-01-01',
229
+ due_date_to: '2024-12-31'
230
+ )
457
231
 
458
- ##### Retrieving a Contract
232
+ # Cancel charge
233
+ Conexa::Charge.cancel(789)
459
234
 
460
- ```ruby
461
- contract = Conexa::Contract.find(contract_id)
235
+ # Send charge by email
236
+ Conexa::Charge.send_email(789)
462
237
  ```
463
238
 
464
- ##### Deleting a Contract
239
+ ### Bill (Invoice)
465
240
 
466
241
  ```ruby
467
- Conexa::Contract.destroy(contract_id)
468
- ```
242
+ # Retrieve bill
243
+ bill = Conexa::Bill.retrieve(101)
469
244
 
470
- ##### Listing Contracts
471
-
472
- ```ruby
473
- contracts = Conexa::Contract.find({ active: true }, 1, 20)
245
+ # List bills
246
+ bills = Conexa::Bill.list(
247
+ customer_id: [127],
248
+ page: 1,
249
+ size: 50
250
+ )
474
251
  ```
475
252
 
476
- #### Products
477
-
478
- ##### Creating a Product
253
+ ### Plan
479
254
 
480
255
  ```ruby
481
- product = Conexa::Product.new(
482
- name: 'Product Name',
483
- description: 'Product Description',
484
- price: 2990 # in cents
485
- ).create
486
- ```
487
-
488
- ##### Retrieving a Product
256
+ # List plans
257
+ plans = Conexa::Plan.list(company_id: [3])
489
258
 
490
- ```ruby
491
- product = Conexa::Product.find(product_id)
259
+ # Retrieve plan
260
+ plan = Conexa::Plan.retrieve(5)
261
+ plan.name # => "Plano Básico"
262
+ plan.price # => 99.90
492
263
  ```
493
264
 
494
- ##### Deleting a Product
265
+ ### Product
495
266
 
496
267
  ```ruby
497
- Conexa::Product.destroy(product_id)
498
- ```
499
-
500
- ##### Listing Products
268
+ # List products
269
+ products = Conexa::Product.list(company_id: [3])
501
270
 
502
- ```ruby
503
- products = Conexa::Product.find({ category: 'Electronics' }, 1, 20)
271
+ # Retrieve product
272
+ product = Conexa::Product.retrieve(101)
504
273
  ```
505
274
 
506
- #### Sales
507
-
508
- ##### Creating a Sale
275
+ ### Credit Card
509
276
 
510
277
  ```ruby
511
- sale = Conexa::Sale.new(
512
- customer_id: customer_id,
513
- product_id: product_id,
514
- quantity: 2,
515
- total_amount: 5980 # in cents
516
- ).create
517
- ```
278
+ # Add credit card to customer
279
+ card = Conexa::CreditCard.create(
280
+ customer_id: 127,
281
+ card_number: '4111111111111111',
282
+ cardholder_name: 'JOAO SILVA',
283
+ expiration_month: '12',
284
+ expiration_year: '2025',
285
+ cvv: '123'
286
+ )
518
287
 
519
- ##### Retrieving a Sale
288
+ # List customer's cards
289
+ cards = Conexa::CreditCard.list(customer_id: 127)
520
290
 
521
- ```ruby
522
- sale = Conexa::Sale.find(sale_id)
291
+ # Delete card
292
+ Conexa::CreditCard.delete(card_id)
523
293
  ```
524
294
 
525
- ##### Deleting a Sale
295
+ ### Company (Unit)
526
296
 
527
297
  ```ruby
528
- Conexa::Sale.destroy(sale_id)
529
- ```
530
-
531
- ##### Listing Sales
298
+ # List companies/units
299
+ companies = Conexa::Company.list
532
300
 
533
- ```ruby
534
- sales = Conexa::Sale.find({ date: '2024-01-01' }, 1, 20)
301
+ # Retrieve company
302
+ company = Conexa::Company.retrieve(3)
303
+ company.name # => "Matriz"
304
+ company.document # => "12.345.678/0001-90"
535
305
  ```
536
306
 
537
- #### Recurring Sales
538
-
539
- ##### Creating a Recurring Sale
540
-
541
- ```ruby
542
- recurring_sale = Conexa::RecurringSale.new(
543
- customer_id: customer_id,
544
- plan_id: plan_id,
545
- start_date: '2024-01-01'
546
- ).create
547
- ```
307
+ ## Pagination
548
308
 
549
- ##### Retrieving a Recurring Sale
309
+ All list endpoints return paginated results:
550
310
 
551
311
  ```ruby
552
- recurring_sale = Conexa::RecurringSale.find(recurring_sale_id)
553
- ```
312
+ result = Conexa::Customer.list(page: 1, size: 20)
554
313
 
555
- ##### Deleting a Recurring Sale
314
+ result.data # Array of customers
315
+ result.pagination.current_page # => 1
316
+ result.pagination.total_pages # => 10
317
+ result.pagination.total_items # => 195
318
+ result.pagination.item_per_page # => 20
556
319
 
557
- ```ruby
558
- Conexa::RecurringSale.destroy(recurring_sale_id)
320
+ # Iterate through pages
321
+ loop do
322
+ result.data.each { |customer| process(customer) }
323
+ break if result.pagination.current_page >= result.pagination.total_pages
324
+ result = Conexa::Customer.list(page: result.pagination.current_page + 1)
325
+ end
559
326
  ```
560
327
 
561
- ##### Listing Recurring Sales
328
+ ## Error Handling
562
329
 
563
330
  ```ruby
564
- recurring_sales = Conexa::RecurringSale.find({ active: true }, 1, 20)
331
+ begin
332
+ customer = Conexa::Customer.create(name: '')
333
+ rescue Conexa::ValidationError => e
334
+ # Field validation errors (400)
335
+ e.errors.each do |error|
336
+ puts "#{error['field']}: #{error['messages'].join(', ')}"
337
+ end
338
+ rescue Conexa::AuthenticationError => e
339
+ # Authentication required (401)
340
+ puts e.message
341
+ rescue Conexa::AuthorizationError => e
342
+ # Not authorized (403)
343
+ puts e.message
344
+ rescue Conexa::NotFoundError => e
345
+ # Resource not found (404)
346
+ puts e.message
347
+ rescue Conexa::UnprocessableError => e
348
+ # Business logic error (422)
349
+ e.errors.each do |error|
350
+ puts "#{error['code']}: #{error['message']}"
351
+ end
352
+ rescue Conexa::RateLimitError => e
353
+ # Too many requests (429)
354
+ puts "Rate limit exceeded. Retry after #{e.retry_after} seconds"
355
+ rescue Conexa::ApiError => e
356
+ # Generic API error
357
+ puts "Error #{e.status}: #{e.message}"
358
+ end
565
359
  ```
566
360
 
567
- ### Common Methods
568
-
569
- Each resource provides common methods:
361
+ ## Rate Limiting
570
362
 
571
- - `new(params).create` - Create a new record.
572
- - `find(id)` - Retrieve a specific record by ID.
573
- - `find(filter_hash, page, size)` - Retrieve records matching filters with pagination.
574
- - `destroy(id)` - Delete a record by ID.
575
- - `find(id).destroy` - Find and delete a record.
363
+ The Conexa API has a limit of **100 requests per minute**. Response headers include:
576
364
 
577
- ### Resource-Specific Operations
578
-
579
- Some resources may offer additional methods specific to their functionality. Refer to the [Conexa API Documentation](https://conexa.app/api-docs) for detailed information.
580
-
581
- ## Validating Webhooks
582
-
583
- To ensure that all received webhooks are sent by Conexa, you should validate the signature provided in the HTTP header `X-Signature`. You can validate it using the raw payload and the signature.
584
-
585
- ```ruby
586
- valid = Conexa::Webhook.valid_request_signature?(raw_payload, signature)
587
- ```
365
+ - `X-Rate-Limit-Limit`: Maximum requests in 60s
366
+ - `X-Rate-Limit-Remaining`: Remaining requests in 60s
367
+ - `X-Rate-Limit-Reset`: Seconds until reset
588
368
 
589
- ### Rails Example
369
+ ## Documentation
590
370
 
591
- If you are using Rails, you can validate the webhook in your controller:
371
+ - [Conexa Website](https://conexa.app/)
372
+ - [API Documentation](https://conexa.app/api-docs)
373
+ - [Postman Collection](https://documenter.getpostman.com/view/25182821/2s93RZMpcB)
374
+ - [Discord Community](https://discord.gg/zW28sJh7Nz) - Conexa for Developers
375
+ - [REFERENCE.md](REFERENCE.md) - Complete API reference for LLMs/AI agents
592
376
 
593
- ```ruby
594
- class WebhooksController < ApplicationController
595
- skip_before_action :verify_authenticity_token
596
-
597
- def receive
598
- if valid_webhook?
599
- # Handle your code here
600
- # Webhook payload is in params
601
- else
602
- render_invalid_webhook_response
603
- end
604
- end
377
+ ## Development
605
378
 
606
- private
379
+ ```bash
380
+ # Install dependencies
381
+ bundle install
607
382
 
608
- def valid_webhook?
609
- raw_payload = request.raw_post
610
- signature = request.headers['X-Signature']
611
- Conexa::Webhook.valid_request_signature?(raw_payload, signature)
612
- end
383
+ # Run tests
384
+ bundle exec rspec
613
385
 
614
- def render_invalid_webhook_response
615
- render json: { error: 'Invalid webhook' }, status: 400
616
- end
617
- end
386
+ # Run linter
387
+ bundle exec rubocop
618
388
  ```
619
389
 
620
- ## Undocumented Features
621
-
622
- This gem is stable but under continuous development. This README provides a quick overview of its main features.
623
-
624
- You can explore the source code to see all [supported resources](lib/conexa/resources). We will continue to document and add support for all features listed in the [Conexa API Documentation](https://conexa.app/api-docs).
390
+ ## Contributing
625
391
 
626
- Feel free to contribute by sending pull requests.
627
-
628
- ## Support
629
-
630
- If you have any problems or suggestions, please open an issue [here](https://github.com/guilhermegazzinelli/conexa-ruby/issues).
392
+ 1. Fork the repository
393
+ 2. Create your feature branch (`git checkout -b feature/amazing-feature`)
394
+ 3. Commit your changes (`git commit -am 'Add amazing feature'`)
395
+ 4. Push to the branch (`git push origin feature/amazing-feature`)
396
+ 5. Create a Pull Request
631
397
 
632
398
  ## License
633
399
 
634
- This project is licensed under the [MIT License](LICENSE).
635
-
636
- ## Disclaimer
400
+ MIT License. See [LICENSE](LICENSE) for details.
637
401
 
638
- This gem is based on the Conexa API definitions available in the official [Postman collection](https://web.postman.co/workspace/8e1887b1-bef9-4e36-848f-2b6774a81022/collection/33452984-58f4d7ab-d280-4aac-8578-8366988ff7af). It currently supports authentication via API key only.
402
+ ## Changelog
639
403
 
640
- For more information about the Conexa API, visit the [official documentation](https://conexa.app/).
404
+ See [CHANGELOG.md](CHANGELOG.md) for release history.