Skip to content

File-based Vendor Specifics

This document covers format specifications, common issues, and troubleshooting information for file-based integrations.

VendorFile FormatHost TypeDeveloper
AllianzCSV/ExcelSelf-hostedYan Hu
AltruistCSVSelf-hostedYan Hu
ApexCSVSelf-hostedTingsong Xu
BettermentCSVSelf-hostedKewei Yan
FidelityCSVVendor-hostedQianwei Hao
First ClearingCSVVendor-hostedQianwei Hao
FlourishCSVSelf-hostedTingsong Xu
Folio InvestingCSVSelf-hostedQianwei Hao
Interactive BrokersCSVSelf-hostedWinston Li
JacksonCSV/ExcelSelf-hostedWinston Li
LPLCSVVendor-hostedQianwei Hao
My529CSVSelf-hostedKewei Yan
Pacific LifeCSVSelf-hostedWinston Li
PershingExcel (.xlsx)Vendor-hostedKewei Yan
Raymond JamesCSVSelf-hostedWinston Li
RBCCSVSelf-hostedYan Hu
Schwab (File)CSVSelf-hostedYan Hu
SEICSVSelf-hostedWinston Li
Trust AmericaCSVSelf-hostedKewei Yan
IssueSymptomSolution
UTF-8 BOMExtra characters at file startStrip BOM before parsing
Latin-1 / ISO-8859-1Special characters corruptedConvert to UTF-8
Windows-1252Smart quotes brokenConvert to UTF-8
// Handle encoding detection and conversion
$content = file_get_contents($filePath);
// Detect encoding
$encoding = mb_detect_encoding($content, ['UTF-8', 'ISO-8859-1', 'Windows-1252']);
// Convert to UTF-8
if ($encoding !== 'UTF-8') {
$content = mb_convert_encoding($content, 'UTF-8', $encoding);
}
// Strip BOM if present
$content = preg_replace('/^\xEF\xBB\xBF/', '', $content);
VendorDate FormatExample
FidelityMM/DD/YYYY12/31/2024
PershingYYYY-MM-DD2024-12-31
SchwabM/D/YYYY1/5/2024
LPLDD-MMM-YYYY31-Dec-2024
// Flexible date parsing
private function parseDate(string $value): ?Carbon
{
$formats = [
'm/d/Y', // 12/31/2024
'n/j/Y', // 1/5/2024
'Y-m-d', // 2024-12-31
'd-M-Y', // 31-Dec-2024
'm-d-Y', // 12-31-2024
];
foreach ($formats as $format) {
try {
return Carbon::createFromFormat($format, trim($value));
} catch (Exception) {
continue;
}
}
return null;
}
IssueExampleClean Value
Currency symbol$1,234.561234.56
Thousands separator1,234,567.891234567.89
Parentheses for negative(1,234.56)-1234.56
Space separator1 234 567.891234567.89
private function parseAmount(string $value): float
{
$cleaned = $value;
// Handle parentheses for negative
if (preg_match('/^\((.*)\)$/', $cleaned, $matches)) {
$cleaned = '-' . $matches[1];
}
// Remove currency symbols and separators
$cleaned = preg_replace('/[^0-9.\-]/', '', $cleaned);
return (float) $cleaned;
}
VendorEmpty Representation
FidelityEmpty string ""
PershingNULL string
SchwabN/A string
LPL- dash
private function normalizeNull(mixed $value): mixed
{
if (is_string($value)) {
$normalized = strtoupper(trim($value));
if (in_array($normalized, ['', 'NULL', 'N/A', 'NA', '-', '--'])) {
return null;
}
}
return $value;
}

File Type: CSV Encoding: UTF-8 Date Format: MM/DD/YYYY

Required Columns:

Column NameDescriptionExample
Account NumberUnique account ID123456789
Account NameDisplay nameJohn’s IRA
Account TypeAccount classificationROTH IRA
Total ValueCurrent balance$45,678.90
As of DateData date12/31/2024

Holdings Columns (if present):

Column NameDescription
SymbolTicker symbol
QuantityNumber of shares
PricePrice per share
ValueTotal position value

Common Issues:

  • Multi-sheet files need consolidation
  • Some exports include summary rows at bottom

File Type: Excel (.xlsx) Encoding: UTF-8 Date Format: YYYY-MM-DD

Required Columns:

Column NameDescriptionExample
ACCT_NBRAccount numberABC123
ACCT_NAMEAccount nameSmith Family Trust
ACCT_TYPE_CDType codeIND, JT, IRA
MKT_VALMarket value123456.78
POS_DTPosition date2024-12-31

Holdings Sheet:

Column NameDescription
CUSIPSecurity identifier
SEC_DESCSecurity description
QTYQuantity held
MKT_PRCMarket price
MKT_VALMarket value

Common Issues:

  • Multiple sheets (Accounts, Holdings, Transactions)
  • Header row may not be row 1
  • Numeric fields sometimes formatted as text

File Type: CSV Encoding: UTF-8 with BOM Date Format: M/D/YYYY (no leading zeros)

Required Columns:

Column NameDescriptionExample
Account NumberAccount IDXXXX-1234
Account TypeClassificationBrokerage
BalanceTotal value50000.00
DateAs of date1/5/2024

Common Issues:

  • BOM at file start needs stripping
  • Account numbers may be masked (XXXX-1234)
  • Same vendor has API version (Schwab API) - don’t confuse

File Type: CSV Encoding: Windows-1252 Date Format: DD-MMM-YYYY

Required Columns:

Column NameDescriptionExample
RepCodeAdvisor rep codeABC123
AccountNumberAccount ID12345-67890
ClientNameClient nameJohn Smith
AccountValueTotal value100,000.00
AsOfDateData date31-Dec-2024

Common Issues:

  • Windows-1252 encoding (not UTF-8)
  • Large files may need chunked processing
  • Rep code filtering required for multi-rep advisors

File Type: CSV (Activity Statement export) Encoding: UTF-8 Date Format: YYYY-MM-DD

Structure:

  • Multiple sections in single file
  • Section headers indicate data type
  • Need to parse section by section
Statement,Header,Account,Date
Statement,Data,U1234567,2024-12-31
Positions,Header,Symbol,Quantity,Price,Value
Positions,Data,AAPL,100,150.00,15000.00
Positions,Data,GOOGL,50,140.00,7000.00
Trades,Header,Date,Symbol,Quantity,Price
Trades,Data,2024-12-15,AAPL,10,148.00

Common Issues:

  • Multi-section format requires custom parser
  • Currency conversion for multi-currency accounts
  • Options/futures positions need special handling

File Type: CSV Encoding: UTF-8 Date Format: MM/DD/YYYY

Common Issues:

  • Advisor hierarchy in export
  • Branch code filtering may be needed

File Type: CSV Encoding: UTF-8 Date Format: MM/DD/YYYY

Common Issues:

  • Trust account structures
  • Multi-custody accounts
  1. Obtain Sample Files

    • Get at least 3 sample files with real data structure
    • Document file format (CSV/Excel)
    • Document encoding
    • Document date/amount formats
  2. Create Directory Structure

    app/Integrations/[NewVendor]/
    ├── Integrator.php
    ├── Parser.php
    ├── Mapper.php
    └── Models/
    ├── Account.php
    └── Holding.php
  3. Implement Parser

    • Handle encoding conversion
    • Handle header detection
    • Handle multi-sheet (if Excel)
    • Handle empty/summary rows
  4. Implement Mapper

    • Document column mapping
    • Handle date parsing
    • Handle amount parsing
    • Handle null values
    • Map account types
  5. Implement Integrator

    • Extend FileBasedIntegrator
    • Wire up Parser and Mapper
    • Implement sync logic
  6. Add to IntegrationType Enum

    • Add new enum case
    • Implement isFileBased() return true
    • Set getFileBasedHostType()
  7. Testing

    • Unit test Parser with sample files
    • Unit test Mapper with edge cases
    • Integration test full sync flow
    • Test with malformed/edge case files
  8. Documentation

    • Add to this vendor-specifics document
    • Update architecture-overview vendor list
    • Add developer ownership
<?php
namespace App\Integrations\NewVendor;
use App\Integrations\Support\FileBasedIntegrator;
use RightCapital\Core\Enums\Integration\IntegrationType;
class Integrator extends FileBasedIntegrator
{
protected function getParser(): Parser
{
return new Parser();
}
protected function getMapper(): Mapper
{
return new Mapper();
}
protected static function getVendor(): IntegrationType
{
return IntegrationType::NEW_VENDOR;
}
}
DeveloperIntegrations
Qianwei HaoFidelity, First Clearing, Folio Investing, LPL
Kewei YanBetterment, My529, Pershing, Trust America
Tingsong XuApex, Flourish
Yan HuAllianz, Altruist, RBC, Schwab (file)
Winston LiInteractive Brokers, Jackson, Pacific Life, Raymond James, SEI
Terminal window
# Check encoding
file -I /path/to/uploaded/file.csv
# View first few lines
head -20 /path/to/uploaded/file.csv
# Check for BOM
hexdump -C /path/to/uploaded/file.csv | head -1
ErrorLikely CauseSolution
”Column X not found”Wrong column name or encodingCheck actual headers in file
”Invalid date format”Unexpected date formatAdd format to parser
”Number format exception”Non-numeric charactersImprove amount cleaning
”File too large”Exceeds memory limitImplement chunked reading
// Quick test in tinker
$parser = new \App\Integrations\Fidelity\Parser();
$rows = $parser->parse('/tmp/test-file.csv');
dd($rows[0]); // View first parsed row