AlertKeeper 0.2.12

Schwab connection

Where this comes from

Originator and date

AlertKeeper's maker, 10/12/2026, as the first slice of a broker connection: sign in to Schwab and keep the sign-in fresh. Made whole on 10/14/2026: the accounts read daily -- positions, balances, transactions -- for every user with an app key of their own. An app key must be the user's own, never shared with another program on the same login (below).

Industry sources read

Schwab's Trader API and its sign-in (OAuth 2.0), from Schwab's developer portal (developer.schwab.com): the authorize address (api.schwabapi.com/v1/oauth/authorize), the token address (api.schwabapi.com/v1/oauth/token), an access token good for 30 minutes and a refresh token good for 7 days; the account numbers and their hashes (trader/v1/accounts/accountNumbers), an account with its positions and balances (trader/v1/accounts/{hash}?fields= positions), and its transactions (trader/v1/accounts/{hash}/transactions: at most 60 days at a time, one type per request, each kept once by its activityId). The maker's own earlier ledger tool, read for how it pulls: a per-account checkpoint with a 7-day overlap. No other program's code, data or sign-in is used.

What prompted it

Positions and, later, option chains with delta and theta straight from the broker, which Yahoo's data doesn't have.

What we changed and why

The sign-in came first, watched before anything read the API. Then (10/14) the daily read: what Schwab gives is written out the way Schwab's own files are laid out and brought in through the same packs as a file -- so transfers, journal rows, expirations, the positions check, starting cash and Review behave exactly as with a file -- and a row both the API and a file carry is counted once, matched by what it means (day, kind, instrument, side, quantity, money), not by its words. A transaction the mapping doesn't know keeps Schwab's own words and goes to Review, never guessed. An account is known by Schwab's hash and its last digits, never its full number. A refused refresh is red on Health at once, with Schwab's reason. Other programs on the same computer may read the sign-in's state (a status file, never a token); with the user's switch on, they may ask for the current access token (loopback only, with a key in a file only that user can read) instead of signing in themselves. Testing showed that an app key shared with another program on the same Schwab login fails: Schwab keeps one refresh token per app per login, so a second program's sign-in ends the first's. The Broker page and Help say plainly that the app key must be your own, never shared. The key, the secret and the tokens live in the Keychain / Credential Manager only, never in a file or a log. The callback is caught on this computer with a certificate made on the spot; pasting the address is the fallback. AlertKeeper never trades: no order function is used.

Our own evidence

`tests/test_broker_schwab.py`, with Schwab's token service stood in for: sign-in, refresh, a refused refresh, 7 days running out, Disconnect wiping everything, the callback caught over https on 127.0.0.1, and no key, secret or token in the data folder, the log or a page. `tests/test_schwab_api.py`, with Schwab's API stood in for (made-up accounts and rows, shaped as Schwab's answers are): the pull, the checkpoint and its overlap, positions and cash, a file and the API counted once either way round, transfers, an unknown row to Review, the greeks, the status file, sharing off and on. Not yet run against Schwab itself: the first live read is still to come. Tried live on 10/12/2026 with an app key another program also used: 34 minutes after AlertKeeper signed in, Schwab refused the other program's refresh token ("invalid, expired or revoked"). Sharing an app key is ruled out.