Why is the Google Sheet the integration point?

Portle reads a Google Sheet you own. Nothing stops another program from writing to the same sheet, which means you do not have to wait for anyone to build a connector for your broker. If your broker issues personal API credentials, a small script on your own machine can append your executed trades directly.

Portle never holds your broker credentials in this arrangement, and never sees the script. There is a prompt file you can paste into a coding assistant to have the script written for you, carrying the column contract and the safety rules described below.

Open the prompt file

What should I check in the API docs before writing any code?

First, whether there is an IP allowlist. Many brokers only accept calls from addresses you register in advance, which rules out serverless hosts with rotating egress addresses and rules out phones entirely. If your broker does this, the script has to live on a machine with a stable address.

Second, how many access tokens may exist at once. Some brokers keep exactly one valid token per client and silently invalidate the previous one when a new one is issued, so two jobs running at the same time will keep killing each other. Third, how far back trade history goes: a three- or twelve-month window means the script can keep a ledger current going forward but cannot rebuild the past.

How do I make the script safe to run twice?

Give every row the script adds an id built from the broker order id, such as broker:order-id, and write it in the Id column. Before adding anything, read the sheet, collect the ids already there, and skip whatever is already recorded. Matching on date and amount instead will fail the first time a partial fill produces two identical-looking trades.

Two consequences are easy to miss. A row you marked in the Void column still counts as already present, because Void means you decided not to count that row, not that the trade never happened. And if the Id column is missing from the header row, the script must stop rather than continue, because without it every run duplicates the entire ledger.

Why does cash stop matching after an API import?

Most broker APIs report executed orders and current holdings and say nothing at all about deposits, withdrawals, currency conversion, or dividends. Append only buys and sells and your ledger will show cash that never arrived, and every cash figure in the app follows it down.

The honest handling is to append the trades and report the gap: print the ledger cash balance against what the broker reports and enter the deposits yourself. If you do reconstruct the missing cash rows, give each one its own stable id and mark every inferred row in the note column, so an inferred row can never be mistaken for a reported one.

Why should the script append rows and never rebuild the tab?

The quickest way to write this is to regenerate every row and overwrite the tab, and it appears to work because the output matches. It also erases anything you typed by hand and every Void you set, every single run. That is why such a script can never be put on a schedule, no matter how correct its arithmetic is.

Build the full row set in memory if that is simpler, then compare it with the sheet by ID and append only missing rows. Update a row in place only when it is a confirmed correction, such as a cash balance matched to the broker. Leave every other row unchanged. Run the script twice and confirm that the second run reports nothing to do.

What if my broker has no API?

Most brokers still let you export transactions as a CSV or Excel file. Import that file in Portle, review the transactions it reads, and choose which rows to save. Screenshots from a broker app go through the same review list.

A file import and an API script can feed the same ledger. Keep the stable ID rule for the script, and compare position quantity and cash with the broker after either kind of import.

Read the broker CSV checklist