Onboarding Self-Check Answers
Reference answers for the self-check questions in the Onboarding Guide. Use these to verify your understanding after completing each phase.
Phase 1: Foundations
Section titled “Phase 1: Foundations”What is the business value of integrations for advisors?
Section titled “What is the business value of integrations for advisors?”Financial advisors’ clients (Households) typically hold assets across multiple financial institutions — bank deposits, brokerage accounts, insurance policies. Without integrations, advisors would manually enter all client data into RightCapital, a time-consuming and error-prone process.
Integration provides three core values:
- Rapid onboarding — Advisors link vendor accounts and import client data in minutes instead of hours
- Automated sync — Nightly Sync updates holdings daily without manual intervention
- Data accuracy — Data flows directly from financial institutions, eliminating manual entry errors
RightCapital currently integrates with 46+ vendors (27 API-based, 19 file-based), covering custodians, portfolio management platforms, CRMs, data aggregators, and insurance providers.
What are the main types of integrations (Data, SSO, CRM)?
Section titled “What are the main types of integrations (Data, SSO, CRM)?”| Type | Purpose | Examples |
|---|---|---|
| Data Integration | Sync financial data: accounts, positions/holdings, insurance policies | Schwab API, Fidelity (file), Orion, Addepar |
| SSO (Single Sign-On) | Allow advisors to jump from vendor portals into RightCapital without re-authenticating | Schwab SSO, Fidelity SSO via SAML 2.0 |
| CRM Integration | Import household/contact information from CRM systems | Wealthbox, Redtail, Smart Office |
Additionally, the team manages Morningstar Security Master — the securities pricing and fundamentals data pipeline — which does not fit neatly into the above categories but falls under Integration Team’s responsibilities.
Data Integration is the core workload, accounting for the majority of development and operational effort.
What is the difference between File-based and API-based integrations?
Section titled “What is the difference between File-based and API-based integrations?”| Dimension | File-based | API-based |
|---|---|---|
| Data source | Vendor pushes files (CSV/Excel) via SFTP | RightCapital calls vendor REST/SOAP APIs |
| Data flow | Vendor SFTP → Collector → S3 → Retail API → DB | Retail API → Vendor API → DB |
| Authentication | None (files transferred via SFTP) | OAuth 2.0 / JWT / API Key / SOAP / mTLS |
| Advisor setup | Passive: Support configures Rep Code in Admin Center | Active: Advisor self-service OAuth authorization |
| Data freshness | Depends on vendor push schedule (usually daily) | Near real-time via on-demand or webhook |
| Complexity | Medium (parsing, field mapping) | High (state machine, error recovery, token refresh) |
| Count | ~19 vendors | ~27 vendors |
| Examples | Fidelity, Pershing, Schwab (file), SEI | Orion, Schwab API, Addepar, Wealthbox |
Some vendors support both modes (e.g., Schwab, LPL, Betterment).
Phase 2: Collector
Section titled “Phase 2: Collector”What is the purpose of Collector?
Section titled “What is the purpose of Collector?”Collector is a standalone service (repo: integrations/collector) that downloads data files from vendor SFTP servers, processes them, and uploads them to S3 for Retail API consumption.
It is the data ingestion entry point for all file-based integrations. Without Collector, Retail API would need to connect to each vendor’s SFTP individually.
Data flow: Vendor SFTP → Collector → S3 → Retail API
How does Collector communicate with Vendors (SFTP, etc.)?
Section titled “How does Collector communicate with Vendors (SFTP, etc.)?”Collector connects to vendor SFTP servers using per-vendor configuration:
- Connection: SFTP protocol with vendor-specific host, port, and credentials (password or SSH key)
- File selection: Pattern matching rules to identify target files
- Download strategy: Date/timestamp filtering to download only new files
Note: Some vendors push files to RightCapital’s self-hosted SFTP (e.g., Pershing), rather than hosting their own. Collector handles both directions.
What are the 4 processing stages? What does each stage do?
Section titled “What are the 4 processing stages? What does each stage do?”| Stage | Responsibility | Input | Output |
|---|---|---|---|
| 1. Downloader | Connect to vendor SFTP and download files to local temp directory | Files on vendor SFTP | Raw files in local temp directory |
| 2. Processor | Decompress (ZIP/GZ), validate format, organize by type | Compressed files in temp | Clean, validated files |
| 3. Uploader | Upload processed files to S3 in organized directory structure, update timestamp.txt, clean up temp | Processed files | Files on S3 at vendor/{rep_code}/{date}/ |
| 4. Finalizer | Create/update LATEST symlinks pointing to the most recent data files | Dated files on S3 | LATEST_accounts.csv etc. |
Pipeline: Vendor SFTP → [Downloader] → temp/ → [Processor] → clean files → [Uploader] → S3 → [Finalizer] → LATEST links
What is the final output (LATEST files on S3)?
Section titled “What is the final output (LATEST files on S3)?”LATEST-prefixed files on S3 that always point to the most recent data for each vendor/rep-code combination:
s3://bucket/vendor-name/├── rep_code_1/│ ├── 2024-01-15/│ │ ├── accounts.csv│ │ ├── positions.csv│ │ └── securities.csv│ ├── 2024-01-16/│ │ └── ...│ ├── LATEST_accounts.csv ← Retail API reads this│ ├── LATEST_positions.csv│ └── LATEST_securities.csv└── timestamp.txtRetail API always reads LATEST files without needing to know which date directory contains the newest data. This decouples the file schedule from the sync schedule.
Phase 3: API-based Integration
Section titled “Phase 3: API-based Integration”How do we establish connection with Vendors (OAuth, API key, etc.)?
Section titled “How do we establish connection with Vendors (OAuth, API key, etc.)?”Supported authentication methods:
| Auth Method | Description | Vendors |
|---|---|---|
| OAuth 2.0 | Most common. Advisor authorizes in browser → access_token + refresh_token stored in integrations.credentials | Schwab API, Orion, Addepar, LPL |
| OAuth 2.0 + PKCE | Enhanced security OAuth | Schwab API |
| JWT (RS512) | RSA private key signs JWT tokens | Yodlee (separate system) |
| API Key | Static key assigned by vendor | Wealthbox, Redtail |
| mTLS | Mutual TLS certificate authentication | Commonwealth |
| WS-Security/SOAP | XML-based SOAP auth | Tamarac |
| HMAC | Hash-based message signing | Wealth Access |
| RSA | RSA encrypted authentication | DST |
| Certificate-based | Client certificate | Albridge |
Typical OAuth 2.0 flow (implemented in OauthConnector):
- Advisor clicks “Connect” → RC redirects to vendor’s authorize URL
- Advisor authenticates and grants permission on vendor’s page
- Vendor redirects back to RC with authorization code
- RC exchanges code for access_token + refresh_token
- Tokens encrypted and stored in
integrations.credentials
Token refresh is handled by ThreadSafeRefreshAccessToken plugin for concurrent-safe token renewal.
What is the Connector/Integrator/Request architecture?
Section titled “What is the Connector/Integrator/Request architecture?”Three-layer architecture built on the Saloon PHP library:
| Component | Responsibility | Analogy |
|---|---|---|
| Connector | Transport layer — manages vendor API connection: base URL, auth headers, rate limiting, logging | HTTP Client |
| Integrator | Orchestration layer — implements sync logic: calls Connector, transforms data, persists to database | Service / Use Case |
| Request | Endpoint definition — each specific API call: HTTP method, path, query params, error handling | API Endpoint Definition |
Per-vendor code structure:
app/Integrations/[Vendor]/├── Connector.php ← Transport + authentication├── Integrator.php ← Sync orchestration├── Requests/ ← Individual API calls│ ├── GetAccountsRequest.php│ └── GetPositionsRequest.php├── Models/ ← Vendor-specific data models└── Importer.php ← Household import logicCall chain: Controller → Integrator → Connector → Request → Vendor API
How does API integration fetch Vendor data?
Section titled “How does API integration fetch Vendor data?”Using Nightly Sync as example:
- Scheduler triggers sync command (after US market close)
- Command queries all active integration mappings, dispatches a queue job per mapping
- Worker processes each job:
- Loads OAuth credentials from
integrationstable - Gets vendor’s Sync handler via
Integration::getSynchronizer() - Sync handler instantiates Connector (with access_token)
- Sends Requests to vendor API endpoints
- Receives account/position/insurance data
- Loads OAuth credentials from
- Integrator transforms vendor response models into RC internal models
- Persist creates/updates accounts, positions in database
For manual sync: Advisor clicks “Link Account” → same Integrator logic runs on demand.
What data do we typically fetch (households, accounts, positions)?
Section titled “What data do we typically fetch (households, accounts, positions)?”| Data Type | Description | mappable_type |
|---|---|---|
| Households | Client family unit | HOUSEHOLD |
| Accounts | Financial accounts (investment, bank, loan) | ACCOUNT |
| Positions/Holdings | Securities held (ticker, quantity, market value) | Stored in positions table, linked to Account |
| Insurance | Policies (life, disability, LTC) | INSURANCE |
| Persons | Family members | PERSON |
| Contacts | CRM contacts | CONTACT |
| Notes/Tasks | CRM notes and tasks | NOTE / TASK |
Account and Insurance are core data integration types — IntegrationMapping::isDataIntegrationMapping() returns true only for these two.
How is Vendor data linked to RightCapital households?
Section titled “How is Vendor data linked to RightCapital households?”Through the integration_mappings table, which forms a hierarchical tree:
Integration (Advisor ↔ Vendor connection)└── IntegrationMapping (parent_id=NULL, mappable_type=HOUSEHOLD) ← root ├── IntegrationMapping (mappable_type=ACCOUNT) ← child ├── IntegrationMapping (mappable_type=ACCOUNT) └── IntegrationMapping (mappable_type=INSURANCE)Link Account flow:
- Advisor opens Client Portal → Profile → Net Worth → Link Account
- Selects a connected vendor
- System calls vendor API via Integrator, displays available households/accounts
- Advisor selects accounts to import
- System creates
integration_mappingsrecords:- Root mapping:
mappable_type=HOUSEHOLD,parent_id=NULL, linked to RC Household - Child mappings:
mappable_type=ACCOUNT/INSURANCE,parent_id→ root mapping - Each record’s
referencefield stores the vendor’s entity ID
- Root mapping:
Key rule: Only root mappings (parent_id=NULL) can trigger synchronization. Child mappings inherit sync from their parent.
What does IntegrationConfigController do?
Section titled “What does IntegrationConfigController do?”Manages integration lifecycle operations:
- Create new integration (
CREATE_INTEGRATIONscenario) — OAuth flow initiation - Configure vendor connection settings
- Disconnect integration (soft delete)
API endpoints:
POST /advisors/{advisor}/integrations— Create integrationDELETE /advisors/{advisor}/integrations/{integration}— Delete integration
What does IntegrationImportController do?
Section titled “What does IntegrationImportController do?”Handles bulk import of household and client data, primarily for CRM integrations:
IMPORT_HOUSEHOLD— Batch import vendor households into RCIMPORT_CLIENTS— Import client/contact dataLIST_TAGS— Retrieve CRM tags/categories for filtering
This is distinct from Data Integration (account/position sync). Import focuses on CRM data ingestion from vendors like Wealthbox, Redtail, and Smart Office.
Phase 4: File-based Integration
Section titled “Phase 4: File-based Integration”Where does the Vendor data come from (S3 via Collector)?
Section titled “Where does the Vendor data come from (S3 via Collector)?”File-based data comes from LATEST files on S3, uploaded by Collector from vendor SFTP servers.
Full chain:
Vendor → SFTP push → Collector downloads → Process (decompress/validate) → Upload to S3 → LATEST links ↓ Retail API reads LATEST files → Parse → Save to databaseRetail API uses the integrations-file-based package (packages/libs/integrations-file-based) to parse these files.
What data is typically in the files (accounts, positions, securities)?
Section titled “What data is typically in the files (accounts, positions, securities)?”| File Type | Content | Typical Format | Purpose |
|---|---|---|---|
| Accounts | Account metadata (number, type, name, status) | CSV | Create/update account records |
| Positions | Holdings (security, quantity, market value) | CSV | Update portfolio positions |
| Securities | Security master data (CUSIP, ticker, name) | CSV | Security matching |
| Tax Lots | Cost basis, purchase date | CSV | Tax lot tracking |
| Transactions | Trade history | CSV | Transaction records |
Format variations across vendors include different delimiters (comma, tab, pipe), column names, encodings (UTF-8 vs Latin-1), and date formats. Each vendor has a custom Parser to handle these differences.
How is file data linked to RightCapital households?
Section titled “How is file data linked to RightCapital households?”Through Rep Code — the advisor’s unique identifier in the vendor’s system.
Flow:
- Support creates
integrationsrecord in Admin Center with advisor’s Rep Code in thereferencefield - During sync, Retail API reads LATEST files from the S3 directory matching that Rep Code
- Parser extracts available accounts from the file
- Advisor uses Link Account in Client Portal to select accounts for import
- System creates
integration_mappingschild records linking to the appropriate Household
Key difference from API-based: File-based mappings require Support to manually configure the Rep Code, while API-based mappings are advisor self-service via OAuth.
Phase 5: Sync Process
Section titled “Phase 5: Sync Process”What is Sync in one sentence?
Section titled “What is Sync in one sentence?”Nightly Sync is a scheduled batch job that runs daily after US market close, fetching the latest data from all connected vendors and updating RightCapital’s database.
What data gets synced?
Section titled “What data gets synced?”| Data Type | Source | Operations |
|---|---|---|
| Accounts | Vendor | Create / Update / Mark stale |
| Positions | Vendor | Full replacement with latest holdings |
| Holdings | Vendor | Update quantity and market value |
| Prices | Morningstar | Update security prices |
| Insurance | Vendor (where supported) | Update premium and benefit amounts |
What is a Holding?
Section titled “What is a Holding?”A Holding (stored in the positions table) represents a specific securities position within an account.
Each holding record contains:
security_id— Which security (matched via Morningstar Security Master)quantity— Number of shares/units heldcost_basis— Original purchase costreference— Vendor’s position IDinvestment_account_id— The investment account that holds this position
Example: A client holds 100 shares of AAPL in their Schwab account with a cost basis of $15,000 — this is one Holding.
How are Holdings synchronized?
Section titled “How are Holdings synchronized?”API-based sync:
- Load OAuth credentials for the mapping’s integration
- Call vendor API to get current positions list
- Compare with existing positions in database:
- New positions → INSERT
- Changed quantity/value → UPDATE
- No longer returned by vendor → Mark stale or delete
- Update
integration_mappings.last_completed_at
File-based sync:
- Read LATEST positions file from S3
- Parse CSV, filter by Rep Code
- Match securities (via CUSIP/ticker → Morningstar Security Master)
- Same INSERT/UPDATE/DELETE logic
- Update sync status
Holdings are typically full-replaced (not incrementally updated) to ensure data consistency.
What are the different types of Holdings?
Section titled “What are the different types of Holdings?”By account type:
| Account Type | Holding Characteristics |
|---|---|
| Investment Account | Securities positions (stocks, bonds, mutual funds, ETFs) |
| Retirement Account (401k, IRA) | Retirement investment positions |
| Bank Account | Usually only cash_balance, no securities positions |
| Loan Account | Liability, no holdings concept |
By data source: The AccountSource enum (45 values) tracks origin — YODLEE, SCHWAB, FIDELITY, TWEAK (manual entry), and 41 other vendor-specific sources.
Phase 6: Database Schema
Section titled “Phase 6: Database Schema”What does a row in integrations represent?
Section titled “What does a row in integrations represent?”A row in integrations represents one advisor’s connection to one vendor.
Key fields:
advisor_id— FK → advisors tabletype— IntegrationType enum (47 vendor types)reference— Vendor-side identifier (e.g., Rep Code for file-based)credentials— Encrypted JSON containing OAuth tokens or API keysfailed_since/failed_biz_days— Failure tracking; auto-disables after threshold
Constraint: Each advisor can have at most one active integration per vendor type.
What is the reference field in integrations?
Section titled “What is the reference field in integrations?”The reference field stores the advisor’s identifier in the vendor’s system. Its meaning varies by integration type:
- File-based: Rep Code — used to locate the correct files on S3 (
s3://bucket/vendor/{rep_code}/) - API-based: May be empty (identity established via OAuth token) or store a vendor-assigned ID
What is the difference between credentials and reference?
Section titled “What is the difference between credentials and reference?”| Field | Purpose | Content |
|---|---|---|
reference | Identity — who this advisor is at the vendor | Rep Code, vendor-assigned ID |
credentials | Authentication — how to access vendor API | OAuth tokens, API keys, JWT secrets |
Analogy: reference is your employee badge number; credentials is your login password.
credentials is encrypted JSON. Typical content:
{ "access_token": "eyJ...", "refresh_token": "abc123...", "expires_at": "2024-01-15T10:00:00Z"}What does integration_mappings represent?
Section titled “What does integration_mappings represent?”The integration_mappings table maps vendor external entities to RightCapital internal objects.
What is the reference field in integration_mappings?
Section titled “What is the reference field in integration_mappings?”The reference field stores the vendor’s entity ID — the unique identifier for this specific entity (account, household, etc.) in the vendor’s system. Used for deduplication and re-sync.
What does parent_id being null vs non-null mean?
Section titled “What does parent_id being null vs non-null mean?”parent_id = NULL→ Root mapping: Represents a household-level link. Only root mappings can trigger synchronization.parent_id ≠ NULL→ Child mapping: Represents an account, insurance, or other entity nested under a household. Inherits sync behavior from its parent.
Tree structure example:
Integration (Schwab API, advisor_id=123)└── Mapping #1 (HOUSEHOLD, parent_id=NULL, reference="vendor_hh_001") ├── Mapping #2 (ACCOUNT, parent_id=1, reference="vendor_acct_001") ├── Mapping #3 (ACCOUNT, parent_id=1, reference="vendor_acct_002") └── Mapping #4 (INSURANCE, parent_id=1, reference="vendor_ins_001")What are the different mappable_type values and their meanings?
Section titled “What are the different mappable_type values and their meanings?”mappable_type | Meaning | Notes |
|---|---|---|
HOUSEHOLD | Client family unit | Root node, typically parent_id=NULL |
ACCOUNT | Financial account | Bank, investment, loan (core data type) |
INSURANCE | Insurance policy | Life, disability, LTC (core data type) |
PERSON | Family member | Links to persons table |
CONTACT | CRM contact | From CRM integrations |
TARGET_CATEGORY_MIX | Target asset allocation | Investment portfolio target |
NOTE | CRM note | From CRM integrations |
TASK | CRM task | From CRM integrations |
ACCOUNT and INSURANCE are the two data integration types — IntegrationMapping::isDataIntegrationMapping() returns true only for these.
Phase 7: SSO
Section titled “Phase 7: SSO”What is a Service Provider (SP)?
Section titled “What is a Service Provider (SP)?”The SP (Service Provider) is the system that receives authentication assertions and provides the service. In Integration Team’s SSO implementations, RightCapital is the SP — we receive SAML assertions from vendors, validate them, and create user sessions.
What is an Identity Provider (IdP)?
Section titled “What is an Identity Provider (IdP)?”The IdP (Identity Provider) is the system that authenticates users and issues identity information. In IdP-initiated SSO, the vendor is the IdP (e.g., Schwab, Fidelity) — they have already verified the advisor’s identity and transmit it to RC via SAML assertion.
What is IdP-initiated SSO flow?
Section titled “What is IdP-initiated SSO flow?”The most common SSO pattern. Advisor starts from the vendor’s system and lands in RightCapital:
- Advisor logs into vendor portal
- Clicks “Open in RightCapital” link
- Vendor generates a SAML Assertion (signed XML document containing user identity)
- Vendor POSTs the SAML Assertion to RightCapital’s SSO endpoint
- RightCapital validates signature and assertion
- Looks up the corresponding Advisor via identifier in the assertion (email/advisor ID)
- Creates session, redirects to application
What is SP-initiated SSO flow?
Section titled “What is SP-initiated SSO flow?”Advisor starts from RightCapital and authenticates through the vendor:
- Advisor clicks “Login with [Vendor]” on RightCapital
- RC redirects to vendor’s login page
- Advisor authenticates at vendor
- Vendor POSTs SAML Assertion back to RC
- RC validates and creates session
Less commonly used than IdP-initiated.
How is a SAML Response validated? What fields are validated?
Section titled “How is a SAML Response validated? What fields are validated?”| Validation | What is Checked | Common Failure Cause |
|---|---|---|
| Signature | XML digital signature verified using vendor’s public X.509 certificate | Certificate expired or rotated without notification |
| Issuer | Must match expected vendor identifier | Configuration mismatch |
| Audience | Must match RC’s SP Entity ID | Configuration mismatch |
| NotBefore / NotOnOrAfter | Assertion must be within valid time window | Server clock skew |
| Subject | Contains user identifier (email or advisor ID) | User not found in RC |
| Conditions | Additional business rule checks | Vendor-specific constraints |
Common issues:
- User Not Found: Identifier in SAML does not match any RC advisor record
- Invalid Signature: Vendor rotated their certificate without notifying RC
- Expired Assertion: Clock drift between vendor and RC servers exceeds tolerance
Code location: api/app/Http/Controllers/Sso/ — each vendor has its own SSO controller.
Appendix: Yodlee Special Architecture
Section titled “Appendix: Yodlee Special Architecture”Yodlee is the most complex integration and operates as a completely separate system from the standard Integration architecture:
| Aspect | Standard Integration | Yodlee |
|---|---|---|
| Initiator | Advisor configures connection | End-user (client) links their bank accounts |
| Connection level | Advisor ↔ Vendor | Client ↔ Financial Institution |
| Storage | integrations + integration_mappings | Dedicated yodlee_providers + yodlee_provider_accounts + account_yodlees tables |
| IntegrationType | Listed in enum | Not in enum (separate system) |
| Authentication | OAuth 2.0 (Saloon) | JWT RS512 (direct Guzzle) |
| Sync mode | Nightly Sync auto-trigger | Passive refresh (user-triggered) |
Yodlee uses 30+ status codes (additional_status_code in account_yodlees):
| Action Category | Meaning | Status Codes |
|---|---|---|
done | Data retrieved successfully | 4, 5 |
get_refresh | Poll Yodlee for status update | 1, 2, 3 |
put | User must re-authenticate via FastLink Edit | 11, 12, 26-28, 30 |
manual_refresh | User must provide MFA via FastLink Refresh | 9, 14 |
fail | Unrecoverable error | Various others |
See Yodlee vendor documentation for full details including test account credentials and FastLink widget modes.
Related Documentation
Section titled “Related Documentation”- Onboarding Guide — Learning path with tasks and resources
- Architecture — System architecture overview
- Data Models — Database schema details
- API-based Patterns — Connector/Integrator patterns
- File-based Patterns — Parser/Mapper design
- Vendor Catalog — All 46+ vendor integrations