Raxx · internal docs

internal · gated

ADR 0109 — BYOB Broker Tier Model and Post-Launch Roadmap

Status: Proposed Date: 2026-05-28 UTC Deciders: product owner (Kristerpher), software-architect Scope: Raptor (backend_v2/), Antlers (frontend/), Velvet (token rotation), Queue (identity) Refs: ADR-0014 (Alpaca scope), ADR-0108 (MBT engine), Epic #495, Research doc #2627, Issue #2629


1. Context

Why BYOB matters

Raxx's structural value is broker-agnostic: the entry/credit/exit discipline the user already decided on, enforced before emotion gets a vote. A user locked to one broker for live execution is a user who may not adopt Raxx at all. Customer choice of broker is a trust signal — "Raxx works with my account" is stronger than "Raxx requires you to open an Alpaca account." Multi-broker households (IRA at Schwab, options at tastytrade) are a real and growing segment among active retail traders.

Current state

What is locked


2. Decision

Raxx brokers are classified in three tiers by depth of integration and Raxx's compliance responsibility. The tier a broker occupies is architectural — it determines the code path, the token model, the UX label set, and the regulatory exposure.

Tier A — Directly integrated brokers

Raxx holds the API contract and is responsible for integration correctness, token lifecycle, and order semantics.

Criteria for Tier A: - Raxx calls the broker's API directly (no intermediary) - Raxx owns the OAuth / API-key flow for that broker - The broker has a public REST API with a stable sandbox - The broker is FINRA/SIPC member or equivalent

v1 Tier A: Alpaca (default and BYOB mode). Post-launch Tier A targets: Tradier, tastytrade, Schwab (if direct API approved).

Tier A capabilities matrix:

Capability Tier A
Place equity orders Yes
Place options orders Yes (broker-dependent; Tradier/tastytrade/Alpaca all support)
Cancel orders Yes
Positions + account state Yes — live from broker API
Order status streaming Yes — broker WebSocket
Paper trading MBT (never broker paper)
Multi-leg options Yes (v2; v1 single-leg)

What is not available / deferred in Tier A v1: - Margin / leverage tracking: deferred to v2 - Short-locate / borrow: deferred - Extended-hours orders: deferred - Futures / crypto: out of scope for v1

UX label: "Live" indicator (moss-pill pattern). No broker name in primary copy. Settings page shows "Connected: [Broker brand name]" as the secondary/detail label only.

Tier B — Aggregator-routed brokers

Raxx calls a licensed aggregator (SnapTrade) which holds the broker relationships. Raxx is an API consumer of the aggregator; the aggregator handles per-broker protocol differences and compliance posture.

Criteria for Tier B: - Raxx calls the aggregator API; the aggregator calls the broker - The aggregator holds the broker API credentials, not Raxx - Order semantics are mediated by the aggregator

Post-launch Tier B targets (via SnapTrade): IBKR, Schwab (if direct API not pursued), E*TRADE, Fidelity (read-only initially — see Tier C note), Robinhood (read-only initially).

Tier B capabilities matrix:

Capability Tier B
Place equity orders Yes — via aggregator
Place options orders Aggregator-dependent; SnapTrade supports options for select brokers
Cancel orders Yes — via aggregator
Positions + account state Yes — via aggregator
Order status streaming Polling in v1; aggregator-push if available in v2
Paper trading MBT (never broker paper)

What is not available in Tier B: - Aggregator availability determines broker availability; outages are transitive - Some Tier B brokers (e.g., Fidelity) do not support order placement via SnapTrade — they are Tier C until that changes - Streaming order status is polling in v1; latency is higher than Tier A

Compliance note: SnapTrade holds the introducing-broker relationship with the downstream broker. Raxx inherits SnapTrade's compliance posture for order routing. This is the most compliance-protective architecture for multi-broker support. However, Raxx still must confirm with securities counsel whether acting as a SnapTrade API consumer triggers Section 15(a) registration. This is an open question (see §8).

UX label: Same moss-pill "Live" indicator. No aggregator name in primary copy. Settings shows "Connected: [Broker brand name]." Aggregator is invisible to the user at the UX layer.

Tier C — Read-only / data-import brokers

Raxx can import portfolio state (positions, history) but cannot submit orders.

Criteria for Tier C: - Read-only access only — no order placement - Used for portfolio import, performance attribution, and position aggregation across accounts - No paper-first gate applies (no live orders)

Post-launch Tier C targets: Plaid Investments (portfolio import), direct read-only broker APIs where available (e.g., Fidelity read-only), Yodlee (deferred pending cost/complexity review).

Tier C capabilities matrix:

Capability Tier C
Place orders Never — read-only invariant
Import positions Yes
Import trade history Yes
Performance attribution Yes — Raxx-computed on imported data
Paper trading N/A — no live orders; MBT is separate
Streaming No — polling only

UX label: "Linked" (not "Live"). Settings shows "Linked: [Institution name]."


3. Sequencing

Phase 1 — Current (v1 launch)

Scope: Alpaca as default live broker. MBT as paper layer. Single broker per user.

Dependencies already satisfied: ADR-0014 (Alpaca scope), ADR-0108 (MBT), PR #3021 (paper-first gate), PR #3024 (compliance enforcement).

Estimated effort: Already shipped.

Phase 2 — Alpaca BYOB + Tradier + tastytrade (Tier A)

Scope: - Alpaca BYOB: user supplies their own Alpaca API key; Raxx uses it instead of platform keys. Config switch in Velvet — approximately 1 engineering week. - Tradier: REST + OAuth, paper sandbox for QA, equities + options. Approximately 1–2 engineering weeks. - tastytrade: partner program contact (api.support@tastytrade.com), OAuth 2.0, sandbox (no live account required). Approximately 2–3 engineering weeks. - BrokerConnect wizard step (PR #3057) must land first as the shared UI entry point.

Dependencies: - Securities attorney opinion letter on Section 15(a) exposure must precede production deployment of any Tier A BYOB broker (60–90 day lead time from engagement). - Velvet token rotation extended for multi-broker: tier-tag column in tokens table (see §6). - KMS audit chain (approved, SC-A11/SC-A14) must be deployed before first Tier A BYOB order reaches production — every live order against a user-supplied credential must be in the audit chain. - Paper-first gate (PR #3021) must enforce graduation against MBT cycles, not broker-paper cycles (already the design in ADR-0108).

Customer impact: Power users with existing Tradier / tastytrade accounts can connect immediately. Alpaca-native users can BYOB their own key.

Phase 3 — SnapTrade aggregator (Tier B)

Scope: - SnapTrade API integration: broker selection at signup or in Settings → Broker - Aggregator-mediated live orders for IBKR, Schwab (if not direct), and any SnapTrade-supported broker - SnapTrade connection token stored in Velvet (connection ID, not per-broker credential — see §6)

Dependencies: - SnapTrade contract signed (pricing tier confirmed — open question §8) - Tier A architecture (Phase 2) proven stable — shared service layer pattern applies to Tier B adapters - Securities counsel must confirm SnapTrade-consumer posture satisfies Section 15(a) safe harbor - Per project_byob_hybrid_strategy: aggregator is not a permanent dependency; if a Tier B broker reaches demand threshold, it may be promoted to Tier A direct

Estimated effort: 3–5 engineering weeks for SnapTrade adapter + connection flow + Velvet extension.

Customer impact: Opens IBKR, Schwab, and full SnapTrade broker list without per-broker integration work. Highest leverage phase for broker breadth.

Phase 4 — Schwab direct (Tier A) and IBKR assessment

Scope: - If Schwab Trader API access is approved (developer.schwab.com portal): direct Tier A integration. Same pattern as Tradier / tastytrade. Estimated 2–3 engineering weeks. - If Schwab Trader API approval is not obtained or is slow: Schwab stays at Tier B via SnapTrade from Phase 3. No customer-facing gap. - IBKR: assess whether direct API justifies Tier A promotion based on customer demand signals at Phase 3 completion. IBKR's TWS architecture and funded-account sandbox requirement add friction. Decision deferred to Phase 4 assessment (open question §8).

Dependencies: - Schwab developer portal application submitted and approved (~1–3 business days historically per research doc) - IBKR demand assessment from Phase 3 customer data

Phase 5+ — Tier C data import

Scope: Plaid Investments portfolio import. Yodlee (pending cost review). Direct read-only broker APIs.

Dependencies: - Plaid partnership agreement and pricing - Data model for imported positions distinct from live-broker positions (different provenance, no order-placement capability, different freshness semantics)

Estimated effort: 2–4 engineering weeks per provider.

Customer impact: Multi-account households can import their 401(k) or IRA for performance attribution even if those accounts are not actively traded through Raxx.


4. Customer UX

Broker connection flow

New customer — wizard path:

  1. Signup wizard reaches BrokerConnect step (PR #3057).
  2. User sees a list of supported brokers by their brand label. Unavailable brokers are hidden (not grayed) per feedback_hide_dont_gray_unavailable_features.
  3. User selects a broker. The UI presents the appropriate connection mechanism: - Tier A: OAuth flow (redirect to broker authorization page) or API-key entry (for brokers that use API keys rather than OAuth). - Tier B: SnapTrade-hosted connection widget (SnapTrade handles the OAuth for the downstream broker; Raxx never sees the broker OAuth token). - Tier C: Read-only OAuth or credential flow as applicable.
  4. On successful connection, Raxx receives and stores the connection artifact in Velvet (see §6). The wizard shows "Connected: [Broker brand name]" and proceeds.

Existing customer — Settings path:

Settings → Broker panel shows: - Current connection(s): "[Broker brand name] — Live" (moss-pill) or "[Institution name] — Linked" (Tier C). - "Swap broker" — disconnects current and triggers the wizard BrokerConnect step. - "Add second account" — available post-Phase 4 for multi-broker households. - "Disconnect" — revokes token via Velvet, clears connection. Confirmation required.

Multi-broker households (Phase 4+)

Each broker connection is a separate "account" in Raxx. A user with Schwab and tastytrade has two accounts. At order submission, the user picks which account to trade from (or the active strategy's configuration specifies it). Positions are shown per-account and optionally in an aggregate portfolio view. Raxx does not net positions across brokers — this is a deliberate choice to keep position semantics clean and avoid cross-broker margin confusion.

UX copy rules (per feedback_no_backend_branding)


5. Compliance and Risk

Tier A direct integration

Raxx submits orders directly to the broker API on the user's behalf. This is the highest regulatory exposure point. Exchange Act Section 15(a) prohibits acting as a broker-dealer without registration unless an exemption applies. The securities attorney opinion letter must address this specifically before Phase 2 production deployment.

The research doc (#2627) notes Tradier, tastytrade, and Alpaca all have documented third-party platform policies. These policies acknowledge platform integrations but do not constitute a Section 15(a) exemption. Raxx must obtain independent legal confirmation.

Tier B aggregator-mediated

SnapTrade holds the introducing-broker relationship. Raxx is a SaaS consumer of SnapTrade's API. This significantly reduces Raxx's direct regulatory exposure for order routing. However, Raxx still presents the order placement UI to the user, which may be viewed as facilitating brokerage activity. Counsel must confirm.

Tier C read-only

Lowest regulatory exposure. No order placement, no money movement. The primary compliance concern shifts to data licensing: Plaid and Yodlee data-use agreements must be reviewed against Raxx's use case.

Marketing copy

"Your Schwab account" and "your tastytrade account" are fine — referring to the user's existing relationship. "Raxx-Schwab" or "integrated with Schwab" implies a commercial relationship Raxx does not have. Per BLR cluster (#2850, #2847) research: use the user's broker brand label only in possessive context.

Execution remains deterministic

Per feedback_deterministic_execution_ai_augments: the broker tier is infrastructure. Order-firing is rule-based and deterministic regardless of which broker processes the order. Changing a broker is changing the plumbing, not the logic.


6. Velvet and Secrets

Tier A token model

Tier A connections use long-lived OAuth tokens or API keys per broker. These are stored in Velvet using the existing envelope-encryption pattern (ADR-0009 scope extended to cover additional Tier A brokers).

Required change: tokens table in Velvet gains a broker_tier column (TEXT, NOT NULL, values: 'tier_a', 'tier_b', 'tier_c') and a broker_slug column (TEXT, NOT NULL, e.g. 'alpaca', 'tradier', 'tastyworks'). This enables per-broker rotation policies and per-broker revocation without touching rows for other brokers.

Rotation: Tier A tokens follow the existing 90-day rotation pattern (ADR-0008 scope). Each broker's rotation mechanics are wrapped in a broker-specific Velvet rotation handler.

Revocation: Raxx calls the broker's token-revoke endpoint (where available) and marks the Velvet row revoked_at. Session invalidation propagates through the existing session invalidation path (Queue).

Tier B aggregator token model

For SnapTrade: - Raxx stores the SnapTrade user connection ID (a SnapTrade-issued identifier for the user-broker pairing) in Velvet. This is not a credential that can replay a broker order — it is a reference ID. - The actual broker OAuth token is held by SnapTrade. Raxx never receives it. - Token rotation for the broker credential is SnapTrade's responsibility. - Raxx maintains a SnapTrade API key (server-side, in secret store). This key is rotatable without redeploy and is the only Raxx-held credential in the Tier B path. - broker_tier = 'tier_b', broker_slug = 'snaptrade' in Velvet. The SnapTrade connection ID is stored as token_ciphertext — it is encrypted at rest even though it is not itself a secret, for schema consistency and defense-in-depth.

Tier C read-only token model

Read-only tokens (Plaid link tokens, etc.) follow the same Velvet storage pattern. broker_tier = 'tier_c'. These tokens have no_order_write flag set on the Velvet row (new column, Boolean, default false for Tier A/B). Any code path that attempts to use a Tier C token for order placement is rejected at the Velvet service layer — not just at the application layer.

Kill-switch

BYOB_LIVE_DISABLED=1 — Raptor returns 503 on all live order submissions for BYOB (Tier A/B) connections. MBT paper trading is unaffected. Alpaca default-platform connection is also unaffected.

Per-broker kill-switch: BYOB_BROKER_<SLUG>_DISABLED=1 (e.g., BYOB_BROKER_TRADIER_DISABLED=1) — same 503 behavior scoped to that broker slug only.


7. MBT Relationship

MBT (ADR-0108) is the permanent paper layer. This is independent of broker tier.

This ADR resolves ADR-0108 Open Question #3 (BYOB paper parity) definitively: YES, MBT is the permanent simulator for all broker tiers. No broker-specific paper path will be added. The rationale: broker paper environments have different fidelity, different data latency, different account reset semantics, and different API stability. MBT's deterministic, Raxx-owned simulation is the consistent baseline across all tiers.


8. Open Questions — Operator Decisions Required

These items block sub-card implementation. They are listed in priority order.

OQ-1 (Phase 2 blocker): Securities attorney engagement. The research doc (#2627) identifies the Section 15(a) broker-dealer registration question as unresolved. Attorney engagement must begin 60–90 days before target Phase 2 production deployment. The attorney shortlist is at docs/business-legal/securities-attorney-engagement-2026-05-13/ATTORNEY-SHORTLIST.md. Scope must explicitly cover Exchange Act Section 15(a) for both Tier A direct integration and Tier B SnapTrade-consumer posture. Decision needed: Confirm attorney engagement is initiated and target opinion-letter date.

OQ-2 (Phase 3 blocker): SnapTrade contract and pricing tier. SnapTrade pricing is approximately $2/user/month for real-time + trading access. Phase 3 depends on a signed contract. Operator should engage SnapTrade's sales/partnerships team to confirm pricing tier, per-order vs. subscription model, SLA commitments, and data-use terms. SnapTrade research is in the research doc (#2627, §1.4). Decision needed: Initiate SnapTrade contract discussion; confirm pricing model before Phase 3 sub-cards are claimed.

OQ-3: Schwab — direct API vs. SnapTrade-routed. Schwab Trader API is public and approval is reportedly fast (1–3 business days). If approved, Schwab is a strong Tier A candidate (OAuth 2.0, equities + options, well-documented). If not pursued directly, Schwab is Tier B via SnapTrade. The engineering cost difference is moderate; the compliance posture difference is significant (Tier A = more direct Raxx responsibility). Decision needed: Should the team apply for Schwab Trader API access as a prerequisite to Phase 4? Or hold Schwab at Tier B via SnapTrade indefinitely?

OQ-4: IBKR prioritization. IBKR has high demand among advanced traders (options, futures, international equities). However, IBKR direct API (TWS) has significant integration friction: funded-account-required sandbox, TWS gateway architecture, FIX protocol option. SnapTrade routes IBKR and is the preferred path. The question is whether IBKR should jump the queue at Phase 3 alongside the general SnapTrade integration (which it would, automatically, if SnapTrade supports it) or if IBKR-specific UX/testing should be prioritized separately. Decision needed: Is IBKR a named priority for Phase 3 customer communications, or is it bundled silently with the SnapTrade rollout?

OQ-5: Multi-broker households — Phase 4 or Phase 5? The design in §4 describes multi-broker households as a Phase 4+ feature (available after Schwab direct/IBKR assessment). Supporting two simultaneous live broker connections adds non-trivial complexity to position aggregation, order routing UI, and paper-first gate logic (which account do graduation cycles count toward?). Decision needed: Confirm whether multi-broker household support is a Phase 4 target or deferred to Phase 5+.

OQ-6: Tier C provider selection. Plaid Investments is the leading candidate for portfolio import (Tier C). Yodlee is an alternative. Some brokers expose read-only APIs directly. The question is which provider(s) to target and when. Decision needed: Is Tier C in scope for the 6-month post-launch window, or deferred to the following planning cycle? If in scope, confirm Plaid as the starting point.


9. Security and GDPR Checklist


10. Language Choice Rationale

This ADR does not introduce a new service. BYOB integration is implemented within: - Raptor (Tier 2 — Python): broker adapter modules, order routing, Velvet client calls - Velvet (Tier 1 — Rust, per operator designation and C-1 criterion): token storage, rotation, revocation

The SnapTrade and Tier A broker adapter modules are Raptor additions (Python). They do not trigger Tier 1 promotion criteria: no sub-5ms latency requirement, no cryptographic key material handled in the adapter layer (Velvet holds that), no throughput demand at v1 post-launch scale.

Velvet's Tier 1 classification already covers the credential-handling hot path for all broker tiers. The adapter modules in Raptor are domain-logic translation layers (request shaping, response mapping, compliance gate calls), which are Tier 2.

API contract portability: Raptor's broker adapter interface is designed as a protocol: BrokerAdapter.submit_order(order) → OrderResult, BrokerAdapter.cancel_order(order_id) → CancelResult, BrokerAdapter.get_positions() → [Position]. This contract is portable to a future Rust implementation without redesign if a specific adapter becomes latency-sensitive.


11. Alternatives Considered

Single aggregator only (SnapTrade for all brokers, no direct Tier A)

Rejected. Aggregator-only creates a single point of dependency, SnapTrade pricing scales with user count, and the compliance posture analysis still requires attorney review. Direct Tier A integration for the most-demanded brokers (Alpaca BYOB, Tradier, tastytrade) is low-effort given existing architecture and builds a direct relationship with the broker. The hybrid model is confirmed (project_byob_hybrid_strategy).

All brokers as Tier B via SnapTrade

Rejected for the same reasons. Additionally, tastytrade has a formal partner program and sandbox that encourages direct integration. Defaulting every broker to Tier B misses the brand alignment and fill-fidelity benefits of a direct API relationship.

Expose broker names in primary UX copy

Rejected per feedback_no_backend_branding. User sees their broker's brand name in account-specific contexts ("Connected: Schwab"). Raxx's primary copy ("Live trading") does not reference broker names.


12. References


Revisit when