Skip to main content
POST
/
api
/
upload-csv
Upload CSV Files
curl --request POST \
  --url https://api.example.com/api/upload-csv \
  --header 'Content-Type: application/json' \
  --data '{}'
{
  "type": "<string>",
  "percentage": 123,
  "message": "<string>",
  "stats": {
    "transactions_inserted": 123,
    "realized_gains_lots": 123,
    "broker_verified_trades": 123
  }
}

Endpoint

POST /api/upload-csv

Authentication

Requires OAuth 2.0 authentication and user must have brokerage account number set in profile.

Content Type

multipart/form-data

Parameters

transaction_history_file
file
required
Transaction history CSV file from your brokerage
realized_gains_file
file
required
Realized gains/losses CSV file from your brokerage

Response Format

The endpoint returns streaming JSON responses to provide real-time progress updates:
{"type": "progress", "percentage": 25, "message": "Starting data processing..."}
{"type": "progress", "percentage": 40, "message": "Processing transaction history and realized gains..."}
{"type": "progress", "percentage": 60, "message": "Synchronizing with database..."}
{"type": "progress", "percentage": 80, "message": "Finalizing data import..."}
{"type": "success", "message": "Successfully processed files", "stats": {"transactions_inserted": 279, "realized_gains_lots": 713, "broker_verified_trades": 156}}

Success Response Fields

type
string
Response type: “progress”, “success”, or “error”
percentage
number
Progress percentage (0-100) for progress type responses
message
string
Human-readable status message
stats
object
Import statistics (only in success response)

Example

const formData = new FormData();
formData.append('transaction_history_file', transactionFile);
formData.append('realized_gains_file', gainsFile);

const response = await fetch('/api/upload-csv', {
  method: 'POST',
  body: formData
});

// Handle streaming response
const reader = response.body.getReader();
const decoder = new TextDecoder();

while (true) {
  const { done, value } = await reader.read();
  if (done) break;
  
  const text = decoder.decode(value);
  const lines = text.split('\n').filter(l => l.trim());
  
  for (const line of lines) {
    const data = JSON.parse(line);
    
    if (data.type === 'progress') {
      console.log(`Progress: ${data.percentage}% - ${data.message}`);
    } else if (data.type === 'success') {
      console.log('Upload complete!', data.stats);
    } else if (data.type === 'error') {
      console.error('Upload failed:', data.message);
    }
  }
}

Error Responses

{"type": "error", "message": "Both files must be CSV files"}
HTTP Status: 400 Bad Request
{"type": "error", "message": "Brokerage account number not set. Please update your profile."}
HTTP Status: 400 Bad Request
{"type": "error", "message": "Both transaction history and realized gains files are required"}
HTTP Status: 400 Bad Request

CSV File Requirements

Transaction History File

Should include columns such as:
  • Transaction date
  • Symbol
  • Action (Buy, Sell, etc.)
  • Quantity/Shares
  • Price
  • Amount
  • Account number

Realized Gains File

Should include columns such as:
  • Symbol
  • Date acquired
  • Date sold
  • Proceeds
  • Cost basis
  • Gain/Loss
File format requirements may vary by brokerage. The system attempts to automatically detect and parse common formats.

Upload History

View history of previous uploads

CSV Upload Feature

Learn more about CSV upload functionality