/insider-module/api/insiders/transactions/searchSearch insider transactions with advanced filters.
Search insider transactions with advanced filters. Each row includes total_beneficial_ownership and sector/industry classification from Sharadar.
Why use this
Common use case
Multi-criteria insider-transaction search — the workhorse endpoint for screeners that combine ticker + role + value + sector filters. Each row carries total_beneficial_ownership (sum across all ownership vehicles per insider per company) and Sharadar sector/industry classification. Use dedup_owners=true to collapse joint-filer rows (PE LP+GP+manager, 13D groups, SPAC sponsors) into one canonical row per economic transaction — see v3.17.0 changelog for partition keys. For ticker-only history use GET /insider-module/api/insiders/transactions/by-ticker/{ticker}; for cluster signals use GET /insider-module/api/insiders/clusters.
Parameters
| Name | In | Required | Default | Allowed | Description | Example |
|---|---|---|---|---|---|---|
| query | query | required | — | — | REQUIRED free-text search (min 2 chars), matched case-insensitively in ONE field (`ILIKE '%query%'`) against ticker symbol, company name, AND insider name — e.g. `AAPL`, `Apple`, or `Buffett`. There is no separate `ticker`/`insider_name` param; this single field covers all three. | AAPL |
| filed_at_days | query | optional | 7 | — | Look back this many days by FILING date (when the Form 4 landed on EDGAR). Default 7, range 1–3650. | 30 |
| transaction_days | query | optional | — | — | Look back this many days by TRANSACTION (trade-execution) date. Range 1–365. Omit to bound only by filing date. | 30 |
| transaction_code | query | optional | — | — | Filter by raw SEC Form 4 transaction code (`P` purchase, `S` sale, `A` grant, `M` exercise, …); comma-separated for multiple. For the normalized 6-bucket version use `standard_type`. | P |
| max_value | query | optional | — | — | Maximum dollar value (`shares × price_per_share`). | 5000000 |
| is_officer | query | optional | — | — | When `true`, restrict to Section 16 officers. | true |
| is_director | query | optional | — | — | When `true`, restrict to directors. | true |
| is_ten_percent_owner | query | optional | — | — | When `true`, restrict to 10% beneficial owners. | true |
| exclude_10b5_1 | query | optional | false | — | When `true`, exclude pre-planned Rule 10b5-1 trades (keep only discretionary activity). | true |
| exclude_cashless | query | optional | false | — | When `true`, exclude cashless option exercises. | true |
| exclude_sell_to_cover | query | optional | false | — | When `true`, exclude RSU sell-to-cover (tax-withholding) sales. | true |
| standard_type | query | optional | — | purchase, sale, grant, exercise, gift, other | Normalized transaction type — accepts `purchase`, `sale`, `grant`, `exercise`, `gift`, `other`. This is FinRadar's mapping of the SEC's 10+ Form 4 transaction codes (P, S, A, M, G, F, etc.) into 6 buckets analysts actually filter on. Omit to include all types. | purchase |
| min_value | query | optional | — | — | Minimum dollar value (`shares × price_per_share`) — rows with null price (code A grants) are EXCLUDED when this is set. Use to focus on material trades; `1000000` removes most exercise-and-immediate-sale noise. Always combined with the `dedup_owners=true` flag for trading-flow analysis to avoid double-counting joint-filer rows. | 1000000 |
| is_c_suite | query | optional | — | — | When `true`, restricts to C-suite officers (CEO/CFO/COO/CIO/CTO/General Counsel) — heuristic match against the `officer_title` field. Setting `false` is treated the same as omitting (i.e. NOT a 'non-C-suite-only' filter; it's an opt-in narrowing). Useful for screening insider conviction signals where lower-rank insider trades are noisier. | true |
| limit | query | optional | 50 | — | Maximum rows returned (default 50, capped at 1000 server-side). Combine with `filed_at_days`/`transaction_days` to widen the window; the endpoint does not currently support cursor pagination so for full backfills prefer date-range chunking over `offset` pagination. | 20 |
| sector | query | optional | — | — | Sharadar sector classification, case-sensitive (e.g. `Technology`, `Healthcare`, `Financial Services`, `Industrials`, `Consumer Cyclical`). Joins via `cusip → ticker → Sharadar SF1 sector`. Rows whose ticker has no Sharadar mapping are excluded when this filter is set. | Technology |
| industry | query | optional | — | — | Sharadar industry classification, case-sensitive (more specific than `sector` — e.g. `Software—Application`, `Biotechnology`, `Semiconductors`). Use the `/financials/tickers` endpoint to enumerate exact valid values, since some Sharadar industry strings contain em-dashes that must be URL-encoded. | Consumer Electronics |
| dedup_owners | query | optional | false | — | Opt-in server-side joint-filer dedup (introduced v3.17.0). When `true`, collapses joint-filer rows (PE LP+GP+manager, 13D groups, SPAC sponsors) into one canonical row per economic transaction and exposes `co_owners` (JSON array) + `co_owner_count` (int). Eliminates the +112-223% aggregate-flow inflation observed across joint Form 4 filings. When `false` or omitted, response is byte-identical to pre-3.17.0 (no new keys appear). | true |
Response schema
| Field | Type | Nullable | Description |
|---|---|---|---|
| status | string | no | Always `success` on a 2xx response. |
| data | array | no | Array of matching transaction rows, ordered by `transaction_date DESC` (most recent first), tie-broken by `transaction_id DESC`. Empty array when no rows match — never null. One row per `(transaction × reporting_owner)` pair by default; one row per economic transaction when `dedup_owners=true`. |
| data[].transaction_id | integer | no | Stable internal primary key from the `insiders_transactions` table. When `dedup_owners=true` this is the canonical winner of the joint-filer dedup partition (deterministic by lowest `transaction_id` across the joint group). Stable across re-runs and re-parses — safe to use as a deduplication key on the client side. |
| data[].ticker | string | no | Issuer ticker (the company whose insider is trading), normalized to canonical hyphen form (e.g. `BRK-A`, `GOOG-L`). For multi-class issuers, the class actually traded on the Form 4 is preserved — NOT collapsed to the primary share class. |
| data[].insider_name | string | no | Reporting-person legal name as filed on Form 4 (Item 1). May be an individual or an entity (LP, fund vehicle, trust). Casing is preserved verbatim from the filing — do NOT use this as a join key; use `insider_cik` instead. For canonical resolution across name variants, see `/insider-module/api/insider/search`. |
| data[].insider_cik | string | no | SEC-issued reporting-person CIK as a 10-character zero-padded string. Same insider may file at multiple companies — combine `insider_cik + ticker` for per-issuer position tracking. Use as the join key against `/api/v1/ownership/holders/{uuid}/filing-history` once you've resolved CIK → unified-holder UUID. |
| data[].shares | number | no | Share count for the transaction (split-adjusted to most recent split via Sharadar's split-adjustment factor). For derivative transactions (exercise/grant of options), this is the number of underlying shares — NOT the option contract count. Always positive; direction (acquired vs disposed) is encoded in `acquired_disposed_code`. |
| data[].price_per_share | number | yes | Per-share transaction price in USD (Form 4 Item 5 column 4). Null for code-A grants and code-G gifts where there is no consideration. Already split-adjusted to match the `shares` field. For derivative transactions, this is the strike or exercise price, not the spot price of the underlying. |
| data[].transaction_value | number | yes | Computed `shares × price_per_share` in USD (rounded to nearest cent). Null when `price_per_share` is null (grants/gifts have no dollar value). Useful for `min_value` filtering and aggregate-flow analysis — combine with `dedup_owners=true` to avoid joint-filer double-counting. |
| data[].transaction_date | string | no | ISO `YYYY-MM-DD` date the trade was executed (Form 4 Item 3, NOT the filing acceptance date). For the date the filing was disclosed publicly, see the parent filing's `filed_date`. Trade dates can pre-date filing dates by up to 2 business days under the SEC's filing window. |
| data[].total_beneficial_ownership | number | yes | Aggregate shares owned by this insider across ALL ownership vehicles (direct + indirect trusts, LLCs, joint accounts) for this issuer, AS OF this transaction. Computed from the `shares_owned_following` field plus a roll-up across vehicles. Null when the underlying filing does not report ownership (rare). Use this as a conviction proxy: a $5M sale that's 60% of holdings ≠ a $5M sale that's 2% of holdings. |
| data[].sector | string | yes | Sharadar sector classification for the issuer (e.g. `Technology`, `Healthcare`, `Financial Services`). Null when the ticker is unmapped in Sharadar (private CUSIPs, recently-listed issuers, foreign issuers without ADRs). |
| data[].industry | string | yes | Sharadar industry classification (more specific than `sector` — e.g. `Software—Application`, `Biotechnology`, `Semiconductors`). Null when unmapped. Em-dash characters are preserved verbatim — be careful with URL encoding when round-tripping. |
| data[].co_owners | array | yes | Present only when `dedup_owners=true`. JSON array of joint-filer co-owners collapsed into this canonical row, each entry shape `{name, cik, is_officer, is_director, is_ten_percent_owner}`. Use to surface 'this trade was filed jointly by 3 entities' in UIs, or to enumerate the legal participants for compliance audit. |
| data[].co_owner_count | integer | yes | Length of `co_owners` array. Present only when `dedup_owners=true`. A value of `1` means there were no joint filers (single owner). Values ≥2 mean a joint filing — `2` is the most common (LP+GP), but PE filings with `count: 9+` exist (e.g. LGN Form 4 with $514M × 9 owners). |
| meta | object | no | Result metadata block: pagination state plus a verbatim echo of the applied filters. Use it to drive UI page counters AND to confirm server-side parameter coercion (e.g. ticker normalization to canonical hyphen form is reflected in `meta.applied_filters.ticker` if returned). |
| meta.total | integer | no | Total matching rows for the full filter set, computed via a parallel `COUNT(*)` query (NOT just the size of the returned page). Use for UI page counters; for cursor-only iteration the per-page array length is sufficient. |
| meta.limit | integer | no | Effective page size after server-side capping. Mirrors the `limit` query parameter when it was within bounds, OR is set to the server-side cap (currently 1000) when the requested limit exceeded the cap. Always check this rather than echoing the requested limit. |
Sample response
- "status": "success"
- "data":
- "meta":
- "total": 14
- "limit": 100
Errors
| Status | Label | Description |
|---|---|---|
| 200 | OK | Request succeeded. |
| 400 | Bad Request | Invalid query, body, or path parameter. |
| 401 | Unauthorized | Missing or invalid Authorization header / api_Token. |
| 402 | Payment Required | Insufficient token balance for this call. Top up |
| 429 | Too Many Requests | Rate limit exceeded for your tier (see /pricing for tier limits). Tier limits |
| 500 | Server Error | Unexpected server-side failure. Retry with backoff; report if persistent. |
Code samples
curl "https://api.finradar.ai/insider-module/api/insiders/transactions/search?api_Token=YOUR_API_KEY" \
-H "Authorization: Bearer YOUR_JWT_TOKEN"Generate an API key in /account/credentials to run live queries (literal YOUR_API_KEY placeholder shown until then).