Metadata-Version: 2.4
Name: insider-trades-api
Version: 0.2.2
Summary: Official Python SDK for the Insider Trades API — real-time SEC Form 3, 4, and 5 insider transaction data.
Project-URL: Homepage, https://insidertrades.us
Project-URL: Documentation, https://insidertrades.us/docs
Project-URL: Pricing, https://insidertrades.us/pricing
Author: GoodTech LLC
License-Expression: Apache-2.0
License-File: LICENSE
Keywords: api-client,edgar,financial-data,fintech,form-3,form-4,form-5,insider-trading,insider-transactions,quantitative-finance,sec
Classifier: Development Status :: 4 - Beta
Classifier: Intended Audience :: Developers
Classifier: Intended Audience :: Financial and Insurance Industry
Classifier: License :: OSI Approved :: Apache Software License
Classifier: Operating System :: OS Independent
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.8
Classifier: Programming Language :: Python :: 3.9
Classifier: Programming Language :: Python :: 3.10
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Programming Language :: Python :: 3.13
Classifier: Topic :: Office/Business :: Financial :: Investment
Classifier: Typing :: Typed
Requires-Python: >=3.8
Description-Content-Type: text/markdown

# Insider Trades API — Python SDK

Official Python SDK for the [Insider Trades API](https://insidertrades.us) — real-time SEC Form 3, 4, and 5 insider transaction data.

> **Using Claude, Cursor, ChatGPT, or another AI assistant?** Use the [insider-trades-mcp](https://www.npmjs.com/package/insider-trades-mcp) package instead — it connects your AI tool directly to the Insider Trades API with no code required.
>
> **Using JavaScript or TypeScript?** See the [insider-trades-api Node.js SDK](https://www.npmjs.com/package/insider-trades-api) on npm.

## Installation

```bash
pip install insider-trades-api
```

Requires Python 3.8+. No runtime dependencies.

## Quick Start

```python
import os
from insider_trades_api import InsiderTradesAPI

client = InsiderTradesAPI(api_key=os.environ["INSIDER_TRADES_API_KEY"])

# Get recent insider purchases for Apple
result = client.get_insider_transactions(
    issuer_ticker="AAPL",
    transaction_types="purchase",
    limit=10,
)

for tx in result["insiderTransactions"]:
    owner = tx.get("reportingOwnerInformation", {})
    print(owner.get("name"), tx.get("purchaseAmount"))
```

If you omit `api_key`, the client reads `INSIDER_TRADES_API_KEY` from the environment.

Get your API key at [insidertrades.us](https://insidertrades.us).

---

## API Reference

For the full reference including all parameters, response schemas, and plan limits, see [insidertrades.us/docs](https://insidertrades.us/docs).

### `InsiderTradesAPI(api_key=None, *, timeout=30.0)`

| Argument | Type | Required | Description |
|---|---|---|---|
| `api_key` | `str` | Yes | Your API key. Falls back to `INSIDER_TRADES_API_KEY` env var |
| `timeout` | `float` | No | Per-request socket timeout in seconds (default `30.0`) |

---

### `get_insider_transactions(**params)`

Retrieve SEC insider transactions from Form 3, 4, and 5 filings. All arguments are keyword-only. Returns the decoded JSON response as a `dict` with `insiderTransactions`, `count`, `recordedTimeInUtc`, `hasMore`, and (when `hasMore` is `True`) `nextCursor`.

```python
result = client.get_insider_transactions(
    issuer_ticker="AAPL",
    transaction_types=["purchase", "sale"],
    filing_date_in_est_start_date="2026-01-01",
    filing_date_in_est_end_date="2026-01-31",
    limit=50,
)
print(result["count"], len(result["insiderTransactions"]))
```

| Parameter | Type | Description |
|---|---|---|
| `filing_id` | `str` | Direct lookup by filing ID |
| `issuer_ticker` | `str` | Filter by ticker symbol, e.g. `"AAPL"` |
| `issuer_cik` | `str` | Filter by issuer CIK |
| `reporting_owner_cik` | `str` | Filter by insider CIK |
| `accession_number` | `str` | Filter by SEC accession number |
| `form_types` | `str \| Sequence[str]` | Form types: `"3"`, `"4"`, `"5"` (default: all) |
| `transaction_types` | `str \| Sequence[str]` | See transaction types below |
| `owner_roles` | `str \| Sequence[str]` | `"director"`, `"officer"`, `"tenPercentOwner"` |
| `officer_titles` | `str \| Sequence[str]` | Normalized titles: `"CEO"`, `"CFO"`, `"COO"`, etc. |
| `filing_date_in_est_start_date` | `str` | Filing date start `YYYY-MM-DD` (Eastern Time) |
| `filing_date_in_est_end_date` | `str` | Filing date end `YYYY-MM-DD` (Eastern Time) |
| `period_of_report_start_date` | `str` | Period of report start `YYYY-MM-DD` |
| `period_of_report_end_date` | `str` | Period of report end `YYYY-MM-DD` |
| `min_total_amount` | `float` | Minimum total dollar value |
| `max_total_amount` | `float` | Maximum total dollar value |
| `fieldset` | `"minimal" \| "standard" \| "full"` | Control response size (see below) |
| `limit` | `int` | Page size, default `100`, max `750` |
| `cursor` | `str` | Opaque pagination cursor — pass back the `nextCursor` from a previous response (see [Pagination](#pagination)) |

#### Transaction types

| Value | SEC Code | Description |
|-------|----------|-------------|
| `"purchase"` | P | Open market purchase |
| `"sale"` | S | Open market sale |
| `"grant"` | A | Grant or award |
| `"gift"` | G | Bona fide gift |
| `"exercise"` | M | Option exercise (Rule 16b-3) |
| `"derivativeExercise"` | O, X | Derivative exercise |
| `"disposition"` | D | Disposition to issuer |
| `"discretionary"` | I | Discretionary transaction |
| `"derivativeConversion"` | C | Conversion of derivative |
| `"derivativeExpiration"` | E, H | Expiration of derivative |
| `"smallAcquisition"` | L | Small acquisition (Rule 16a-6) |
| `"inheritance"` | W | Inheritance |
| `"equitySwap"` | K | Equity swap |
| `"tender"` | U | Tender offer / change of control |
| `"other"` | J | Other acquisition / disposition |

#### Fieldsets

| Fieldset | Fields included |
|---|---|
| `"minimal"` | ID, issuer, owner, key amounts, dates |
| `"standard"` | All of minimal + all aggregates, boolean flags, links, AI summary |
| `"full"` | All of standard + raw transaction arrays (`nonDerivativeTransactions`, `derivativeTransactions`, holdings) |

Default (no `fieldset`): all stored fields are returned. `minimal` and `standard` produce significantly smaller payloads — recommended for bulk queries.

**Sample response:**

```json
{
  "insiderTransactions": [
    {
      "id": "97e823b724619e921c68ba73b2f95f3b015fb83cc05666320b6ddf34b97cdcbe",
      "formType": "4",
      "accessionNumber": "0001140361-26-023363",
      "issuerCik": "320193",
      "issuerInformation": {
        "cik": "0000320193",
        "tradingSymbol": "AAPL",
        "companyName": "Apple Inc."
      },
      "reportingOwnerCik": "1214128",
      "reportingOwnerInformation": {
        "cik": "0001214128",
        "name": "LEVINSON ARTHUR D",
        "city": "CUPERTINO",
        "state": "CA",
        "isDirector": true,
        "isOfficer": false
      },
      "ownerRoles": "director",
      "filingDateInEst": "2026-05-29",
      "periodOfReport": "2026-05-27",
      "totalAmount": 15551000.0,
      "saleAmount": 15551000.0,
      "saleCount": 1,
      "netSharesAcquired": -50000.0,
      "netTradingAmount": -15551000.0,
      "hasSales": "true",
      "hasLateTransactions": false,
      "aff10b5One": false,
      "summary": "Arthur D. Levinson sold 50,000 shares of Apple Inc. common stock at $311.02 per share on May 27, 2026.",
      "linkToFilingDetail": "https://www.sec.gov/Archives/edgar/data/1214128/000114036126023363/0001140361-26-023363-index.htm"
    }
  ],
  "count": 1,
  "recordedTimeInUtc": "2026-05-29T22:30:00Z",
  "hasMore": false
}
```

---

### `iter_insider_transactions(**params)`

Auto-paginating generator that yields individual transactions across **all** pages, following `nextCursor` for you. Accepts the same filters as `get_insider_transactions` (the cursor is managed internally). Iteration is lazy — pages are fetched on demand.

```python
# Walk an entire year without managing cursors yourself.
for tx in client.iter_insider_transactions(
    filing_date_in_est_start_date="2025-01-01",
    filing_date_in_est_end_date="2025-12-31",
    limit=750,  # larger page size = fewer requests against your quota
):
    print(tx["id"], tx.get("totalAmount"))
```

---

## Pagination

A single response holds at most `limit` records (capped at **750** to stay within the API's response-size limit). When more results remain, the response sets `"hasMore": true` and includes an opaque `nextCursor`.

**Easiest:** let the SDK walk pages for you with [`iter_insider_transactions`](#iter_insider_transactionsparams).

**Manual:** pass `nextCursor` back as `cursor`, keeping the **same** filter arguments. A cursor minted for one set of filters is rejected (HTTP 400) if replayed against different ones.

```python
cursor = None
while True:
    page = client.get_insider_transactions(
        issuer_cik="320193",
        period_of_report_start_date="2025-01-01",
        period_of_report_end_date="2025-12-31",
        limit=750,
        cursor=cursor,
    )
    for tx in page["insiderTransactions"]:
        ...
    if not page["hasMore"]:
        break
    cursor = page["nextCursor"]
```

Each page is a separate request and counts against your monthly quota — prefer a large `limit` (up to 750) on big walks to minimize request count.

---

## Usage examples

### Recent Form 4 purchases by date range

```python
result = client.get_insider_transactions(
    transaction_types="purchase",
    form_types="4",
    filing_date_in_est_start_date="2026-05-01",
    filing_date_in_est_end_date="2026-05-31",
    limit=50,
)
```

### High-value transactions over $1M

```python
result = client.get_insider_transactions(
    min_total_amount=1_000_000,
    transaction_types="purchase",
    filing_date_in_est_start_date="2026-05-01",
    filing_date_in_est_end_date="2026-05-31",
    limit=25,
)
```

### All transactions by a specific insider

```python
result = client.get_insider_transactions(reporting_owner_cik="1214128", limit=20)
```

### CEO transactions across all companies

```python
result = client.get_insider_transactions(
    officer_titles=["CEO"],
    form_types="4",
    filing_date_in_est_start_date="2026-05-01",
    filing_date_in_est_end_date="2026-05-31",
    limit=20,
)
```

### Look up a specific filing

```python
result = client.get_insider_transactions(accession_number="0001140361-26-023363")
```

---

## Typing

The package ships with type hints (`py.typed`). Responses are plain `dict`s; `TypedDict` definitions describe their shape for editors and type checkers.

```python
from insider_trades_api import (
    InsiderTransaction,
    InsiderTransactionsResponse,
    IssuerInformation,
    ReportingOwnerInformation,
    NonDerivativeTransaction,
    DerivativeTransaction,
    NonDerivativeHolding,
    DerivativeHolding,
    Footnote,
    OwnerSignature,
)
```

> **Note:** the `has*` flags (`hasPurchases`, `hasSales`, …) are returned as the string `"true"`, not a Python `bool`. Use truthiness checks (`if tx.get("hasPurchases"):`) rather than `== True`.

---

## Error handling

Client-side validation failures raise `ValueError` before any network call. Non-success HTTP responses raise `InsiderTradesAPIError`, which carries the HTTP `status`.

```python
from insider_trades_api import InsiderTradesAPI, InsiderTradesAPIError

try:
    result = client.get_insider_transactions(issuer_ticker="AAPL")
except InsiderTradesAPIError as err:
    print(err.status, err)  # e.g. 403 "InsiderTrades API error 403: Forbidden"
```

| Status | Meaning |
|---|---|
| 400 | Invalid parameters (bad date format, invalid CIK, inverted date range) |
| 403 | Invalid or missing API key, or requested date range exceeds plan limit |
| 429 | Rate limit exceeded — retried automatically up to 3 times with backoff |
| 504 | Request timed out — retried automatically up to 3 times |
| 500 | Server error |

The SDK validates date format (`YYYY-MM-DD`), numeric CIK, and date range order before making any network request, so many errors are caught immediately without a round trip.

---

## Plans and limits

| Plan | Monthly requests | Historical depth | Rate limit |
|---|---|---|---|
| Free | 1,000 | 1 year | 2 req/s |
| Pro | 100,000 | 10 years | 10 req/s |

The SDK retries automatically on 429 and 504 responses (up to 3 attempts, respects the `Retry-After` header).

---

## Changelog

### [0.1.0] - 2026-06-05

- Initial release: `get_insider_transactions()` with full query parameter support
- Filters: issuer_ticker, issuer_cik, reporting_owner_cik, transaction_types, owner_roles, officer_titles, date ranges, min_total_amount, max_total_amount, fieldset
- Retry logic for 429 and 504 with backoff
- Client-side input validation for date format, CIK format, and date range order
- Full type hints (`py.typed`) including transaction arrays, holdings, and boolean flags
- Zero runtime dependencies (stdlib only)

---

## Resources

- Docs: [insidertrades.us/docs](https://insidertrades.us/docs)
- Pricing: [insidertrades.us/pricing](https://insidertrades.us/pricing)
- Dashboard: [insidertrades.us/dashboard](https://insidertrades.us/dashboard)
- Support: [insidertrades.us](https://insidertrades.us)

---

## Legal disclaimer

The data provided through this SDK is for **informational purposes only** and does not constitute investment advice, financial advice, trading advice, or any other type of advice. GoodTech LLC makes no representations as to the accuracy, completeness, or timeliness of the data. You are solely responsible for your use of the data. Past filings and transactions do not predict future performance. Always consult a qualified financial professional before making investment decisions.

---

Licensed under the [Apache 2.0 License](./LICENSE). Copyright 2026 GoodTech LLC.
