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.