Skip to main content
This guide explains how to use the Provider generators, which make it easy to add new integrations with either global or per-family scope credentials.

Quick start

Two generators available

Quick examples

Global vs per-family: Which to use?

Use provider:global when:

  • ✅ One set of credentials serves the entire application
  • ✅ Provider charges per-application (not per-customer)
  • ✅ You control the API account (self-hosted or managed mode)
  • ✅ All families can safely share access
  • ✅ Examples: Plaid, OpenAI, exchange rate services

Use provider:family when:

  • ✅ Each family/customer needs their own credentials
  • ✅ Provider charges per-customer
  • ✅ Users bring their own API keys
  • ✅ Data isolation required between families
  • ✅ Examples: Lunch Flow, SimpleFIN, YNAB, personal bank APIs

Provider:family generator

Usage

Reserved field names

The generator rejects field names that are already defined on the items table. Passing a reserved name raises a Thor::Error at generation time rather than producing broken migrations or inconsistent models. Reserved names include: family_id, institution_id, institution_name, institution_domain, institution_url, institution_color, status, scheduled_for_deletion, pending_account_setup, sync_start_date, raw_payload, raw_institution_payload. Note that family (without _id) is not reserved — the migration writes t.references :family, which creates family_id, so a field named family is not a collision.

Example: Adding a MyBank provider

What gets generated

This single command generates:
  • ✅ Migration for my_bank_items and my_bank_accounts tables with credential fields
  • ✅ Models: MyBankItem, MyBankAccount, and MyBankItem::Provided concern
  • ✅ Adapter class for provider integration
  • ✅ Simple manual panel view for provider settings
  • ✅ Controller with CRUD actions and Turbo Stream support
  • ✅ Routes
  • ✅ Updates to settings controller and view

Key characteristics

  • Credentials: Stored in my_bank_items table (encrypted)
  • Isolation: Each family has completely separate credentials
  • UI: Manual form panel at /settings/providers
  • Configuration: Per-family, self-service

Provider:global generator

Usage

Example: Adding a Plaid provider

What gets generated

This single command generates:
  • ✅ Migration for plaid_items and plaid_accounts tables without credential fields
  • ✅ Models: PlaidItem, PlaidAccount, and PlaidItem::Provided concern
  • ✅ Adapter with Provider::Configurable
  • ❌ No controller (credentials managed globally)
  • ❌ No view (UI auto-generated by Provider::Configurable)
  • ❌ No routes (no CRUD needed)

Key characteristics

  • Credentials: Stored in settings table (global, not encrypted)
  • Sharing: All families use the same credentials
  • UI: Auto-generated at /settings/providers (self-hosted mode only)
  • Configuration: ENV variables or admin settings

Important notes

  • Credentials are shared by all families - use only for trusted services
  • Only available in self-hosted mode (admin-only access)
  • No per-family credential management needed
  • Simpler implementation (fewer files generated)

Comparison table

What gets generated (detailed)

1. Migration

File: db/migrate/xxx_create_my_bank_tables_and_accounts.rb Creates two complete tables with all necessary fields:

2. Models

File: app/models/my_bank_item.rb The item model stores per-family connection credentials:
File: app/models/my_bank_account.rb The account model stores individual account data from the provider:
File: app/models/my_bank_item/provided.rb The Provided concern connects the item to its provider SDK:

3. Adapter

File: app/models/provider/my_bank_adapter.rb

Customization

After generation, you’ll typically want to customize three files:

1. Customize the adapter

Implement the build_provider method in app/models/provider/my_bank_adapter.rb:

2. Update the model

Add custom validations, helper methods, and business logic in app/models/my_bank_item.rb:

3. Customize the view

Edit the generated panel view app/views/settings/providers/_my_bank_panel.html.erb to add custom content.

Examples

Example 1: Simple API key provider

Result: Basic provider with just an API key field.

Example 2: OAuth provider

Then customize the adapter to implement OAuth flow.

Example 3: Complex provider

Then add custom validations and logic in the model:

Tips & best practices

1. Always run migrations

2. Test in console

3. Use proper encryption

Always check that encryption is set up:

4. Implement proper error handling

5. Add integration tests

Troubleshooting

Reserved field name error

If the generator raises Thor::Error: '<field>' is a reserved field name, remove that field from the command. The items table already defines it, so declaring it again would produce a duplicate migration column and inconsistent model code. See Reserved field names for the full list.

Panel not showing

  1. Check that the provider is excluded in settings/providers_controller.rb
  2. Check that the instance variable is set
  3. Check that the section exists in settings/providers/show.html.erb

Form not submitting

  1. Check routes are properly added: rails routes | grep my_bank
  2. Check turbo frame ID matches between view and controller

Encryption not working

  1. Check credentials are configured: rails credentials:edit
  2. Add encryption keys if missing
  3. Or use environment variables

Reserved field name error

The generator rejects field names that collide with columns already defined on the items table. If you see a Thor::Error like:
Drop the named field from your command — the standard column covers it. Reserved names include: institution_id, institution_name, institution_domain, institution_url, institution_color, status, family_id, scheduled_for_deletion, pending_account_setup, sync_start_date, raw_payload, raw_institution_payload. Note that family (without _id) is not reserved — t.references :family creates family_id, so a field named family does not collide.

NoMethodError: undefined method 'syncable' during family sync

If a freshly generated provider raises this error and takes down the nightly family sync, the generated item model is missing the syncable scope. Add it manually:
Providers generated after the fix include this scope automatically.

Advanced: Creating a provider SDK

For complex providers, consider creating a separate SDK class:

Summary

The per-family Provider Rails generator system provides:
  • Fast development - Generate in seconds, not hours
  • Consistency - All providers follow the same pattern
  • Maintainability - Clear structure and conventions
  • Flexibility - Easy to customize for complex needs
  • Security - Built-in encryption for sensitive fields
  • Documentation - Self-documenting with descriptions
Use it whenever you need to add a new provider where each family needs their own credentials.