Wolves of Capitol HillAPI Docs

The trades data model

Every field on a Trade, the STOCK Act amount ranges, conflict-signal semantics, and the nullable-ticker caveat.

Every trade in the API went through the same pipeline: scraped from an official House or Senate disclosure, extracted, human-reviewed, and only then published. The Trade object is identical everywhere it appears — the feed, politician profiles, ticker pages, and webhook payloads.

Trade fields

FieldTypeMeaning
idstringStable trade id.
politicianobjectThe disclosing member: slug, name, chamber (house | senate), party, state (the last two nullable).
tickerstring | nullExchange symbol, uppercase. Nullable — see below.
assetNamestringThe asset as written in the filing.
assetTypestring | nullAsset class as disclosed (e.g. stock, bond, fund), when stated.
sidestringbuy, sell_full, sell_partial, or exchange.
amountBucketstringThe statutory range key (e.g. 15k_50k) — see the table below.
amountRangeobjectThe bucket resolved to { min, max, label }; max is null when unbounded.
tradeDatestring | nullThe transaction date (yyyy-mm-dd), when the filing states it.
disclosedAtstringISO 8601 instant the trade was disclosed. Feed ordering key.
filingUrlstring | nullThe official source document URL.
ownerTypestring | nullWho holds the asset: self, spouse, joint, or child; null when not stated.
conflictSignalbooleanWhether the trade overlaps an industry the member oversees — see below.
conflictReasonstring | nullWhy the signal fired; null when it did not.

Amounts are ranges, not numbers

Members of Congress never disclose exact amounts — the STOCK Act disclosure forms use checkbox ranges. amountBucket is the range key and amountRange spells out the statutory bounds:

amountBucketRange
1k_15k$1,001 – $15,000
15k_50k$15,001 – $50,000
50k_100k$50,001 – $100,000
100k_250k$100,001 – $250,000
250k_500k$250,001 – $500,000
500k_1m$500,001 – $1,000,000
1m_5m$1,000,001 – $5,000,000
5m_25m$5,000,001 – $25,000,000
25m_50m$25,000,001 – $50,000,000
over_50mOver $50,000,000 (max: null)
over_1m_spouseOver $1,000,000, spouse/dependent holdings (max: null)

Two consequences for consumers:

  • Never treat amountRange.min (or the midpoint) as "the amount" in analytics without labeling it as a bound — a 1m_5m trade could be $1,000,001 or $4,999,999.
  • amountRange.max is null for the two open-ended buckets; handle that before doing arithmetic.

The over_1m_spouse bucket exists because the House form has a distinct "over $1,000,000" checkbox for spouse/dependent-held assets that doesn't state an upper bound.

Conflict signals

conflictSignal is the platform's editorial flag: true when the traded asset's industry overlaps a committee the member sits on (e.g. a Senate Armed Services member trading a defense contractor). conflictReason explains the overlap in one sentence.

How it's computed, so you know what you're consuming:

  • Committee assignments and memberships come from public congressional datasets; tickers map to sectors/industries with curated overrides.
  • A daily sweep recomputes the verdict for every trade — signals can appear or be corrected after first publication as committee data updates, so treat the pair as mutable metadata, not immutable history.
  • It is an editorial signal of potential conflict of interest, not an allegation of illegality — STOCK Act trading is legal when disclosed. Present it accordingly.

The nullable-ticker caveat

ticker is null on a meaningful share of real trades: municipal bonds, private funds, crypto, real-estate partnerships, and assets whose symbol can't be resolved from the filing text. Two practical rules:

  • Code that groups or joins by ticker must handle null (use assetName as the display fallback).
  • The feed's ticker= filter only matches trades whose symbol resolved — it will never return the null-ticker rows.

tradeDate and filingUrl are nullable for the same underlying reason: the API reports exactly what the filing supports, never a guess.

CSV export

The trades feed can answer CSV for offline analysis (plans with CSV export; otherwise 403 csv_export_not_available):

curl -H "Authorization: Bearer wch_YOUR_KEY" \
  "https://www.wolfofcapitolhill.com/api/v1/trades?format=csv&limit=100" > trades.csv

Columns, in order: id, politician_slug, politician_name, chamber, party, state, ticker, asset_name, asset_type, side, amount_bucket, amount_min, amount_max, trade_date, disclosed_at, filing_url, owner_type.

Null fields are empty strings, values are RFC-4180 quoted, and pagination works exactly as in JSON (limit + cursor still apply; the response is one page, not the whole feed). Note the CSV omits conflictSignal / conflictReason — use the JSON format when you need them.