dev 28c3078ee2 feat(provider/northcapital): full TransactAPI adapter implementation
Pass 2 — every endpoint method is fully wired against the TransactAPI
public REST surface; the encrypted-webhook consumer is fully
implemented per the documented AES-256-CBC envelope; the conformance
suite drives every endpoint against httptest.Server fixtures with no
production HTTP traffic.

Endpoints (all fully implemented, no stubs):

  Party / Entity
    CreateParty, CreateEntity, GetParty, ListParties (paginated)

  KYC / AML / Accredited / Suitability
    PerformKYC, PerformAML
    PerformAccredited (income, net_worth, third_party_letter,
                       professional_license) + PerformAccreditedFull
    Suitability

  Offerings
    CreateOffering, GetOffering, ListOfferings (paginated)

  Trades
    CreateTrade, GetTrade, BulkUploadTrades (multipart),
    CancelTrade, RefundTrade,
    SendSubscriptionDocs, GetTradeDocuments

  Custody
    OpenCustodyAccount, GetCustodyAccount

  ATS / Secondary
    PublishATSEvent (uses EventID as the natural idem-key),
    GetSecondaryTrades

  Admin
    UpdateWebhookAuthKey

  Webhook
    ConsumeWebhook — full AES-256-CBC decryption per the documented
    TransactAPI scheme: URL-safe Base64 decode, undo "plusencr" → "+"
    substitution, split 16-byte IV, AES-256-CBC decrypt, PKCS#7 unpad
    (constant-time), parse "k=v, k=v, …" plaintext into the broker-wide
    WebhookEvent shape. HMAC-SHA256 signature gate runs when
    WebhookAuthKey is configured, with comma-separated key rotation
    overlap support.

Cross-cutting:

  - Uniform pagination: list endpoints iterate offset/limit internally
    until a short page or MaxRecords cap; callers receive complete
    result sets without writing pagination logic.
  - Rate-limiting + retry: exponential backoff with full jitter on 429
    and 5xx, honoring Retry-After (delta-seconds and HTTP-date); after
    the retry budget surfaces wrapped ErrRateLimited.
  - Idempotency: deriveIdempotencyKey(orgID, endpoint, canonicalBody)
    SHA-256 fallback on every mutating call; caller-supplied
    IdempotencyKey always wins. ATS PublishATSEvent uses EventID
    directly so duplicate events collapse upstream.
  - Authentication: clientID + developerAPIKey injected as form fields
    on every legacy v1 request; Bearer + X-Client-Id on the modern v3
    transport.
  - APIError carries StatusCode, Endpoint, Body, RetryAfter for
    errors.As recovery; envelope-level TransactAPI failures
    (statusCode != "101") are surfaced through the same shape.

Conformance suite (broker/pkg/provider/northcapital/conformance_test.go):

  - Every endpoint's happy path with form-field + idempotency-header
    assertions
  - All four accredited methods exercised independently
  - Bulk upload exercises the multipart/form-data path
  - Pagination iteration across multiple pages
  - 4xx mapping → *APIError; envelope-level errors mapped identically
  - 429 retry-then-succeed; 429 budget exhausted → ErrRateLimited
  - Retry-After parsing
  - Webhook signature: missing, bad, valid, rotation overlap
  - Webhook decryption: valid envelope, wrong key, invalid base64,
    plusencr substitution path, missing config
  - PKCS#7 unpadder unit tests (positive + 4 negative cases)

Build green: go build ./..., go vet ./..., go test -race ./pkg/provider/
northcapital/... all pass. 40 test cases pass, 0 failures.

Assumptions pinned for the NCPS sandbox handshake:

  1. Legacy v1 endpoints use form-encoded bodies with clientID +
     developerAPIKey carried as form fields on every call. Confirmed
     against the public reference; pinned if the sandbox key issuance
     diverges.
  2. The webhook HMAC ordering is decrypt-then-MAC over the raw
     envelope bytes. The public encrypted-webhooks guide is silent on
     this point; if the sandbox reveals MAC-then-decrypt, swap the
     ordering in ConsumeWebhook.
  3. The X-TransactAPI-Signature header name is the Lux-side
     convention pinned in the integration brief §7; remap if the
     sandbox uses a different upstream name.
  4. WebhookDecryptionKey is required to be exactly 32 bytes; the
     public guide says NCPS pads server-side to 32, but the adapter
     enforces 32 on the inbound to fail closed.

Source-of-design: Public-Spec
Source-ref: https://transactapi.readme.io/reference
Clean-Team-Member: dev-agent (pass 2 — full implementation)
Signed-off-by: dev <[email protected]>
2026-05-26 17:55:39 -07:00
2026-05-24 01:12:17 -07:00
2026-05-16 16:42:22 -07:00

Broker

Multi-venue trading router with smart order routing, pre-trade risk, instant settlement, and real-time market data aggregation across 16 institutional providers.

go build -o brokerd ./cmd/brokerd/
ALPACA_API_KEY=pk_... ALPACA_API_SECRET=sk_... ./brokerd

Providers

Provider Asset Classes Type
Alpaca Equities, Crypto Broker-dealer (SEC/FINRA)
Interactive Brokers Equities, Options, Futures, FX Prime broker
Tradier Equities, Options Broker-dealer
Coinbase Crypto Exchange (Advanced Trade API)
Binance Crypto Exchange
Kraken Crypto Exchange
Gemini Crypto Exchange
SFOX Crypto Prime dealer / SOR
FalconX Crypto Institutional RFQ
Fireblocks Crypto Custody + OTC
BitGo Crypto Custody + Prime
Circle USDC / Stablecoins Stablecoin infrastructure
CurrencyCloud FX (35+ pairs) Institutional FX (Visa)
LMAX FX, Crypto, Metals Institutional CLOB
Polygon.io Equities, FX, Crypto Market data
Finix Payments Payment processing

Architecture

                        ┌──────────────┐
                        │  brokerd     │
                        │  :8090       │
                        └──────┬───────┘
                               │
              ┌────────────────┼────────────────┐
              │                │                │
       ┌──────┴──────┐  ┌─────┴──────┐  ┌──────┴──────┐
       │ Smart Order │  │   Risk     │  │   Audit     │
       │   Router    │  │  Engine    │  │    Log      │
       └──────┬──────┘  └────────────┘  └─────────────┘
              │
    ┌────┬────┼────┬────┬────┬────┐
    │    │    │    │    │    │    │
   CEX  CEX  OTC  LP   FX  Data  Pay   (16 providers)
    │    │    │    │    │    │    │
   CB  KRK  FLX  SFX  CC  POLY  FNX

Smart Order Router polls all venues in parallel, ranks by net price (spread + fees), and can split large orders across venues using VWAP.

Risk Engine enforces per-account and global limits: order value, daily volume, open order count, rate limits, symbol whitelists/blacklists.

Settlement Engine manages a prefunding pool for instant crypto buys while ACH settles. Margin monitoring auto-liquidates at configurable drawdown thresholds.

Audit Log is an immutable append-only trail of every order, fill, cancellation, and transfer. Queryable, exportable, with hook support for external logging.

API Reference

Base URL: http://localhost:8090/v1

Auth: Authorization: Bearer <api-key> or X-API-Key: <api-key> header. Health check at /healthz requires no auth.

Accounts

Method Path Description
POST /v1/accounts Create account (with provider, identity, contact)
GET /v1/accounts List all accounts across providers
GET /v1/accounts/{provider}/{accountId} Get account detail
GET /v1/accounts/{provider}/{accountId}/portfolio Portfolio snapshot
PATCH /v1/accounts/{provider}/{accountId} Update account
DELETE /v1/accounts/{provider}/{accountId} Close account
GET /v1/accounts/{provider}/{accountId}/activities Account activity feed

Orders

Method Path Description
POST /v1/accounts/{provider}/{accountId}/orders Place order
GET /v1/accounts/{provider}/{accountId}/orders List orders (?status=open|closed|all)
GET /v1/accounts/{provider}/{accountId}/orders/{orderId} Get order
PATCH /v1/accounts/{provider}/{accountId}/orders/{orderId} Replace/modify order
DELETE /v1/accounts/{provider}/{accountId}/orders/{orderId} Cancel order
DELETE /v1/accounts/{provider}/{accountId}/orders Cancel all orders

Positions

Method Path Description
GET /v1/accounts/{provider}/{accountId}/positions/{symbol} Get position
DELETE /v1/accounts/{provider}/{accountId}/positions/{symbol} Close position
DELETE /v1/accounts/{provider}/{accountId}/positions Close all positions

Smart Order Routing

Method Path Description
GET /v1/route/{symbol} Best venues for symbol
GET /v1/route/{symbol}/{quote} Best venues for pair (e.g. BTC/USD)
GET /v1/route/{symbol}/split VWAP split plan
GET /v1/route/{symbol}/{quote}/split VWAP split plan for pair
POST /v1/smart-order Execute smart order (routes to best venue)
POST /v1/smart-order/split Execute split across venues
GET /v1/assets Aggregated assets across all providers

Market Data

Method Path Description
GET /v1/market/{provider}/snapshot/{symbol} Real-time price snapshot
GET /v1/market/{provider}/snapshots Multiple snapshots (?symbols=)
GET /v1/market/{provider}/bars/{symbol} OHLCV bars (?timeframe=&start=&end=&limit=)
GET /v1/market/{provider}/trades/latest Latest trades (?symbols=)
GET /v1/market/{provider}/quotes/latest Latest quotes (?symbols=)
GET /v1/market/{provider}/clock Market clock
GET /v1/market/{provider}/calendar Market calendar
GET /v1/market/{provider}/crypto/bars Crypto OHLCV bars
GET /v1/market/{provider}/crypto/quotes Crypto quotes
GET /v1/market/{provider}/crypto/trades Crypto trades
GET /v1/market/{provider}/crypto/snapshots Crypto snapshots

Consolidated Data

Method Path Description
GET /v1/bbo/{symbol} Best bid/offer across all venues
GET /v1/bbo/{symbol}/{quote} BBO for pair
GET /v1/stream SSE stream (real-time consolidated tickers)

Transfers & Banking

Method Path Description
GET /v1/accounts/{provider}/{accountId}/transfers List transfers
POST /v1/accounts/{provider}/{accountId}/transfers Create transfer (ACH/wire/crypto)
DELETE /v1/accounts/{provider}/{accountId}/transfers/{transferId} Cancel transfer
GET /v1/accounts/{provider}/{accountId}/bank-relationships List bank relationships
POST /v1/accounts/{provider}/{accountId}/bank-relationships Create bank relationship
DELETE /v1/accounts/{provider}/{accountId}/ach-relationships/{achId} Delete ACH
POST /v1/accounts/{provider}/{accountId}/recipient-banks Add wire recipient
GET /v1/accounts/{provider}/{accountId}/recipient-banks List wire recipients
DELETE /v1/accounts/{provider}/{accountId}/recipient-banks/{bankId} Remove wire recipient

Journals (Inter-Account Transfers)

Method Path Description
POST /v1/journals/{provider} Create journal (JNLC cash / JNLS security)
GET /v1/journals/{provider} List journals
GET /v1/journals/{provider}/{journalId} Get journal
DELETE /v1/journals/{provider}/{journalId} Delete journal
POST /v1/journals/{provider}/batch Batch journal
POST /v1/journals/{provider}/reverse_batch Reverse batch

Documents

Method Path Description
POST /v1/accounts/{provider}/{accountId}/documents Upload document
GET /v1/accounts/{provider}/{accountId}/documents List documents
GET /v1/accounts/{provider}/{accountId}/documents/{documentId} Get document
GET /v1/accounts/{provider}/{accountId}/documents/{documentId}/download Download

Watchlists

Method Path Description
POST /v1/accounts/{provider}/{accountId}/watchlists Create watchlist
GET /v1/accounts/{provider}/{accountId}/watchlists List watchlists
GET /v1/accounts/{provider}/{accountId}/watchlists/{id} Get watchlist
PUT /v1/accounts/{provider}/{accountId}/watchlists/{id} Update watchlist
DELETE /v1/accounts/{provider}/{accountId}/watchlists/{id} Delete watchlist
POST /v1/accounts/{provider}/{accountId}/watchlists/{id}/assets Add asset
DELETE /v1/accounts/{provider}/{accountId}/watchlists/{id}/{symbol} Remove asset

Portfolio History

Method Path Description
GET /v1/accounts/{provider}/{accountId}/portfolio/history Equity time series (?period=&timeframe=)

Event Streaming (SSE)

Method Path Description
GET /v1/events/{provider}/trades Trade events
GET /v1/events/{provider}/accounts Account events
GET /v1/events/{provider}/transfers Transfer events
GET /v1/events/{provider}/journals Journal events

Risk & Audit

Method Path Description
GET /v1/risk/check Pre-trade risk check (?provider=&account_id=&symbol=&side=&qty=&price=&type=)
GET /v1/audit Query audit log (?action=&provider=&account_id=&symbol=&since=&until=)
GET /v1/audit/stats Audit statistics
GET /v1/audit/export Export audit log (JSON download)

Funding

Method Path Description
POST /v1/fund/deposit Deposit via payment processor
POST /v1/fund/withdraw Withdraw via payment processor
POST /v1/fund/webhook/{processor} Payment processor webhook
GET /v1/fund/processors List available processors

Providers

Method Path Description
GET /v1/providers List registered providers
GET /v1/providers/capabilities Provider capabilities (asset classes, fees, features)

Settlement Engine

The prefunding pool enables instant crypto execution while ACH/wire settlement is pending.

User: "Buy 1 BTC"  →  Pool reserves $50k  →  Executes at market  →  ACH initiated
                                                                        │
                                              ACH clears (2-5 days) ────┤
                                              → Pool credit released    │
                                                                        │
                                              ACH fails ────────────────┘
                                              → Auto-liquidate position
                                              → Recover pool capital

KYC-tiered instant buy limits:

Tier Instant Limit Use Case
basic $250 Email-verified users
standard $5,000 ID-verified users
enhanced $25,000 Full KYC + accredited
institutional $250,000 Institutional accounts

Margin thresholds (configurable): 20% warning, 30% margin call, 50% auto-liquidation.

Configuration

Required

At least one provider must be configured. Set the API key environment variables for each provider you want to use.

Environment Variables

Variable Default Description
BROKER_LISTEN :8090 HTTP listen address
BROKER_API_KEY — Initial API key to register
BROKER_ORG_ID — Organization ID for API key
BROKER_DEV_MODE false Bypass auth (development only)
ADMIN_USERNAME admin Admin login username
ADMIN_PASSWORD — Admin login password (hashed, never plaintext)
ADMIN_SECRET — JWT signing secret (required for production)

Provider credentials — set the pair for each provider you want to enable:

Provider Variables
Alpaca ALPACA_API_KEY, ALPACA_API_SECRET
Interactive Brokers IBKR_ACCESS_TOKEN, IBKR_ACCOUNT_ID, IBKR_GATEWAY_URL, IBKR_CONSUMER_KEY
Coinbase COINBASE_API_KEY, COINBASE_API_SECRET
Binance BINANCE_API_KEY, BINANCE_API_SECRET
Kraken KRAKEN_API_KEY, KRAKEN_API_SECRET
Gemini GEMINI_API_KEY, GEMINI_API_SECRET
SFOX SFOX_API_KEY
FalconX FALCON_API_KEY, FALCON_API_SECRET, FALCON_PASSPHRASE
Fireblocks FIREBLOCKS_API_KEY, FIREBLOCKS_PRIVATE_KEY
BitGo BITGO_ACCESS_TOKEN, BITGO_ENTERPRISE
Circle CIRCLE_API_KEY
Tradier TRADIER_ACCESS_TOKEN, TRADIER_ACCOUNT_ID
Polygon.io POLYGON_API_KEY
CurrencyCloud CURRENCYCLOUD_LOGIN_ID, CURRENCYCLOUD_API_KEY
LMAX LMAX_API_KEY, LMAX_USERNAME, LMAX_PASSWORD
Finix FINIX_USERNAME, FINIX_PASSWORD
Braintree BRAINTREE_PUBLIC_KEY, BRAINTREE_PRIVATE_KEY, BRAINTREE_MERCHANT_ID

Build & Test

make build          # Build binary
make test           # Run tests
make test-race      # Run tests with race detector
make lint           # go vet
make docker         # Build Docker image
make docker-push    # Push to ghcr.io

Docker

docker build --platform linux/amd64 -t ghcr.io/luxfi/broker:latest .
docker run -p 8090:8090 -e ALPACA_API_KEY=... -e ALPACA_API_SECRET=... ghcr.io/luxfi/broker:latest

Image: ghcr.io/luxfi/broker — 7.5 MB, alpine-based, healthcheck on /healthz.

Project Structure

broker/
├── cmd/brokerd/          Entry point, provider wiring
├── pkg/
│   ├── api/              HTTP handlers, chi router, middleware
│   ├── admin/            JWT auth (HMAC-SHA256), admin users
│   ├── auth/             API key validation, permissions
│   ├── audit/            Immutable audit trail
│   ├── funding/          Deposit/withdraw via payment processors
│   ├── marketdata/       Real-time ticker aggregation, BBO
│   ├── provider/         Provider interface + 16 implementations
│   │   ├── alpaca/       Full Alpaca Broker API (100% coverage)
│   │   ├── binance/      Binance spot/margin
│   │   ├── bitgo/        BitGo custody + Prime
│   │   ├── circle/       Circle USDC operations
│   │   ├── coinbase/     Coinbase Advanced Trade
│   │   ├── currencycloud/ CurrencyCloud FX
│   │   ├── falcon/       FalconX RFQ
│   │   ├── finix/        Finix payments
│   │   ├── fireblocks/   Fireblocks custody
│   │   ├── gemini/       Gemini exchange
│   │   ├── ibkr/         Interactive Brokers
│   │   ├── kraken/       Kraken exchange
│   │   ├── lmax/         LMAX Digital
│   │   ├── polygon/      Polygon.io data
│   │   ├── sfox/         SFOX prime dealer
│   │   └── tradier/      Tradier equities
│   ├── risk/             Pre-trade risk engine
│   ├── router/           Smart order routing (net-price + VWAP)
│   ├── settlement/       Prefunding pool, instant buy, margin
│   ├── types/            Unified type definitions
│   └── ws/               WebSocket / SSE server
├── Dockerfile
├── Makefile
└── go.mod
Module Purpose
luxfi/compliance KYC/AML, identity verification, regulatory frameworks
luxfi/bank Customer apps, payments, admin dashboard
hanzoai/commerce Payment processors (Plaid, Braintree, Stripe)
hanzoai/iam Identity and access management (OAuth2/OIDC)

License

Copyright 2024-2026 Lux Partners Limited. All rights reserved.

S
Description
Federated broker: 16 providers, smart order routing, institutional trading
Readme
2 MiB
Languages
Go 99%
TypeScript 0.8%
Dockerfile 0.1%