Insider transactions
Paid plansPull insider purchases, sales, grants and option exercises from SEC Forms 3, 4 and 5, one row per filed transaction line.
GET /v1/insiders/{ticker} returns the transactions that company insiders report to the SEC on Forms 3, 4 and 5. Each row is one transaction line as the form states it, so a Form 4 that reports four trades returns four rows. Pass one or more tickers in the path, comma-separated, or pass entity_id instead: GET /v1/insiders?entity_id=1.
Rows are keyed to the issuing company. entity_id on every row is the issuer and meta.entity_id_is reads issuer, so both share classes of a dual-class company return the same rows. Tickers and entities explains how entity_id scope differs by endpoint.
Units:
sharesandshares_held_afterare share counts exactly as filed.transaction_priceis USD per share, as filed.transaction_valueisshares×transaction_price, in USD. It is null when the line carries no price.underlying_sharesis a count of underlying shares.conversion_or_exercise_priceis USD per underlying share.
Quantities are as filed
Share counts and prices are not adjusted for later splits. An Apple director's purchase on 2000-10-25 reads 5600 shares at 18.81 USD per share, the figures on the form.
Insider transactions are available on Pro and higher plans. A Free key receives 402.
Two eras
Rows come from two eras, split by filing date. source on every row names the era, and meta.archive_era gives the boundary:
archive: forms filed from 1983-02-10 throughmeta.archive_era.through,2005-11-30. Coverage is broad from 1986.filing: forms filed on or aftermeta.archive_era.seam,2005-12-01, read from the SEC's Form 3, 4 and 5 data.
The split is by filing date, so a transaction dated before 2005-12-01 on a form filed after it is a filing row.
The two eras fill some fields differently:
document_idis the SEC accession number on afilingrow, for example0001140361-26-037020, and the archive's numeric document number on anarchiverow, for example31254007.reporting_ownerslists every reporting person on afilingrow, with the relationship flags and title from the form. Anarchiverow lists one person, withis_director,is_officer,is_ten_percent_ownerandofficer_titlenull.reporting_owners[].owner_cikis the person's SEC CIK on afilingrow and the archive's own person number on anarchiverow. Arthur D. Levinson reads9202on his 2000 rows and1214128, his SEC CIK, on his 2026 rows.source_quality_codeappears onarchiverows only.rule_10b5_1_affirmedis null onarchiverows.insider_roleon anarchiverow comes from the archive's role codes, which include labels such asSenior Vice PresidentandOfficer / Director.
An archive-era row:
curl -s -H "X-API-Key: YOUR_API_KEY" \
"https://api.xfinlink.com/v1/insiders/AAPL?start=2000-01-01&end=2000-12-31&limit=3"{
"tickers": ["AAPL"],
"data": [
...
{
"entity_id": 1,
"ticker": "AAPL",
"entity_name": "APPLE INC",
"transaction_date": "2000-10-25",
"filing_date": "2000-11-13",
"form_type": "4",
"insider_name": "LEVINSON ARTHUR D",
"insider_role": "Director",
"officer_title_as_filed": null,
"transaction_code": "P",
"transaction_type": "open_market_buy",
"acquisition_or_disposition": "A",
"shares": 5600,
"shares_held_after": 5600,
"transaction_price": 18.81,
"transaction_value": 105336,
"ownership_type": "direct",
"is_amendment": false,
"document_id": "31254007",
"is_derivative": false,
"source": "archive",
"source_quality_code": "R",
"is_current": true,
"security_title": "COM",
"is_weekend_dated": false,
"is_dated_after_own_filing": false,
"rule_10b5_1_affirmed": null,
"issuer_link_method": "windowed",
"reporting_owners": [
{
"owner_cik": 9202,
"owner_name": "LEVINSON ARTHUR D",
"is_director": null,
"is_officer": null,
"is_ten_percent_owner": null,
"officer_title": null
}
]
},
...
],
"data_through": "2000-11-13",
"count": 3,
"next_cursor": "djJ8ZXlKeUlqb2lhVzV6YVdSbGNuTWlMQ0p4SWpvaWFGSjZjbkZYV1hGUFpISXpNSEowT0U4eU1YUkRRU0lzSW5BaU9qSXNJbXNpT2lKTmFrRjNUVU13ZUUxRE1IbE9XSGQ2VFZSSk1VNUVRWGRPTTNkM1prUkZkeUo5fHg2M0JPd3dhTWlHQTFUNEcwSUJKNXc=",
"meta": {
"entity_id_is": "issuer",
"amendment_view": "current",
"derivative_lines": "excluded",
"uncoded_rows_excluded": 4,
"archive_era": {"through": "2005-11-30", "seam": "2005-12-01"},
"unmapped_codes": 0,
"unlinked_filings_included": 0,
...
"has_more": true,
"next_cursor": "djJ8ZXlKeUlqb2lhVzV6YVdSbGNuTWlMQ0p4SWpvaWFGSjZjbkZYV1hGUFpISXpNSEowT0U4eU1YUkRRU0lzSW5BaU9qSXNJbXNpT2lKTmFrRjNUVU13ZUUxRE1IbE9XSGQ2VFZSSk1VNUVRWGRPTTNkM1prUkZkeUo5fHg2M0JPd3dhTWlHQTFUNEcwSUJKNXc="
}
}Amendment versions
include_amendments selects which versions of an amended filing you receive. It has three states:
- Omitted: the current view. Each amendment chain contributes the rows of the filing in force, which carry
is_current: true.meta.amendment_viewreadscurrent. true, in any letter case: every filed version. Superseded rows carryis_current: false.meta.amendment_viewreadsall.false, in any letter case: original filings only, with no/Aforms.meta.amendment_viewreadsoriginals.- Any other non-empty value returns
400.
On 2024-08-06 a General Electric officer filed a Form 4 (0000040545-24-000182) with two lines and, the same day, a Form 4/A (0000040545-24-000184) that restates it with one line.
curl -s -H "X-API-Key: YOUR_API_KEY" \
"https://api.xfinlink.com/v1/insiders/GE?start=2024-08-03&end=2024-08-03&insider_name=procacci&include_amendments=true"{
"tickers": ["GE"],
"data": [
{"transaction_date": "2024-08-03", "filing_date": "2024-08-06", "form_type": "4/A", "transaction_code": "M", "shares": 10779, "shares_held_after": 20289, "transaction_price": 0, "is_amendment": true, "document_id": "0000040545-24-000184", "is_current": true, ...},
{"transaction_date": "2024-08-03", "filing_date": "2024-08-06", "form_type": "4", "transaction_code": "F", "shares": 4635, "shares_held_after": 20309, "transaction_price": 162.86, "is_amendment": false, "document_id": "0000040545-24-000182", "is_current": false, ...},
{"transaction_date": "2024-08-03", "filing_date": "2024-08-06", "form_type": "4", "transaction_code": "M", "shares": 10799, "shares_held_after": 24944, "transaction_price": 0, "is_amendment": false, "document_id": "0000040545-24-000182", "is_current": false, ...}
],
"count": 3,
...
"meta": {"amendment_view": "all", ...}
}The same request in each view:
- Omitted: 1 row, the Form 4/A line (
10779shares). include_amendments=true: 3 rows, the Form 4/A line and both original lines.include_amendments=false: 2 rows, the two original lines (4635and10799shares).
Derivative lines
By default you receive lines from the form's non-derivative table only, and meta.derivative_lines reads excluded. Pass include_derivatives=true to add lines from the derivative table, such as options and restricted stock units. They carry is_derivative: true and five more fields: underlying_security_title, underlying_shares, conversion_or_exercise_price, exercise_date and expiration_date.
A conversion appears on both tables: the derivative line gives up the units and the non-derivative line receives the shares. Summing shares across both counts the same event twice.
curl -s -H "X-API-Key: YOUR_API_KEY" \
"https://api.xfinlink.com/v1/insiders/AAPL?start=2026-09-15&end=2026-09-15&include_derivatives=true"{
"tickers": ["AAPL"],
"data": [
{
"entity_id": 1,
"ticker": "AAPL",
"entity_name": "APPLE INC",
"transaction_date": "2026-09-15",
"filing_date": "2026-09-17",
"form_type": "4",
"insider_name": "Newstead Jennifer",
"insider_role": "Officer",
"officer_title_as_filed": "SVP, GC and Government Affairs",
"transaction_code": "M",
"transaction_type": "option_exercise",
"acquisition_or_disposition": "D",
"shares": 30104,
"shares_held_after": 180624,
"transaction_price": null,
"transaction_value": null,
"ownership_type": "direct",
"is_amendment": false,
"document_id": "0001140361-26-037020",
"is_derivative": true,
"source": "filing",
"is_current": true,
"security_title": "Restricted Stock Unit",
"underlying_security_title": "Common Stock",
"underlying_shares": 30104,
"conversion_or_exercise_price": null,
"exercise_date": null,
"expiration_date": null,
...
},
{"transaction_code": "F", "transaction_type": "tax_withholding", "acquisition_or_disposition": "D", "shares": 16228, "transaction_price": 331.34, "transaction_value": 5376985.52, "is_derivative": false, "security_title": "Common Stock", ...},
{"transaction_code": "M", "transaction_type": "option_exercise", "acquisition_or_disposition": "A", "shares": 30104, "transaction_price": null, "transaction_value": null, "is_derivative": false, "security_title": "Common Stock", ...},
{"transaction_code": "S", "transaction_type": "open_market_sell", "acquisition_or_disposition": "D", "shares": 1438, "transaction_price": 330.19, "transaction_value": 474813.22, "is_derivative": false, "security_title": "Common Stock", ...}
],
"count": 4,
...
"meta": {"derivative_lines": "included", ...}
}Without include_derivatives, the same request returns the three non-derivative lines.
Parameters
tickerstr (path)Required unless entity_id is setOne or more tickers, comma-separated: /v1/insiders/AAPL,MSFT. Each resolves to its issuer. Up to 100 per request on Pro, 500 on Max, 5,000 on Redistribution.
entity_idint | strDefault: noneOne id, or several comma-separated, in place of ticker: ?entity_id=1. An issuer id or a share-class id; a share-class id is served as its issuer, so 10003635 (the AAPL share class) returns the same rows as 1. Cannot be combined with a ticker in the path. Counts toward the same per-request cap.
startstrDefault: noneEarliest transaction_date, YYYY-MM-DD, inclusive. Omit it for no lower bound. The Python client's insiders() sends a start 365 days before end, or before today, when you omit it.
endstrDefault: noneLatest transaction_date, YYYY-MM-DD, inclusive.
transaction_typestrDefault: noneOne or more labels, comma-separated, lower case: open_market_buy, open_market_sell, grant_or_award, option_exercise, tax_withholding, gift, sale_to_issuer, conversion_of_derivative, transaction_by_trust, tender_of_shares, acquisition_by_will, discretionary, expiration_of_long_derivative, exercise_of_out_of_the_money_derivative, expiration_of_short_derivative, voluntary_early_report, equity_swap, small_acquisition, reportable_transaction, deposit_into_voting_trust, decreased_holdings, other. other selects code J only. An unknown label is ignored with a warning; a list with no known label returns 400.
acquisition_or_dispositionstrDefault: noneA (acquired) or D (disposed of), upper case.
ownership_typestrDefault: nonedirect or indirect, lower case.
form_typestrDefault: noneOne or more of 3, 4, 5, 3/A, 4/A, 5/A, comma-separated. An unknown form is ignored with a warning; a list with no known form returns 400.
insider_rolestrDefault: noneCase-insensitive substring of any reporting person's insider_role or additional roles, for example ceo or director. % and _ match those characters.
insider_namestrDefault: noneCase-insensitive substring of any reporting person's name, for example cook. Matches every person on a joint filing, not only the first. % and _ match those characters.
min_valuenumberDefault: noneMinimum shares × transaction_price, in USD. Must be 0 or more. Lines without a price do not match.
include_amendmentsstrDefault: omittedOmitted: the filing in force for each amendment chain. true: every filed version. false: originals only. Both are read in any letter case; any other non-empty value returns 400. The Python client's insiders() sends false unless you pass include_amendments=None.
include_derivativesboolDefault: falsetrue adds derivative-table lines and false leaves them out; both are read in any letter case, and any other non-empty value returns 400.
include_uncodedboolDefault: falsetrue adds archive-era rows that carry no SEC transaction code. They read transaction_code: null and transaction_type: "other". true and false are read in any letter case; any other non-empty value returns 400.
fieldsstrDefault: the 12 default fieldsComma-separated. Selectable: insider_name, insider_role, transaction_code, transaction_type, acquisition_or_disposition, shares, shares_held_after, transaction_price, transaction_value, ownership_type, is_amendment, document_id (the default 12), plus insider_role_other and sequence_in_filing (opt-in). Every other row field is always returned. An unknown name is ignored with a warning; a list with no valid name returns 400.
limitintDefault: 1000Rows per page, up to 5,000. A larger whole number, up to nine digits, returns 5,000 rows; 0, a negative or a non-numeric value returns 400.
cursorstrDefault: noneThe next_cursor value from the previous page, passed back unchanged.
Response
The response is not the {data, meta} shape of the prices and fundamentals endpoints. data, data_through, count, next_cursor and warnings sit at the top level, with meta beside them:
{
"tickers": ["AAPL"],
"data": [ ... ],
"data_through": "2026-06-17",
"count": 3,
"next_cursor": "djJ8ZXlKeUlqb2lhVzV6YVdSbGNuTWlMQ0p4SWpvaWFXRmpjRVl6YjFKZlMxaEtaa014VlVoa2FUZzRaeUlzSW5BaU9qSXNJbXNpT2lKTmFrRjVUbWt3ZDA1VE1IZFBTSGQzVFVSQmVFMVVVWGROZWxsNFRGUkpNa3hVUVhsTlJHY3pUVmgzZDJaRVJUMGlmUXw4amsyUS1kbHZnd1BaWUx2N252a193",
"meta": { ... }
}Top-level fields
| field | type | unit | nullable | description |
|---|---|---|---|---|
tickers | list[str] | no | The tickers in the path, upper-cased. An empty list on an entity_id request. | |
entity_ids | list[int] | no | The ids you passed. Present on entity_id requests only. | |
entity_ids_unresolved | list[int] | no | Ids that matched nothing. Present on entity_id requests only. | |
tickers_unresolved | list[str] | no | Tickers that matched nothing, when others resolved. Present only when non-empty. | |
historical_resolution | object | no | Present when a ticker resolved to a company other than its current holder. Keyed by ticker: entity_id (the entity the ticker resolved to), current_entity_id (the ticker's holder today, or null), as_of (the date the ticker was resolved on) and via (the step that matched: requested_date, window_end, window_last_occupant, window_start or last_holder). | |
historical_resolution_note | str | no | A fixed explanation, present with historical_resolution. | |
data | list[object] | no | The rows. See the row fields below. | |
data_through | str | date | yes | The latest filing_date on this page. Null when data is empty. |
count | int | rows | no | Rows on this page. |
next_cursor | str | yes | Pass as cursor for the next page. Null on the last page. meta.next_cursor holds the same value. | |
warnings | list[str] | no | Present only when there is something to report: an ignored parameter value, such as Unknown transaction_type: buy; a parameter the endpoint does not read; a ticker that named several share classes of one company, such as BRK named more than one share class on that date; served at the company level; or a ticker in a list that named more than one company, such as SFN names more than one company; request by entity_id to choose one. | |
meta | object | no | See the meta fields below. |
Row fields
| field | type | unit | nullable | description |
|---|---|---|---|---|
entity_id | int | no | The issuer. | |
ticker | str | yes | The ticker you requested for this issuer. On entity_id requests, the ticker of the share class you sent or, for an issuer id, of the issuer's primary listed class (see Tickers and entities). | |
entity_name | str | no | The issuer's name. | |
transaction_date | str | date | no | Transaction date as filed, YYYY-MM-DD. |
filing_date | str | date | no | Date the SEC received the form. |
form_type | str | no | 3, 4, 5, 3/A, 4/A or 5/A. | |
insider_name | str | yes | Name of the first reporting person, as filed. Reporting persons are ordered by owner_cik. Default field. | |
insider_role | str | no | Role category of the first reporting person. Filing era: CEO, CFO, COO, CTO, Chairman, President, Vice President, General Counsel, Officer, Director, 10% Owner or Other, derived from the officer title and the relationship boxes. Archive era: the archive's role label, such as Senior Vice President or Officer / Director. Default field. | |
officer_title_as_filed | str | yes | The first reporting person's officer title as filed. | |
insider_role_other | str | yes | The first reporting person's additional roles, joined with ; , for example Director. Opt-in through fields. | |
transaction_code | str | yes | The SEC Form 4 transaction code, for example S or M. Null on archive rows whose code is not an SEC code. Default field. | |
transaction_type | str | no | Label for transaction_code, one of the 22 transaction_type values. A null code reads other. Default field. | |
acquisition_or_disposition | str | yes | A or D. Default field. | |
shares | number | shares | yes | Shares in the transaction, as filed. Default field. |
shares_held_after | number | shares | yes | Shares held after the transaction, as filed. Default field. |
transaction_price | number | USD per share | yes | Price per share, as filed. Default field. |
transaction_value | number | USD | yes | shares × transaction_price. Default field. |
ownership_type | str | yes | direct or indirect. Default field. | |
is_amendment | bool | no | True when the row comes from an amendment. Default field. | |
document_id | str | no | Filing era: the SEC accession number. Archive era: the archive's document number. Default field. | |
sequence_in_filing | int | no | The line's sequence number within its document. Opt-in through fields. | |
is_derivative | bool | no | True for a line from the form's derivative table. | |
source | str | no | filing or archive. | |
source_quality_code | str | no | Archive rows only: the one-letter quality grade the archive assigns to the row, served as stated: A, C, H, I, L, R, S or Y. | |
is_current | bool | no | True when the row belongs to the filing in force for its amendment chain. | |
security_title | str | yes | The security's title as filed, for example Common Stock or Restricted Stock Unit. | |
underlying_security_title | str | yes | Derivative lines only: the underlying security's title as filed. | |
underlying_shares | number | shares | yes | Derivative lines only: underlying shares. |
conversion_or_exercise_price | number | USD per underlying share | yes | Derivative lines only: conversion or exercise price. |
exercise_date | str | date | yes | Derivative lines only: date the derivative becomes exercisable. |
expiration_date | str | date | yes | Derivative lines only: expiration date. |
nature_of_ownership | str | no | Present only when the form states it, usually on indirect holdings, for example By Family Trusts. | |
is_weekend_dated | bool | no | True when the filed transaction date is a Saturday or Sunday. | |
is_dated_after_own_filing | bool | no | True when the filed transaction date is later than filing_date. | |
rule_10b5_1_affirmed | bool | yes | True when the form marks the transaction as made under a Rule 10b5-1 plan. Null where the form carries no such statement, including every archive row. | |
issuer_link_method | str | yes | How the filing reached its issuer. Filing era: open_claim (the issuer's SEC CIK is on record for this company without a date range), windowed (on record for a date range that covers the filing) or ticker_as_filed (reached by the ticker the filing states, on its own filing date). Archive era: windowed (the security identifier on the row is on record for a date range that covers the filing), censored (no recorded range covers it; exactly one security has ever carried the identifier, with a record that runs to the end of the recorded history) or unique (exactly one security has ever carried the identifier, with a record that starts after the filing). | |
reporting_owners | list[object] | no | Every reporting person on the form. See the reporting owner fields below. |
Reporting owner fields
| field | type | unit | nullable | description |
|---|---|---|---|---|
owner_cik | int | yes | Filing era: the person's SEC CIK. Archive era: the archive's own person number. | |
owner_name | str | yes | Name as filed. | |
is_director | bool | yes | Director box checked. Null on archive rows. | |
is_officer | bool | yes | Officer box checked. Null on archive rows. | |
is_ten_percent_owner | bool | yes | 10% owner box checked. Null on archive rows. | |
officer_title | str | yes | Officer title as filed. Null on archive rows. |
Meta fields
| field | type | unit | nullable | description |
|---|---|---|---|---|
entity_id_is | str | no | Always issuer. | |
amendment_view | str | no | current, all or originals, from include_amendments. | |
derivative_lines | str | no | included or excluded, from include_derivatives. | |
uncoded_rows_excluded | int | rows | no | Archive rows matching the request that were left out because they carry no SEC transaction code. 0 when include_uncoded=true. |
archive_era | object | no | through: the last filing date of the archive era. seam: the first filing date of the filing era. | |
unmapped_codes | int | rows | no | Archive rows on this page with transaction_code: null. |
unlinked_filings_included | int | filings | no | Filings on this page reached by the ticker the filing states (issuer_link_method: "ticker_as_filed"). |
knowledge_time | str | UTC timestamp | yes | When the newest data in the response became known. See Response metadata. |
as_of | str | date | no | end if you passed it, otherwise start. Absent when you passed neither. |
freshness | list[object] | no | One entry per dataset used: insider_transactions, insider_owners, insider_filings and insider_transactions_historical, each with dataset, through and promoted_at. | |
has_more | bool | no | true when another page follows. | |
next_cursor | str | yes | Pass as cursor for the next page. The same value as the top-level next_cursor. Null on the last page. |
Pagination
A page holds up to limit rows: 1,000 by default, 5,000 at most. Rows are ordered by transaction_date descending, then document_id descending, derivative lines before non-derivative lines, then line sequence descending. The order holds across both eras.
When more rows match, meta.has_more is true and next_cursor, at the top level of the body and in meta, carries a token. Pass it back as cursor with the same path and parameters. On the last page meta.has_more is false and next_cursor is null. One query can run to 50 pages on Pro, 100 on Max and 200 on Redistribution. Pagination covers cursors in general.
The Python client's insiders() returns one page per call, up to 5,000 rows. Page with cursor over REST to read further.
Errors
| status | error code | when it happens | how to fix |
|---|---|---|---|
400 | bad_request | A date is not a real YYYY-MM-DD date, or end is before start. | Pass a valid calendar date, with end on or after start. |
400 | bad_request | include_amendments, include_derivatives or include_uncoded is a non-empty value other than true or false, or limit is not a whole number from 1 to 999,999,999. | Pass true or false, and a limit of 1 or more. |
400 | bad_request | No transaction_type or form_type value is recognised. | Use the values in the parameters table. |
400 | bad_request | acquisition_or_disposition, ownership_type or min_value is out of range. | Pass A or D; direct or indirect; a number of 0 or more. |
400 | bad_request | No fields name is valid. | Use the selectable field names. |
400 | bad_request | Both a path ticker and entity_id, or an entity_id that is not a positive integer. | Pass one or the other. |
400 | bad_request | More tickers than your plan allows. | Split the request. |
400 | bad_request | cursor was not issued for this request: it is not a next_cursor value, it has been altered, or it came from another path, a changed parameter or another endpoint. | Pass next_cursor unchanged with the same path and parameters, or repeat the request without cursor. |
401 | unauthorized | The key is missing or invalid. | Send X-API-Key. See Authentication. |
402 | upgrade_required | The key is on the Free plan. | Upgrade to Pro. |
404 | not_found | No ticker or id matched. | Check the symbol with Search, or pass entity_id. |
404 | not_found | The ticker names a company with no listed security on the dates tried. | Pass the issuer's entity_id. |
409 | ambiguous_ticker | The ticker named more than one company on the resolved date, and nothing else resolved, for example SFN on 2009-06-30. hint reads pass entity_id=. | Pass one of the candidates as entity_id. |
429 | see Rate limits | A quota is exhausted. | Wait for the window to reset. |
Real bodies:
{"error":"bad_request","code":"bad_request","status":400,"detail":"Invalid start date format (YYYY-MM-DD)"}
{"error":"bad_request","code":"bad_request","status":400,"detail":"No valid transaction_type values in: buy,sell"}
{"error":"bad_request","code":"bad_request","status":400,"detail":"No valid form_type values in: 144"}
{"error":"bad_request","code":"bad_request","status":400,"detail":"acquisition_or_disposition must be 'A' or 'D'"}
{"error":"bad_request","code":"bad_request","status":400,"detail":"ownership_type must be 'direct' or 'indirect'"}
{"error":"bad_request","code":"bad_request","status":400,"detail":"min_value must be a non-negative number"}
{"error":"bad_request","code":"bad_request","status":400,"detail":"No valid fields requested. Invalid: foo, _bar"}
{"error":"bad_request","code":"bad_request","status":400,"detail":"Provide either a ticker in the path or an entity_id parameter, not both."}
{"error":"bad_request","code":"bad_request","status":400,"detail":"Invalid entity_id: 'abc'. Must be a positive integer."}
{"error":"bad_request","code":"bad_request","status":400,"detail":"Maximum 100 tickers per request"}
{"error":"bad_request","code":"bad_request","status":400,"detail":"Invalid cursor: not a cursor this API issued, or one from an earlier paging scheme. Repeat the request without cursor to start from the first page."}{"error":"unauthorized","code":"unauthorized","status":401,"detail":"No API key was sent. Pass your key in the X-API-Key header or the ?api_key= query parameter. Get one free at https://xfinlink.com/signup","message":"No API key was sent. Pass your key in the X-API-Key header or the ?api_key= query parameter. Get one free at https://xfinlink.com/signup"}{"error":"upgrade_required","code":"upgrade_required","status":402,"detail":"Insider transactions are available on Pro. https://xfinlink.com/pricing"}{"error":"not_found","code":"not_found","status":404,"detail":"No matching entities for: ZZZZQ"}The 404 for a company with no listed security reads {"error":"not_found","code":"not_found","status":404,"detail":"No listed security for: <ticker>"}.
SFN named two different companies on 2009-06-30. /v1/insiders/SFN?start=2009-06-30&end=2009-06-30 returns 409, and candidates lists the share-class ids that carried the ticker on that date:
{"error":"ambiguous_ticker","code":"ambiguous_ticker","status":409,"detail":"SFN names more than one company. Request by entity_id to choose one.","candidates":{"SFN":[10022947,10034604]},"hint":"pass entity_id="}When one ticker in a list fails and another resolves, you get 200: an unknown ticker is listed in tickers_unresolved, and an ambiguous ticker or one with no listed security is reported in warnings.
Plan differences
- Free:
402. A date,limit,include_amendments,include_derivatives,include_uncodedorcursorvalue that is refused returns its400first. - Pro: full history, up to 100 tickers per request, 50 pages per query.
- Max: full history, up to 500 tickers per request, 100 pages per query.
- Redistribution: full history, up to 5,000 tickers per request, 200 pages per query.
Each ticker or entity_id in a request counts as one unit against your daily quota. A Free key's 402 does not count. See Plans and limits.
The same request on each plan:
curl -s -H "X-API-Key: YOUR_API_KEY" "https://api.xfinlink.com/v1/insiders/AAPL"{"error":"upgrade_required","code":"upgrade_required","status":402,"detail":"Insider transactions are available on Pro. https://xfinlink.com/pricing"}On Pro the same request returns 200 with the first 1,000 rows, newest first.
Edge cases
Share classes
GOOGL and GOOG return the same rows, because both resolve to Alphabet's issuer id 31223. A share-class entity_id is served as its issuer. ?entity_id=10003635 (the AAPL share class) and ?entity_id=1 (Apple's issuer id) return the same transactions with the same values and labels: ticker reads AAPL and entity_name APPLE INC, the labels of Apple's primary listed class (see Tickers and entities). entity_ids echoes the id you sent.
curl -s -H "X-API-Key: YOUR_API_KEY" "https://api.xfinlink.com/v1/insiders?entity_id=10003635&start=2026-09-01&end=2026-09-24&limit=2"{
"tickers": [],
"entity_ids": [10003635],
"entity_ids_unresolved": [],
"data": [
{"entity_id": 1, "ticker": "AAPL", "entity_name": "APPLE INC", "transaction_date": "2026-09-22", "insider_name": "Newstead Jennifer", "transaction_type": "open_market_sell", "shares": 2399, "document_id": "0001140361-26-037584", ...},
{"entity_id": 1, "ticker": "AAPL", "entity_name": "APPLE INC", "transaction_date": "2026-09-15", "insider_name": "Newstead Jennifer", "transaction_type": "tax_withholding", "shares": 16228, "document_id": "0001140361-26-037020", ...}
],
"data_through": "2026-09-24",
"count": 2,
...
"meta": {"entity_id_is": "issuer", ...}
}Recycled tickers
A ticker resolves on the dates of your window. GM with a 2008 window resolves to General Motors Corp (entity_id 4), not today's General Motors (5), and historical_resolution says so:
curl -s -H "X-API-Key: YOUR_API_KEY" "https://api.xfinlink.com/v1/insiders/GM?start=2008-01-01&end=2008-12-31&limit=1"{
"tickers": ["GM"],
"historical_resolution": {
"GM": {"entity_id": 4, "current_entity_id": 5, "as_of": "2008-12-31", "via": "window_end"}
},
"historical_resolution_note": "Resolved to a previous holder of the ticker: the requested date window ends before the ticker's current holder acquired it. Pass entity_id to pin an entity explicitly.",
"data": [
{"entity_id": 4, "ticker": "GM", "entity_name": "GENERAL MOTORS CORP", "transaction_date": "2008-09-02", "insider_name": "Osborne Robert Stephen", "transaction_type": "sale_to_issuer", "shares": 8333, "transaction_price": 10.58, ...}
],
...
}A window from 2008-06-30 to 2010-06-30 ends between the two companies' listings and resolves through via: "window_last_occupant" to the same entity_id 4.
Filings reached by their stated ticker
Some filings name an issuer that carries no link of its own. Such a filing is included when the ticker it states named exactly one security of the requested company on its filing date. Its rows read issuer_link_method: "ticker_as_filed", and meta.unlinked_filings_included counts those filings on the page. Google Inc's filings from 2005 to 2015 reach Alphabet this way:
curl -s -H "X-API-Key: YOUR_API_KEY" "https://api.xfinlink.com/v1/insiders/GOOGL?start=2010-01-01&end=2010-12-31&limit=2"{
"tickers": ["GOOGL"],
"data": [
{"entity_id": 31223, "ticker": "GOOGL", "entity_name": "ALPHABET INC", "transaction_date": "2010-12-16", "insider_name": "Arora Nikesh", "transaction_type": "open_market_sell", "shares": 607, "transaction_price": 592.85, "document_id": "0001127602-10-030943", "security_title": "Class A Common Stock", "issuer_link_method": "ticker_as_filed", ...},
...
],
...
"meta": {"unlinked_filings_included": 1, ...}
}Joint filings
A form filed by several people returns one row per transaction line, with every person in reporting_owners. insider_name and insider_role describe the first person by owner_cik. insider_name as a filter matches any of them: insider_name=berkshire finds Occidental Petroleum rows whose first owner is Warren Buffett.
curl -s -H "X-API-Key: YOUR_API_KEY" "https://api.xfinlink.com/v1/insiders/OXY?start=2022-01-01&insider_name=berkshire&limit=1"{
"tickers": ["OXY"],
"data": [
{
"entity_id": 5451,
"ticker": "OXY",
"entity_name": "OCCIDENTAL PETROLEUM CORP",
"transaction_date": "2025-02-07",
"filing_date": "2025-02-11",
"insider_name": "BUFFETT WARREN E",
"insider_role": "10% Owner",
"transaction_type": "open_market_buy",
"shares": 763017,
"shares_held_after": 264941431,
"transaction_price": 46.82,
"transaction_value": 35724455.94,
"ownership_type": "indirect",
"nature_of_ownership": "See footnotes",
"reporting_owners": [
{"owner_cik": 315090, "owner_name": "BUFFETT WARREN E", "is_director": false, "is_officer": false, "is_ten_percent_owner": true, "officer_title": null},
{"owner_cik": 1067983, "owner_name": "BERKSHIRE HATHAWAY INC", "is_director": false, "is_officer": false, "is_ten_percent_owner": true, "officer_title": null}
],
...
}
],
...
}Dates as filed
transaction_date is the date the filer wrote. start and end filter on it, so a row appears in the window its filed date falls in. A row whose filed transaction date is later than its filing_date carries is_dated_after_own_filing: true, and one dated on a Saturday or Sunday carries is_weekend_dated: true.
Uncoded archive rows
Some archive rows carry no SEC transaction code, for example the holdings statement on a Form 3. They are left out by default and counted in meta.uncoded_rows_excluded. include_uncoded=true adds them:
curl -s -H "X-API-Key: YOUR_API_KEY" "https://api.xfinlink.com/v1/insiders/AAPL?start=2000-01-01&end=2000-12-31&include_uncoded=true"{
"tickers": ["AAPL"],
"data": [
...
{"entity_id": 1, "ticker": "AAPL", "transaction_date": "2000-07-31", "filing_date": "2000-08-23", "form_type": "3", "insider_name": "LEVINSON ARTHUR D", "transaction_code": null, "transaction_type": "other", "acquisition_or_disposition": null, "shares": null, "shares_held_after": 19600, "ownership_type": "direct", "document_id": "31199284", "source": "archive", "source_quality_code": "Y", ...},
...
],
"count": 113,
...
"meta": {"uncoded_rows_excluded": 0, "unmapped_codes": 4, ...}
}The same window without include_uncoded reports "uncoded_rows_excluded": 4.
Tickers with no filings
A security whose issuer files no Forms 3, 4 or 5 returns 200 with an empty data array. SPY returns "data": [], "count": 0 and "data_through": null.
Request examples
Apple's open-market sales by insiders in the first half of 2026, three rows:
import xfinlink as xfl
xfl.set_api_key("YOUR_API_KEY")
df = xfl.insiders(
"AAPL",
start="2026-01-01",
end="2026-06-30",
transaction_type="open_market_sell",
include_amendments=None,
limit=3,
)
print(df[["ticker", "transaction_date", "insider_name", "insider_role",
"shares", "transaction_price", "transaction_value"]].to_string(index=False))curl -s -H "X-API-Key: YOUR_API_KEY" \
"https://api.xfinlink.com/v1/insiders/AAPL?start=2026-01-01&end=2026-06-30&transaction_type=open_market_sell&limit=3"Show me the three most recent open-market sales of Apple stock by insiders between January and June 2026.ticker transaction_date insider_name insider_role shares transaction_price transaction_value
AAPL 2026-06-16 Borders Ben Officer 116 295.14 34236.24
AAPL 2026-05-27 LEVINSON ARTHUR D Director 50000 311.02 15551000.00
AAPL 2026-05-08 Borders Ben Officer 1274 290.00 369460.00{
"tickers": ["AAPL"],
"data": [
{
"entity_id": 1,
"ticker": "AAPL",
"entity_name": "APPLE INC",
"transaction_date": "2026-06-16",
"filing_date": "2026-06-17",
"form_type": "4",
"insider_name": "Borders Ben",
"insider_role": "Officer",
"officer_title_as_filed": "Principal Accounting Officer",
"transaction_code": "S",
"transaction_type": "open_market_sell",
"acquisition_or_disposition": "D",
"shares": 116,
"shares_held_after": 38713,
"transaction_price": 295.14,
"transaction_value": 34236.24,
"ownership_type": "direct",
"is_amendment": false,
"document_id": "0001140361-26-025620",
"is_derivative": false,
"source": "filing",
"is_current": true,
"security_title": "Common Stock",
"is_weekend_dated": false,
"is_dated_after_own_filing": false,
"rule_10b5_1_affirmed": true,
"issuer_link_method": "open_claim",
"reporting_owners": [
{
"owner_cik": 2100523,
"owner_name": "Borders Ben",
"is_director": false,
"is_officer": true,
"is_ten_percent_owner": false,
"officer_title": "Principal Accounting Officer"
}
]
},
{
"entity_id": 1,
"ticker": "AAPL",
"entity_name": "APPLE INC",
"transaction_date": "2026-05-27",
"filing_date": "2026-05-29",
"form_type": "4",
"insider_name": "LEVINSON ARTHUR D",
"insider_role": "Director",
"officer_title_as_filed": null,
"transaction_code": "S",
"transaction_type": "open_market_sell",
"acquisition_or_disposition": "D",
"shares": 50000,
"shares_held_after": 3764576,
"transaction_price": 311.02,
"transaction_value": 15551000,
"ownership_type": "direct",
"is_amendment": false,
"document_id": "0001140361-26-023363",
"is_derivative": false,
"source": "filing",
"is_current": true,
"security_title": "Common Stock",
"is_weekend_dated": false,
"is_dated_after_own_filing": false,
"rule_10b5_1_affirmed": false,
"issuer_link_method": "open_claim",
"reporting_owners": [
{
"owner_cik": 1214128,
"owner_name": "LEVINSON ARTHUR D",
"is_director": true,
"is_officer": false,
"is_ten_percent_owner": false,
"officer_title": null
}
]
},
{
"entity_id": 1,
"ticker": "AAPL",
"entity_name": "APPLE INC",
"transaction_date": "2026-05-08",
"filing_date": "2026-05-12",
"form_type": "4",
"insider_name": "Borders Ben",
"insider_role": "Officer",
"officer_title_as_filed": "Principal Accounting Officer",
"transaction_code": "S",
"transaction_type": "open_market_sell",
"acquisition_or_disposition": "D",
"shares": 1274,
"shares_held_after": 38713,
"transaction_price": 290,
"transaction_value": 369460,
"ownership_type": "direct",
"is_amendment": false,
"document_id": "0001140361-26-020871",
"is_derivative": false,
"source": "filing",
"is_current": true,
"security_title": "Common Stock",
"is_weekend_dated": false,
"is_dated_after_own_filing": false,
"rule_10b5_1_affirmed": true,
"issuer_link_method": "open_claim",
"reporting_owners": [
{
"owner_cik": 2100523,
"owner_name": "Borders Ben",
"is_director": false,
"is_officer": true,
"is_ten_percent_owner": false,
"officer_title": "Principal Accounting Officer"
}
]
}
],
"data_through": "2026-06-17",
"count": 3,
"next_cursor": "djJ8ZXlKeUlqb2lhVzV6YVdSbGNuTWlMQ0p4SWpvaWFXRmpjRVl6YjFKZlMxaEtaa014VlVoa2FUZzRaeUlzSW5BaU9qSXNJbXNpT2lKTmFrRjVUbWt3ZDA1VE1IZFBTSGQzVFVSQmVFMVVVWGROZWxsNFRGUkpNa3hVUVhsTlJHY3pUVmgzZDJaRVJUMGlmUXw4amsyUS1kbHZnd1BaWUx2N252a193",
"meta": {
"entity_id_is": "issuer",
"amendment_view": "current",
"derivative_lines": "excluded",
"uncoded_rows_excluded": 0,
"archive_era": {
"through": "2005-11-30",
"seam": "2005-12-01"
},
"unmapped_codes": 0,
"unlinked_filings_included": 0,
"knowledge_time": "2026-09-27T04:02:06Z",
"as_of": "2026-06-30",
"freshness": [
{"dataset": "insider_transactions", "through": "2026-09-25", "promoted_at": "2026-09-27T04:56:08Z"},
{"dataset": "insider_owners", "through": "2026-09-25", "promoted_at": "2026-09-27T04:41:10Z"},
{"dataset": "insider_filings", "through": "2026-09-25", "promoted_at": "2026-09-27T04:35:43Z"},
{"dataset": "insider_transactions_historical", "through": "2005-11-30", "promoted_at": "2026-09-18T19:34:36Z"}
],
"has_more": true,
"next_cursor": "djJ8ZXlKeUlqb2lhVzV6YVdSbGNuTWlMQ0p4SWpvaWFXRmpjRVl6YjFKZlMxaEtaa014VlVoa2FUZzRaeUlzSW5BaU9qSXNJbXNpT2lKTmFrRjVUbWt3ZDA1VE1IZFBTSGQzVFVSQmVFMVVVWGROZWxsNFRGUkpNa3hVUVhsTlJHY3pUVmgzZDJaRVJUMGlmUXw4amsyUS1kbHZnd1BaWUx2N252a193"
}
}{"tool": "get_insiders", "arguments": {"ticker": "AAPL", "start": "2026-01-01", "end": "2026-06-30", "transaction_type": "open_market_sell", "limit": 3}}
{
"tickers": ["AAPL"],
"data": [
{
"entity_id": 1,
"ticker": "AAPL",
"entity_name": "APPLE INC",
"transaction_date": "2026-06-16",
"filing_date": "2026-06-17",
"form_type": "4",
"insider_name": "Borders Ben",
"insider_role": "Officer",
"officer_title_as_filed": "Principal Accounting Officer",
"transaction_code": "S",
"transaction_type": "open_market_sell",
"acquisition_or_disposition": "D",
"shares": 116,
"shares_held_after": 38713,
"transaction_price": 295.14,
"transaction_value": 34236.24,
"ownership_type": "direct",
"is_amendment": false,
"document_id": "0001140361-26-025620",
"is_derivative": false,
"source": "filing",
"is_current": true,
"security_title": "Common Stock",
"is_weekend_dated": false,
"is_dated_after_own_filing": false,
"rule_10b5_1_affirmed": true,
"issuer_link_method": "open_claim",
"reporting_owners": [
{
"owner_cik": 2100523,
"owner_name": "Borders Ben",
"is_director": false,
"is_officer": true,
"is_ten_percent_owner": false,
"officer_title": "Principal Accounting Officer"
}
]
},
...
],
"data_through": "2026-06-17",
"count": 3,
"next_cursor": "djJ8ZXlKeUlqb2lhVzV6YVdSbGNuTWlMQ0p4SWpvaWFXRmpjRVl6YjFKZlMxaEtaa014VlVoa2FUZzRaeUlzSW5BaU9qSXNJbXNpT2lKTmFrRjVUbWt3ZDA1VE1IZFBTSGQzVFVSQmVFMVVVWGROZWxsNFRGUkpNa3hVUVhsTlJHY3pUVmgzZDJaRVJUMGlmUXw4amsyUS1kbHZnd1BaWUx2N252a193",
"meta": {
"entity_id_is": "issuer",
"amendment_view": "current",
"derivative_lines": "excluded",
"uncoded_rows_excluded": 0,
"archive_era": {"through": "2005-11-30", "seam": "2005-12-01"},
"unmapped_codes": 0,
"unlinked_filings_included": 0,
"knowledge_time": "2026-09-27T04:02:06Z",
"as_of": "2026-06-30",
"freshness": [
{"dataset": "insider_transactions", "through": "2026-09-25", "promoted_at": "2026-09-27T04:56:08Z"},
{"dataset": "insider_owners", "through": "2026-09-25", "promoted_at": "2026-09-27T04:41:10Z"},
{"dataset": "insider_filings", "through": "2026-09-25", "promoted_at": "2026-09-27T04:35:43Z"},
{"dataset": "insider_transactions_historical", "through": "2005-11-30", "promoted_at": "2026-09-18T19:34:36Z"}
],
"has_more": true,
"next_cursor": "djJ8ZXlKeUlqb2lhVzV6YVdSbGNuTWlMQ0p4SWpvaWFXRmpjRVl6YjFKZlMxaEtaa014VlVoa2FUZzRaeUlzSW5BaU9qSXNJbXNpT2lKTmFrRjVUbWt3ZDA1VE1IZFBTSGQzVFVSQmVFMVVVWGROZWxsNFRGUkpNa3hVUVhsTlJHY3pUVmgzZDJaRVJUMGlmUXw4amsyUS1kbHZnd1BaWUx2N252a193"
}
}The tool result's text is the same JSON body as the curl response.
Was this page helpful?
Thank you for helping improve xfinlink documentation.
- Need help? Get in touch.
- Building with an LLM? Read llms.txt.
- Using Claude or ChatGPT? Connect the MCP server.