The sheet is 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

Read three things 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.

A stable id in the Id column is what makes it 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.

Cash is the part that breaks

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.

A rebuilder is not a bridge

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.