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
ApexCSVVendor-hostedTingsong Xu
BettermentCSVSelf-hostedKewei Yan
FidelityFixed-width (NAM, POS, TAX)Self-hostedQianwei Hao
First ClearingCSVVendor-hostedQianwei Hao
FlourishCSVSelf-hostedTingsong Xu
Folio InvestingCSVSelf-hostedQianwei Hao
Interactive BrokersCSVSelf-hostedWinston Li
JacksonCSV/ExcelSelf-hostedWinston Li
LPLCSVVendor-hostedQianwei Hao
My529CSVVendor-hostedKewei Yan
Pacific LifeCSVSelf-hostedWinston Li
PershingFixed-width (ACCT, GCUS, ECMB, FUND, ISCA)Self-hostedKewei Yan
Raymond JamesCSVSelf-hostedWinston Li
RBCCSVSelf-hostedYan Hu
Schwab (File)CSVSelf-hostedYan Hu
SEICSVSelf-hostedWinston Li
Trust AmericaCSVVendor-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
FidelityMMDDYYYY (no separator, in POS header offset 62)12312024
PershingYYYY-MM-DD (in fixed-width files)2024-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
FidelitySpace-padded fixed-width fields; closed accounts marked by & prefix in NAM short name
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: Fixed-width text, delivered as .DAT.ZIP Encoding: UTF-8 Date Format: MMDDYYYY (in POS header offset 62) IBD Code: 570 (DB reference stored as 570:{client_id})

Logical Files:

FileTypeFilename PatternPurpose
NAM*NABASE*Account names, types, owner names
POS*POSITD*Positions: CUSIP, quantity, price, market value
TAX*_TLAOPENDELTA_*Cost basis (aggregated per CUSIP)

Line Prefixes: H = file header, D = detail row, CH = client header (client_id at offset 3 length 20), CT = client tailer.

Account Reference: BRANCH(3) + ACCOUNT_NUMBER(6) from NAM offset 8 length 9 (e.g., X46629715). Stored masked as BRANCH + XXX + LAST(3).

Common Issues:

  • Mismatched CH/CT boundaries throw — usually means truncated upload
  • Closed accounts have & prefix on NAM short name and are filtered out
  • Fidelity’s own docs incorrectly state date format is MMDDYY; actual is MMDDYYYY

See Fidelity vendor doc for full field offset tables and code locations.


File Type: Fixed-width text files Encoding: UTF-8 Date Format: YYYY-MM-DD

Logical Files:

FilePurpose
ACCTAccount information (number, name, type, status)
GCUSSecurities positions (CUSIP, quantity, market value)
ECMBElectronic trading funds — cash balances (new format)
FUNDMoney market funds — fund balances (legacy format)
ISCASecurity information (symbol, CUSIP, ISIN, price)

Filtering: Each detail row carries IBD (3-char) and IP (3–4 char) at known offsets per file type. The Reader filters rows by IBD/IP from the integration reference {transmission_id}:{IBD}[:{IP_list}].

Common Issues:

  • IBD/IP offsets differ per file type (see vendor doc for the offset table)
  • ISCA has no row-level filtering (security catalog applies to all)
  • Empty values represented as the literal string NULL

See Pershing vendor doc for IBD/IP offset table, transmission setup SOP, and full account/holding type mappings.


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 (current Reader/Extractor pattern)
use RightCapital\Integrations\FileBased\Fidelity\{Extractor, FileType, Reader};
$reader = Reader::create('570:CLIENT_ID', FileType::NAM);
$extractor = new Extractor($reader);
dd($extractor->getEntitiesByReference());

Note: legacy file-based integrations used App\Integrations\<Vendor>\Parser. New code lives in the RightCapital\Integrations\FileBased\<Vendor> package and uses the Reader + Extractor + Integrator pattern. See patterns doc.