Support other accounts of a login, e.g. a company account, via --account - #399
Open
HerrNiklasRaab wants to merge 3 commits into
Open
HerrNiklasRaab wants to merge 3 commits into
HerrNiklasRaab wants to merge 3 commits into
Conversation
A Trade Republic login can act for more accounts than its own, e.g. a company account (legal entity) or a child's account. These are separate customers: the web app lists them at /api/v1/customer/relationships/detailed and switches by posting the customer id as subjectId to /api/v2/auth/web/session, which swaps the session tokens. - add relationships() and switch_account() to the API, and --account to every subcommand that logs in - keep the session on the chosen account when it is refreshed - read the securities account number from the accountPairs topic when /api/v2/auth/account refuses with INVALID_AUTH_ACCOUNT_STATE, which it does while the session acts for another account - accept saved cookies that act for another account instead of forcing a new login, and return to the own account when --account is not given Refs pytr-org#228 Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Prints type, name and state of every account the login can act for, from the same relationships call the switch resolves its argument with. Refs pytr-org#228 Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Live tests showed that the session refresh without a subject returns the session to the login's own account, and that a new process always starts with that refresh. So saved cookies never carry the chosen account into the next run, and the handling added for that case could not be reached. - drop the INVALID_AUTH_ACCOUNT_STATE handling in resume_websession(), login() and compact_portfolio(); the own-account paths are as before - keep answers to other subscriptions while compact_portfolio() looks up the securities account, instead of discarding them - report a missing or unanswered accountPairs lookup as ValueError - exit with a message when the switch is refused, not a traceback - match accounts by customer id, type, name or first name; show the customer id in 'pytr accounts' for accounts that share type and name - tolerate missing or non-text fields in the relationships list - stop claiming child accounts work: only a company account was tested - tests: fail on unexpected requests, isolate login() from ~/.pytr, pin the request order of a new process, cover the error paths Refs pytr-org#228 Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
HerrNiklasRaab
marked this pull request as ready for review
October 1, 2026 00:03
Collaborator
|
Sounds cool - I'll give it a try. 😄 |
Author
|
Do you have child account you could try? |
Collaborator
Yes, I can test that. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What this adds
A Trade Republic login can act for more accounts than its own, e.g. a company account (legal entity, "Private Holding"). pytr could not reach them. This PR adds:
pytr accountslists the accounts of the login (type, name, customer id, state).--account <type, name or customer id>on every subcommand that logs in, e.g.pytr portfolio --account LEGAL_ENTITYorpytr dl_docs --account "Mustermann Holding GmbH" ./docs.TradeRepublicApi.relationships()andTradeRepublicApi.switch_account()for library users.Without
--accountnothing changes: same requests, same errors.How Trade Republic addresses these accounts
They are not a second securities account under the same customer. Each one is a customer of its own, and the web app swaps the session cookies to act for it:
GET /api/v1/customer/relationships/detailedlists them. The login's own entry hasrelationshipType: SELF; a company account hasrelationshipType: LEGAL_ENTITY_ACTOR,accountType: LEGAL_ENTITY.POST /api/v2/auth/web/sessionwith{"subjectId": <customerId>}returns cookies that act for that customer. The web app uses the same call, with the current subject, to refresh its session.accountPairsreturns its securities and cash account;compactPortfolioByType,cashand the timeline topics work as usual.Two things behave differently in a switched session:
/api/v2/auth/accountanswers400 INVALID_AUTH_ACCOUNT_STATE. pytr reads the securities account number from that call (Fix portfolio mode by adding secAccNo parameter to compactPortfolio #256), so after a switchcompact_portfolio()reads it fromaccountPairsinstead.GET /api/v1/auth/web/session, returns the session to the login's own account. After a switch the refresh therefore posts the subject. A new process starts with the subject-less refresh, so the choice is never carried over from an earlier run through saved cookies.Changes
switch_account()resolves the argument againstrelationships()(customer id, type, name or first name; exact, case-insensitive; ambiguous or unknown values raise and name the known accounts) and posts the subject to the session endpoint._web_requestkeeps the chosen subject when it refreshes the session. For the own account it is unchanged.compact_portfolio()looks the securities account up viaaccountPairsafter a switch. Answers to other subscriptions that arrive during that lookup are kept for the nextrecv().login()switches after logging in when--accountis given and exits with a message if the account is unknown or the switch is refused.Testing
Unit tests: 47 new cases in
tests/test_accounts.py; the whole suite,ruff check,ruff format --checkandmypypass.Run against a real login that has a company account, with
--v2:pytr accountslists both accounts.pytr portfolio --account LEGAL_ENTITYswitches and loads that account's portfolio and cash, both after a fresh login and when resuming from cookies saved with--store_credentials.--accountafter that uses the own account again.switch_account()without an argument does the same.--accountvalue exits with the list of accounts.Not tested:
--v2.Refs #228
🤖 Generated with Claude Code