vindi-rails 0.2.0 → 0.3.0

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/WIKI.md CHANGED
@@ -1,246 +1,479 @@
1
- # Vindi SDK Wiki
2
-
3
- [Leia em Português (WIKI.pt-BR.md)](./WIKI.pt-BR.md)
4
-
5
- Welcome to the `vindi-rails` SDK Wiki. This document details all the mapped resources, operations, and advanced usage guidelines.
6
-
7
- ---
8
-
9
- ## 1. SDK Design & Architecture
10
-
11
- The SDK uses `RestClient` internally to communicate with the Vindi API.
12
- Resources are represented as Ruby objects inheriting from `Vindi::Resource`. Attributes returned from the API are accessible via dot-notation methods on the instances.
13
-
14
- ### Error Handling
15
-
16
- The SDK raises specific error classes based on HTTP status codes. All errors inherit from `Vindi::Error`:
17
-
18
- - `Vindi::UnauthorizedError` (401)
19
- - `Vindi::ForbiddenError` (403)
20
- - `Vindi::NotFoundError` (404)
21
- - `Vindi::UnprocessableEntityError` (422)
22
- - `Vindi::RateLimitError` (429)
23
- - `Vindi::InternalServerError` (500+)
24
- - `Vindi::APIError` (Fallback for other HTTP statuses)
25
-
26
- ---
27
-
28
- ## 2. Resource Mapping & CRUD Capabilities
29
-
30
- The table below lists all mapped resources and their operations:
31
-
32
- | Resource Class | Endpoint | CRUD Operations Enabled |
33
- | :--- | :--- | :--- |
34
- | `Vindi::Customer` | `customers` | `list`, `create`, `update`, `delete` |
35
- | `Vindi::PaymentProfile` | `payment_profiles` | `list`, `create`, `delete` |
36
- | `Vindi::Subscription` | `subscriptions` | `list`, `create`, `update`, `delete` |
37
- | `Vindi::Charge` | `charges` | `list`, `create`, `update` |
38
- | `Vindi::Plan` | `plans` | `list`, `create`, `update`, `delete` |
39
- | `Vindi::Product` | `products` | `list`, `create`, `update`, `delete` |
40
- | `Vindi::ProductItem` | `product_items` | `list`, `create`, `update`, `delete` |
41
- | `Vindi::Discount` | `discounts` | `list`, `create`, `delete` |
42
- | `Vindi::Bill` | `bills` | `list`, `create`, `update`, `delete` |
43
- | `Vindi::BillItem` | `bill_items` | `list` |
44
- | `Vindi::Period` | `periods` | `list` |
45
- | `Vindi::Transaction` | `transactions` | `list`, `create` |
46
- | `Vindi::Usage` | `usages` | `list`, `create`, `delete` |
47
- | `Vindi::Invoice` | `invoices` | `list` |
48
- | `Vindi::Movement` | `movements` | `list` |
49
- | `Vindi::Message` | `messages` | `list` |
50
- | `Vindi::ExportBatch` | `export_batches` | `list`, `create` |
51
- | `Vindi::ImportBatch` | `import_batches` | `list`, `create` |
52
- | `Vindi::Issue` | `issues` | `list`, `update` |
53
- | `Vindi::Notification` | `notifications` | `list` |
54
- | `Vindi::Merchant` | `merchants` | `list` |
55
- | `Vindi::MerchantUser` | `merchant_users` | `list` |
56
- | `Vindi::Role` | `roles` | `list` |
57
- | `Vindi::User` | `users` | `list` |
58
- | `Vindi::Public` | `public` | None (Static Config) |
59
- | `Vindi::Affiliate` | `affiliates` | `list` |
60
- | `Vindi::Partner` | `partner` | `list` |
61
-
62
- ---
63
-
64
- ## 3. Usage Examples
65
-
66
- ### Customers (`Vindi::Customer`)
67
-
68
- ```ruby
69
- # Create a customer
70
- customer = Vindi::Customer.create(
71
- name: "John Doe",
72
- email: "john@example.com"
73
- )
74
-
75
- # Fetch attribute
76
- puts customer.id
77
- puts customer.name
78
-
79
- # Update customer
80
- updated = Vindi::Customer.update(customer.id, email: "john.new@example.com")
81
-
82
- # Delete customer
83
- Vindi::Customer.delete(customer.id)
84
- ```
85
-
86
- ### Payment Profiles (`Vindi::PaymentProfile`)
87
-
88
- ```ruby
89
- # Create a card payment profile
90
- profile = Vindi::PaymentProfile.create(
91
- customer_id: 12345,
92
- payment_company_code: "visa",
93
- holder_name: "JOHN DOE",
94
- card_number: "4111111111111111",
95
- card_expiration_date: "12/2030",
96
- card_cvv: "123"
97
- )
98
-
99
- # Delete payment profile
100
- Vindi::PaymentProfile.delete(profile.id)
101
- ```
102
-
103
- ### Subscriptions (`Vindi::Subscription`)
104
-
105
- ```ruby
106
- # Create subscription
107
- subscription = Vindi::Subscription.create(
108
- customer_id: customer.id,
109
- plan_id: plan.id,
110
- payment_method_code: "credit_card"
111
- )
112
-
113
- # Cancel/Delete subscription
114
- Vindi::Subscription.delete(subscription.id)
115
- ```
116
-
117
- ### Charges (`Vindi::Charge`)
118
-
119
- ```ruby
120
- # List charges
121
- charges = Vindi::Charge.list(status: "pending")
122
-
123
- # Charge details
124
- puts charges.first.amount
125
- ```
126
-
127
- ### Plans (`Vindi::Plan`)
128
-
129
- ```ruby
130
- # Create a plan
131
- plan = Vindi::Plan.create(
132
- name: "Premium Gold Plan",
133
- code: "gold_premium",
134
- interval: "months",
135
- interval_count: 1
136
- )
137
-
138
- # List plans
139
- plans = Vindi::Plan.list
140
- ```
141
-
142
- ### Products & Product Items (`Vindi::Product` & `Vindi::ProductItem`)
143
-
144
- ```ruby
145
- # Create a product
146
- product = Vindi::Product.create(
147
- name: "Hosting Service",
148
- code: "hosting"
149
- )
150
-
151
- # Associate a product to a plan/subscription
152
- product_item = Vindi::ProductItem.create(
153
- product_id: product.id,
154
- plan_id: plan.id
155
- )
156
- ```
157
-
158
- ### Discounts (`Vindi::Discount`)
159
-
160
- ```ruby
161
- # Create/apply a discount
162
- discount = Vindi::Discount.create(
163
- amount: 15.00,
164
- discount_type: "percentage",
165
- percentage: 10
166
- )
167
- ```
168
-
169
- ### Bills & Bill Items (`Vindi::Bill` & `Vindi::BillItem`)
170
-
171
- ```ruby
172
- # Create a bill manually
173
- bill = Vindi::Bill.create(
174
- customer_id: customer.id,
175
- payment_method_code: "credit_card",
176
- bill_items: [
177
- { product_id: product.id, amount: 99.90 }
178
- ]
179
- )
180
-
181
- # List bill items
182
- items = Vindi::BillItem.list(bill_id: bill.id)
183
- ```
184
-
185
- ### Periods (`Vindi::Period`)
186
-
187
- ```ruby
188
- # List subscription periods
189
- periods = Vindi::Period.list(subscription_id: subscription.id)
190
- ```
191
-
192
- ### Transactions (`Vindi::Transaction`)
193
-
194
- ```ruby
195
- # Create a manual transaction/charge capture
196
- transaction = Vindi::Transaction.create(
197
- charge_id: charge.id,
198
- amount: 99.90
199
- )
200
-
201
- # List transactions
202
- transactions = Vindi::Transaction.list
203
- ```
204
-
205
- ### Usages (`Vindi::Usage`)
206
-
207
- ```ruby
208
- # Report a metered usage for a subscription
209
- usage = Vindi::Usage.create(
210
- subscription_id: subscription.id,
211
- quantity: 50,
212
- description: "API Calls consumed"
213
- )
214
-
215
- # List usages
216
- usages = Vindi::Usage.list(subscription_id: subscription.id)
217
- ```
218
-
219
- ### Invoices (`Vindi::Invoice`)
220
-
221
- ```ruby
222
- # List invoices
223
- invoices = Vindi::Invoice.list(status: "issued")
224
- ```
225
-
226
- ### Issues (`Vindi::Issue`)
227
-
228
- ```ruby
229
- # Update an issue status (e.g. resolve a billing conflict)
230
- issue = Vindi::Issue.update(issue_id, status: "resolved")
231
- ```
232
-
233
- ### Import/Export Batches (`Vindi::ImportBatch` & `Vindi::ExportBatch`)
234
-
235
- ```ruby
236
- # Start a new customer/subscription import batch
237
- import_batch = Vindi::ImportBatch.create(
238
- batch_type: "customer",
239
- file_url: "https://example.com/import.csv"
240
- )
241
-
242
- # Request a data export batch
243
- export_batch = Vindi::ExportBatch.create(
244
- batch_type: "bill"
245
- )
246
- ```
1
+ # Vindi SDK Wiki
2
+
3
+ [Leia em Português (WIKI.pt-BR.md)](./WIKI.pt-BR.md)
4
+
5
+ Welcome to the `vindi-rails` SDK Wiki. This document details all the mapped resources, operations, and advanced usage guidelines.
6
+
7
+ ---
8
+
9
+ ## 1. SDK Design & Architecture
10
+
11
+ The SDK uses `RestClient` internally to communicate with the Vindi API.
12
+ Resources are represented as Ruby objects inheriting from `Vindi::Resource`. Attributes returned from the API are accessible via dot-notation methods on the instances.
13
+
14
+ ### Error Handling
15
+
16
+ The SDK raises specific error classes based on HTTP status codes. All errors inherit from `Vindi::Error`:
17
+
18
+ - `Vindi::UnauthorizedError` (401)
19
+ - `Vindi::ForbiddenError` (403)
20
+ - `Vindi::NotFoundError` (404)
21
+ - `Vindi::UnprocessableEntityError` (422)
22
+ - `Vindi::RateLimitError` (429)
23
+ - `Vindi::InternalServerError` (500+)
24
+ - `Vindi::APIError` (Fallback for other HTTP statuses)
25
+
26
+ ---
27
+
28
+ ## 2. Resource Mapping & CRUD Capabilities
29
+
30
+ The table below lists all mapped resources and their operations:
31
+
32
+ | Resource Class | Endpoint | CRUD Operations Enabled |
33
+ | :--- | :--- | :--- |
34
+ | `Vindi::Customer` | `customers` | `list`, `create`, `update`, `delete` |
35
+ | `Vindi::PaymentProfile` | `payment_profiles` | `list`, `create`, `delete` |
36
+ | `Vindi::Subscription` | `subscriptions` | `list`, `create`, `update`, `delete` |
37
+ | `Vindi::Charge` | `charges` | `list`, `create`, `update` |
38
+ | `Vindi::Plan` | `plans` | `list`, `create`, `update`, `delete` |
39
+ | `Vindi::Product` | `products` | `list`, `create`, `update`, `delete` |
40
+ | `Vindi::ProductItem` | `product_items` | `list`, `create`, `update`, `delete` |
41
+ | `Vindi::Discount` | `discounts` | `list`, `create`, `delete` |
42
+ | `Vindi::Bill` | `bills` | `list`, `create`, `update`, `delete` |
43
+ | `Vindi::BillItem` | `bill_items` | `list` |
44
+ | `Vindi::Period` | `periods` | `list` |
45
+ | `Vindi::Transaction` | `transactions` | `list`, `create` |
46
+ | `Vindi::Usage` | `usages` | `list`, `create`, `delete` |
47
+ | `Vindi::Invoice` | `invoices` | `list` |
48
+ | `Vindi::Movement` | `movements` | `list` |
49
+ | `Vindi::Message` | `messages` | `list` |
50
+ | `Vindi::ExportBatch` | `export_batches` | `list`, `create` |
51
+ | `Vindi::ImportBatch` | `import_batches` | `list`, `create` |
52
+ | `Vindi::Issue` | `issues` | `list`, `update` |
53
+ | `Vindi::Notification` | `notifications` | `list` |
54
+ | `Vindi::Merchant` | `merchants` | `list` |
55
+ | `Vindi::MerchantUser` | `merchant_users` | `list` |
56
+ | `Vindi::Role` | `roles` | `list` |
57
+ | `Vindi::User` | `users` | `list` |
58
+ | `Vindi::Public` | `public` | None (Static Config) |
59
+ | `Vindi::Affiliate` | `affiliates` | `list` |
60
+ | `Vindi::Partner` | `partner` | `list` |
61
+
62
+ ---
63
+
64
+ ## 3. Usage Examples
65
+
66
+ ### Customers (`Vindi::Customer`)
67
+
68
+ ```ruby
69
+ # Create a customer
70
+ customer = Vindi::Customer.create(
71
+ name: "John Doe",
72
+ email: "john@example.com"
73
+ )
74
+
75
+ # Create a customer with an idempotency key (prevents duplicates)
76
+ customer = Vindi::Customer.create(
77
+ { name: "John Doe", email: "john@example.com" },
78
+ idempotency_key: "unique-uuid-or-key"
79
+ )
80
+
81
+ # Fetch attribute
82
+ puts customer.id
83
+ puts customer.name
84
+
85
+ # Update customer
86
+ updated = Vindi::Customer.update(customer.id, email: "john.new@example.com")
87
+
88
+ # Delete customer
89
+ Vindi::Customer.delete(customer.id)
90
+ ```
91
+
92
+ ### Payment Profiles (`Vindi::PaymentProfile`)
93
+
94
+ ```ruby
95
+ # Create a card payment profile
96
+ profile = Vindi::PaymentProfile.create(
97
+ customer_id: 12345,
98
+ payment_company_code: "visa",
99
+ holder_name: "JOHN DOE",
100
+ card_number: "4111111111111111",
101
+ card_expiration_date: "12/2030",
102
+ card_cvv: "123"
103
+ )
104
+
105
+ # Delete payment profile
106
+ Vindi::PaymentProfile.delete(profile.id)
107
+ ```
108
+
109
+ ### Subscriptions (`Vindi::Subscription`)
110
+
111
+ ```ruby
112
+ # Create subscription
113
+ subscription = Vindi::Subscription.create(
114
+ customer_id: customer.id,
115
+ plan_id: plan.id,
116
+ payment_method_code: "credit_card"
117
+ )
118
+
119
+ # Cancel/Delete subscription
120
+ Vindi::Subscription.delete(subscription.id)
121
+ ```
122
+
123
+ ### Charges (`Vindi::Charge`)
124
+
125
+ ```ruby
126
+ # List charges
127
+ charges = Vindi::Charge.list(status: "pending")
128
+
129
+ # Charge details
130
+ puts charges.first.amount
131
+ ```
132
+
133
+ ### Plans (`Vindi::Plan`)
134
+
135
+ ```ruby
136
+ # Create a plan
137
+ plan = Vindi::Plan.create(
138
+ name: "Premium Gold Plan",
139
+ code: "gold_premium",
140
+ interval: "months",
141
+ interval_count: 1
142
+ )
143
+
144
+ # List plans
145
+ plans = Vindi::Plan.list
146
+ ```
147
+
148
+ ### Products & Product Items (`Vindi::Product` & `Vindi::ProductItem`)
149
+
150
+ ```ruby
151
+ # Create a product
152
+ product = Vindi::Product.create(
153
+ name: "Hosting Service",
154
+ code: "hosting"
155
+ )
156
+
157
+ # Associate a product to a plan/subscription
158
+ product_item = Vindi::ProductItem.create(
159
+ product_id: product.id,
160
+ plan_id: plan.id
161
+ )
162
+ ```
163
+
164
+ ### Discounts (`Vindi::Discount`)
165
+
166
+ ```ruby
167
+ # Create/apply a discount
168
+ discount = Vindi::Discount.create(
169
+ amount: 15.00,
170
+ discount_type: "percentage",
171
+ percentage: 10
172
+ )
173
+ ```
174
+
175
+ ### Bills & Bill Items (`Vindi::Bill` & `Vindi::BillItem`)
176
+
177
+ ```ruby
178
+ # Create a bill manually
179
+ bill = Vindi::Bill.create(
180
+ customer_id: customer.id,
181
+ payment_method_code: "credit_card",
182
+ bill_items: [
183
+ { product_id: product.id, amount: 99.90 }
184
+ ]
185
+ )
186
+
187
+ # List bill items
188
+ items = Vindi::BillItem.list(bill_id: bill.id)
189
+ ```
190
+
191
+ ### Periods (`Vindi::Period`)
192
+
193
+ ```ruby
194
+ # List subscription periods
195
+ periods = Vindi::Period.list(subscription_id: subscription.id)
196
+ ```
197
+
198
+ ### Transactions (`Vindi::Transaction`)
199
+
200
+ ```ruby
201
+ # Create a manual transaction/charge capture
202
+ transaction = Vindi::Transaction.create(
203
+ charge_id: charge.id,
204
+ amount: 99.90
205
+ )
206
+
207
+ # List transactions
208
+ transactions = Vindi::Transaction.list
209
+ ```
210
+
211
+ ### Usages (`Vindi::Usage`)
212
+
213
+ ```ruby
214
+ # Report a metered usage for a subscription
215
+ usage = Vindi::Usage.create(
216
+ subscription_id: subscription.id,
217
+ quantity: 50,
218
+ description: "API Calls consumed"
219
+ )
220
+
221
+ # List usages
222
+ usages = Vindi::Usage.list(subscription_id: subscription.id)
223
+ ```
224
+
225
+ ### Invoices (`Vindi::Invoice`)
226
+
227
+ ```ruby
228
+ # List invoices
229
+ invoices = Vindi::Invoice.list(status: "issued")
230
+ ```
231
+
232
+ ### Issues (`Vindi::Issue`)
233
+
234
+ ```ruby
235
+ # Update an issue status (e.g. resolve a billing conflict)
236
+ issue = Vindi::Issue.update(issue_id, status: "resolved")
237
+ ```
238
+
239
+ ### Import/Export Batches (`Vindi::ImportBatch` & `Vindi::ExportBatch`)
240
+
241
+ ```ruby
242
+ # Start a new customer/subscription import batch
243
+ import_batch = Vindi::ImportBatch.create(
244
+ batch_type: "customer",
245
+ file_url: "https://example.com/import.csv"
246
+ )
247
+
248
+ # Request a data export batch
249
+ export_batch = Vindi::ExportBatch.create(
250
+ batch_type: "bill"
251
+ )
252
+ ```
253
+
254
+ ---
255
+
256
+ ## 4. Extensible Companion Gems
257
+
258
+ To keep the core SDK lightweight and dependency-free, Rails-specific features are distributed via companion gems.
259
+
260
+ ### 4.1 Backend Integrations ([`vindi-rails-integrations`](https://github.com/wesleyskap/vindi-rails-integrations))
261
+
262
+ Provides automatic ActiveRecord model synchronization, webhook controller endpoints, background processing jobs, and administration Rake tasks.
263
+
264
+ #### Installation
265
+ Add it to your Gemfile:
266
+ ```ruby
267
+ gem 'vindi-rails-integrations'
268
+ ```
269
+
270
+ #### Webhook Setup
271
+ Generate the webhook endpoint controller and processing job in your host application:
272
+ ```bash
273
+ bundle exec rails generate vindi:webhook
274
+ ```
275
+
276
+ ##### 1. Webhooks Controller (`app/controllers/vindi/webhooks_controller.rb`)
277
+ Validates incoming Vindi HTTP POST notifications by checking a secure token inside the query parameters.
278
+ - **Webhook Endpoint**: `POST /vindi/webhooks?token=YOUR_SECURE_TOKEN`
279
+ - **Controller Response**: Returns `{ "status": "received" }` with HTTP status `200 OK` on success, or `{ "error": "Unauthorized access token" }` (`401 Unauthorized`) / `{ "error": "Invalid payload" }` (`400 Bad Request`).
280
+
281
+ ##### 2. Asynchronous Webhook Job (`app/jobs/vindi/webhook_job.rb`)
282
+ Handles processing events in the background. It includes built-in safeguards like idempotency checking.
283
+
284
+ ##### 3. Modular Webhook Handlers
285
+ For cleaner architectures, separate processing of each event type into dedicated service files:
286
+ ```bash
287
+ bundle exec rails generate vindi:webhook_handler subscription_canceled
288
+ ```
289
+ This generates `app/services/vindi/webhooks/base_handler.rb` (base class) and `app/services/vindi/webhooks/subscription_canceled_handler.rb`. The generated `WebhookJob` will automatically discover and dispatch to these modular classes dynamically.
290
+
291
+ ###### Example Vindi Webhook Payload (Event)
292
+ ```json
293
+ {
294
+ "event": {
295
+ "id": 1928374,
296
+ "type": "bill_paid",
297
+ "created_at": "2026-06-10T15:00:00.000-03:00",
298
+ "data": {
299
+ "bill": {
300
+ "id": 887766,
301
+ "amount": "150.00",
302
+ "status": "paid",
303
+ "customer": {
304
+ "id": 112233,
305
+ "name": "Jane Doe",
306
+ "email": "jane.doe@example.com",
307
+ "code": "user_42"
308
+ }
309
+ }
310
+ }
311
+ }
312
+ }
313
+ ```
314
+
315
+ #### ActiveRecord Synchronization
316
+ Map any ActiveRecord model (e.g., `User`, `Account`) to synchronize automatically with Vindi Customers.
317
+
318
+ ##### 1. Generator Setup
319
+ Run the sync generator for your model:
320
+ ```bash
321
+ bundle exec rails generate vindi:sync User
322
+ ```
323
+ This generates a database migration to add `vindi_customer_id` (String) to your users table and configures the `Vindi::Synchronizable` concern.
324
+
325
+ ##### 2. Usage & Override Customization
326
+ Include `Vindi::Synchronizable` in your model and customize the attributes payload sent to Vindi:
327
+ ```ruby
328
+ class User < ApplicationRecord
329
+ include Vindi::Synchronizable
330
+
331
+ # Optional: Customize the attributes synced with Vindi
332
+ def vindi_customer_attributes
333
+ {
334
+ name: "#{first_name} #{last_name}",
335
+ email: email,
336
+ registry_code: cpf_or_cnpj, # If applicable
337
+ code: "user_#{id}"
338
+ }
339
+ end
340
+ end
341
+ ```
342
+
343
+ When a user record is committed on create or update, it triggers:
344
+ - **On Create**: Calls `Vindi::Customer.create` and populates `vindi_customer_id` automatically in your database.
345
+ - **On Update**: Automatically checks if `name` or `email` changed, and triggers `Vindi::Customer.update` to keep records in sync.
346
+
347
+ ##### 3. Resilient Transactional Outbox Sync (Optional)
348
+ To prevent network requests inside your main database transactions and ensure ultimate reliability:
349
+
350
+ 1. Generate outbox migration:
351
+ ```bash
352
+ bundle exec rails generate vindi:outbox
353
+ bundle exec rails db:migrate
354
+ ```
355
+ 2. Enable it in your config initializer:
356
+ ```ruby
357
+ Vindi.configure do |config|
358
+ config.use_outbox = true
359
+ end
360
+ ```
361
+ 3. When a record is created or updated, the synchronization is written to `vindi_pending_syncs` in-transaction, and `Vindi::ProcessPendingSyncsJob` is enqueued after the commit to process it in background.
362
+
363
+ #### Rake Tasks
364
+ The gem includes task commands for verification:
365
+
366
+ ##### 1. Auditing (`vindi:audit`)
367
+ Reconcile your local ActiveRecord model records against Vindi customers API:
368
+ ```bash
369
+ bundle exec rake vindi:audit model=User
370
+ ```
371
+ **Example Audit Output Log:**
372
+ ```text
373
+ Analyzing User database...
374
+ [Audit] Checking User ID: 42 (Vindi ID: 112233) - Match found.
375
+ [Audit] Checking User ID: 43 (Vindi ID: nil) - Missing in Vindi!
376
+ [Audit Warning] User ID 43 created in Vindi with customer ID 112234.
377
+ Reconciliation complete. 1 missing records synchronized.
378
+ ```
379
+
380
+ ##### 2. Local Webhook Test Simulator (`vindi:test_webhook`)
381
+ Simulate webhook event POST requests to your Rails environment locally:
382
+ ```bash
383
+ bundle exec rake vindi:test_webhook event=bill_paid url=http://localhost:3000/vindi/webhooks token=YOUR_SECURE_TOKEN
384
+ ```
385
+ **Example Request Sent:**
386
+ ```text
387
+ Sending POST to http://localhost:3000/vindi/webhooks?token=YOUR_SECURE_TOKEN...
388
+ Payload: {"event":{"id":9999,"type":"bill_paid","data":{...}}}
389
+ Response Code: 200 OK
390
+ Response Body: {"status":"received"}
391
+ ```
392
+
393
+ ##### 3. Diagnostics and Connectivity Check (`vindi:status`)
394
+ Verify your configured API environments, credentials safely (masked), and run connectivity health checks:
395
+ ```bash
396
+ bundle exec rake vindi:status
397
+ ```
398
+ **Example Status Report:**
399
+ ```text
400
+ === Vindi Integration Status ===
401
+ Environment: Sandbox
402
+ API URL: https://sandbox-gp.vindi.com.br/api/v1
403
+ API Key: *****2345
404
+ Webhook: *****_999
405
+ --------------------------------
406
+ Connectivity: SUCCESS
407
+ ================================
408
+ ```
409
+
410
+ ---
411
+
412
+ ### 4.2 Frontend Engines ([`vindi-rails-engines`](https://github.com/wesleyskap/vindi-rails-engines))
413
+
414
+ Mountable UI resources providing PCI-compliant client side tokenization components.
415
+
416
+ #### Installation
417
+ Add it to your Gemfile:
418
+ ```ruby
419
+ gem 'vindi-rails-engines'
420
+ ```
421
+
422
+ #### Checkout UI Setup
423
+ Initialize the tokenization view templates and stimulus controllers:
424
+ ```bash
425
+ bundle exec rails generate vindi:checkout
426
+ ```
427
+
428
+ ##### 1. Stimulus JS Controller (`app/javascript/controllers/vindi_checkout_controller.js`)
429
+ Intercepts the form submission, serializes card inputs, interacts with Vindi's public tokenization client, and sets the returned token into a hidden field:
430
+ ```javascript
431
+ // Connects to data-controller="vindi-checkout"
432
+ import { Controller } from "@hotwired/stimulus"
433
+
434
+ export default class extends Controller {
435
+ static targets = [ "publicKey", "holderName", "cardNumber", "expiry", "cvv", "tokenInput" ]
436
+
437
+ tokenizeCard(event) {
438
+ event.preventDefault()
439
+ const vindi = new Vindi(this.publicKeyTarget.value)
440
+
441
+ vindi.createToken({
442
+ holder_name: this.holderNameTarget.value,
443
+ card_number: this.cardNumberTarget.value.replace(/\s+/g, ''),
444
+ card_expiration: this.expiryTarget.value,
445
+ card_cvv: this.cvvTarget.value
446
+ }).then((response) => {
447
+ // response: { token: "tok_abc123XYZ", created_at: "2026-06-10..." }
448
+ this.tokenInputTarget.value = response.token
449
+ this.element.submit()
450
+ }).catch((error) => {
451
+ alert("Tokenization Error: " + error.message)
452
+ })
453
+ }
454
+ }
455
+ ```
456
+
457
+ ##### 2. Vindi Public Key Response Example
458
+ When calling `vindi.createToken(...)` with card credentials, the Javascript SDK returns the payment profile token:
459
+ ```json
460
+ {
461
+ "token": "tok_3278918239abc",
462
+ "created_at": "2026-06-10T16:50:00.000-03:00"
463
+ }
464
+ ```
465
+
466
+ Use the generated `payment_profile_token` in your backend controllers to safely set up new subscriptions or charge invoices without storing credit card details locally:
467
+ ```ruby
468
+ # Example Controller endpoint processing checkout token
469
+ def charge
470
+ Vindi::Charge.create(
471
+ payment_method_code: "credit_card",
472
+ payment_profile: {
473
+ token: params[:payment_profile_token]
474
+ },
475
+ amount: "150.00",
476
+ customer_id: current_user.vindi_customer_id
477
+ )
478
+ end
479
+ ```