Documentation

Authentication, request examples, error codes, and billing. Download the Markdown file to share.

AkkruData API & MCP — User Guide

This document describes the /data and /metric HTTP APIs: request and response fields, HTTP status codes, credit usage, and rate limits. It is intended for application integrators.

Base URL: https://api.akkrudata.ai/api/v1

Endpoint paths in this guide are appended to that prefix (for example, POST …/data/filings means POST https://api.akkrudata.ai/api/v1/data/filings).


Table of Contents

SectionLink
1. Conventions
└ Authentication
└ Success and error payloads
└ Credits
└ Rate limiting
└ Examples Disclaimer
└ Filing caveats
└ Workflow budgets
└ History truncation notice
└ Coverage scope notice
└ Industry classification (Pro+)
2. Credit summary
3. Rate limits
4. Data API
POST /data/filings
POST /data/company
GET /data/company/list
POST /data/line-items
POST /data/facts
POST /data/statement
POST /data/filing-statements
└ Statement endpoints (/data/income-statement, /comprehensive-income, /balance-sheet, /cash-flow-statement, /equity-statement)
POST /data/facts/dimensional-breakdown
POST /data/line-items/dimensional-breakdown
POST /data/compare/line-items
POST /data/compare/facts
GET …/excel
5. Metrics API
└ Response conventions
└ Supported metric catalog
POST /metric/filings
POST /metric/all
POST /metric/all/filing-date
POST /metric/items
POST /metric/historical
└ Category endpoints (/metric/profitability, /growth, /financial-health, /efficiency, /cash-flow, /valuation, /valuation/filing-date)
6. Screener API
POST /screener/metrics
GET /screener/metrics/filters
└ Filter DSL (/screener/metrics)
└ Credit formula (/screener/metrics)
POST /screener/ownership
└ Filters (/screener/ownership)
└ Credit formula (/screener/ownership)
POST /screener/initial-holdings
POST /screener/institutional-holdings
└ Credit formula (/screener/institutional-holdings)
7. Ownership API
└ Transaction object
POST /ownership/transactions
POST /ownership/stats
POST /ownership/transaction-ids
GET /ownership/tickers
POST /ownership/names
GET /ownership/transaction-types
└ Holding object
POST /ownership/initial-holdings
POST /ownership/initial-holdings/stats
POST /ownership/initial-holding-ids
└ Snapshot object
└ Institutional holding object
POST /ownership/institutional-holdings/manager-history
POST /ownership/institutional-holdings/portfolio
POST /ownership/institutional-holdings/security
8. API key, account, and plan errors
9. Request limits (validation)
10. MCP access
└ Connect via OAuth
└ Connect via X-API-Key
└ Tool catalog

1. Conventions

1.1 Authentication

All requests to /data/*, /metric/*, /screener/*, and /ownership/* require:

HeaderValue
X-API-KeyYour API key (create and manage keys in the product dashboard after sign-in).

For POST requests with a JSON body, also send:

HeaderValue
Content-Typeapplication/json

1.2 Success and error payloads

Structured errors return JSON of the form:

{
  "detail": {
    "error_code": "SOME_CODE",
    "message": "Human-readable explanation."
  }
}

Validation errors (error_code: "VALIDATION_ERROR") additionally include a fields array describing each rejected input. Each entry has type (a stable code such as missing, extra_forbidden, int_parsing, string_too_long), loc (path to the field), msg (human text), and input (the value that failed). Use detail.message for a single-line summary and detail.fields if you need per-field structured detail.

Authentication failures use the same object form: 401 AUTH_API_KEY_MISSING (no X-API-Key or bearer token), 403 AUTH_API_KEY_INVALID (unknown or inactive key), 403 AUTH_USER_INACTIVE, 403 AUTH_EMAIL_NOT_VERIFIED. Every 4xx and 5xx response uses the object form above.

Plan-tier responses. A request may be rejected because the caller's plan does not include the requested endpoint or option. These return 403 with one of PLAN_TIER_INSUFFICIENT, PLAN_TIER_INSUFFICIENT_HISTORY, PLAN_TIER_INSUFFICIENT_FORMULA_OVERRIDE, or PLAN_TIER_INSUFFICIENT_COVERAGE. The detail body also carries required_tier (the lowest plan that would accept the request) and current_tier (the caller's current plan). See Section 8.

1.3 Credits

Credits are deducted from the account tied to your API key. Amounts and timing are listed under each endpoint and in Section 2. 402 Payment Required indicates insufficient credits for that operation.

1.4 Rate limiting

When limits are exceeded, the API returns 429 Too Many Requests with detail.error_code RATE_LIMIT_EXCEEDED. Limits apply per account across all API keys on that account.

1.5 Examples Disclaimer

Note: All request and response JSON examples in this documentation are provided for reference purposes only. They may be abbreviated or truncated for readability, and the exact structure or available fields are subject to change without prior notice.

1.6 Filing caveats

A filing may carry a free-text disclaimer about its extraction completeness — for example, when a portion of the original filing was deliberately excluded from the extracted facts. When present, the disclaimer surfaces in two places on every endpoint that returns filing information, facts, or statements:

  • A caveat field on the filing information itself (top-level for single-filing responses; per-row in results[] for compare endpoints; per-item in filings[] for the listing endpoint). Either null / absent (no caveat), or a string.
  • A _warnings entry of the form Filing <TICKER> <FORM> FY<YEAR>[ <QUARTER>] has caveat: <text>. Compare endpoints aggregate per-filing caveats into a single deduplicated _warnings list.

The caveat is informational and does not affect billing or response status.

1.7 Workflow budgets

Indicative credit ranges for common workflows, so you can size a plan before you start. Numbers assume the L1 tier on common line-item names (revenue, net income, operating income, etc.). Rarer or ambiguous names land at L2–L3 and cost more; see the tier list in §2.

WorkflowEndpoint patternTypical credits
Discover one company (identity + coverage map)POST /data/company8
List all filings for one company-yearPOST /data/filings10
Pull all three primary statements (income / balance / cash flow) for one filingPOST /data/income-statement + /balance-sheet + /cash-flow-statement84 (28 × 3)
Pull a few specific line items from one filing (3 items × L1)POST /data/line-items60 (3 × 20)
Five-year trend on one metric for one companyPOST /data/line-items × 5 filings, 1 item, L1100 (5 × 20)
Peer comparison: 5 companies × 1 metric × 1 year (L1)POST /data/compare/line-items100 (1 × 20 × 5)
All key metrics snapshot for one company (1 call)POST /metric/all148
Full dimensional breakdown of revenue for one filing (~50 slice facts)POST /data/line-items/dimensional-breakdown~120 (20 + 100)
Download one filing's Excel workbookGET /data/filings/{id}/excel300

Reference: a Starter plan (20,000 credits / month) covers about 330 three-item line-item queries, 240 three-statement pulls, or 135 /metric/all snapshots per month — pick the mix that fits your workflow.

1.8 History truncation notice

List, range, and discovery endpoints attach a generic _warnings entry when results would be larger on a higher plan. Affected endpoints: POST /data/filings, POST /data/company (the coverage map), POST /metric/filings, POST /metric/historical, POST /screener/metrics, and POST /ownership/transactions, POST /ownership/stats, POST /ownership/names, POST /screener/ownership, POST /ownership/initial-holdings, POST /ownership/initial-holdings/stats, POST /screener/initial-holdings (on filing_date). For /screener/metrics the lookback is additionally auto-clamped to your plan's window so you are only billed for the portion you can access. Single-filing endpoints (/data/facts, /data/statement, /data/line-items, etc.) instead return 403 PLAN_TIER_INSUFFICIENT_HISTORY when the requested filing is out of window. POST /ownership/transaction-ids lists out-of-window ids in restricted_ids and returns that 403 only when every id found is out of scope.

1.9 Coverage scope notice

Each plan covers a subset of companies. Single-company endpoints return 403 PLAN_TIER_INSUFFICIENT_COVERAGE with detail.required_tier when the requested company is outside your plan's scope. /ownership/* endpoints do this whenever the request is anchored on a ticker. List, discovery, /screener/metrics, /screener/ownership, /screener/initial-holdings, and /ownership/* requests not anchored on a ticker are silently filtered to your plan's scope and attach a generic _warnings entry when companies are excluded. POST /ownership/transaction-ids and POST /ownership/initial-holding-ids report out-of-scope ids in restricted_ids instead.

1.10 Industry classification (Pro+)

Pro-plan and higher responses attach an industry classification block per company on GET /data/company/list, POST /data/compare/line-items, POST /data/compare/facts, and POST /screener/metrics results. Sub-Pro callers receive the same responses without it; attaching it costs no extra credits.

"classification": {
  "sectors": ["Technology"],
  "source": { "scheme": "US_SIC", "code": "3571", "url": "https://www.sec.gov/search-filings/standard-industrial-classification-sic-code-list" }
}
FieldMeaning
sectorsOne or two of the 12 canonical buckets — primary first, plus an optional secondary when a code genuinely spans two.
source.schemeUS_SIC (US, SEC SIC), KR_KSIC (Korea, KSIC), JP_TSE33 (Japan, TSE 33-sector), or EU_ICB (Europe, ICB).
source.codeThe company's official industry code as filed.
source.urlOfficial page to look that code up.

The 12 canonical buckets: Technology, Healthcare, Finance, Consumer Discretionary, Consumer Staples, Communications, Industrials, Energy, Utilities, Materials, Real Estate, Other. POST /screener/metrics (§6.1) and POST /screener/ownership (§6.5) both accept a sectors filter over these.


2. Credit summary

Credit charges for /data, /metric, /screener, and /ownership are as follows.

EndpointCredits
POST /data/filings10 per successful debit. Debited even if the returned filings list is empty.
POST /data/company8 per successful debit. Debited even if DATA_COMPANY_NOT_FOUND is returned.
GET /data/company/list175 per successful debit.
POST /data/line-itemsSum over requested line items: tier L0=10, L1=20, L2=30, L3=50 per line item. If your balance is less than the full sum, you may be charged up to your remaining balance.
POST /data/factsceil(n / 5) × 10 where n is the number of deduplicated fact ids.
POST /data/statement (role_label mode)Tiered 28 / 48: 28 per debit, debited even if the filing is missing or nothing matches; the extra 20 of the higher (48-credit) tier may be capped at your remaining balance.
POST /data/statement (statement_type mode)28 flat per successful debit. Debited even if the filing is missing or has no block of this statement_type.
POST /data/filing-statements10 per successful debit. Debited even if the filing is missing.
POST /data/income-statement28 per successful debit. Debited even if the filing is missing or has no such statement.
POST /data/comprehensive-income28 per successful debit. Debited even if the filing is missing or has no such statement.
POST /data/balance-sheet28 per successful debit. Debited even if the filing is missing or has no such statement.
POST /data/cash-flow-statement28 per successful debit. Debited even if the filing is missing or has no such statement.
POST /data/equity-statement28 per successful debit. Debited even if the filing is missing or has no such statement.
POST /data/facts/dimensional-breakdownceil((1 + N) / 5) × 10 where N is the number of returned slice facts. 10 credits are debited on DATA_FACT_NOT_FOUND.
POST /data/line-items/dimensional-breakdownTier credit for line_item (L0=10 … L3=50) + ceil(N_total / 5) × 10 for returned slice facts. Partial billing applies.
POST /data/compare/line-itemsFor each line item, (tier credits) × (number of filings in the request). Same partial charging as POST /data/line-items when your balance is below the full price.
POST /data/compare/factsceil(total_deduplicated_ids / 5) × 10 across all filing rows.
GET /data/filings/{filing_id}/excel300 when the download is issued.
POST /metric/filings10
POST /metric/all148
POST /metric/all/filing-date148
POST /metric/items148
POST /metric/profitability148
POST /metric/growth148
POST /metric/financial-health148
POST /metric/efficiency148
POST /metric/cash-flow148
POST /metric/valuation148
POST /metric/valuation/filing-date148
POST /metric/historical55 base fee, plus 148 × (number of filing rows returned on the current page). Default page size is 3 filing rows max.
POST /screener/metricsDynamic per request: max(65, 425 − tickerDiscount − lookbackDiscount − quarterlyDiscount + lookbackSurcharge + filterSurcharge + temporalSurcharge + includeSurcharge). Range 89–1825. See §6.4 for the formula. Debited even if results are empty.
GET /screener/metrics/filters10 per call.
POST /ownership/transactions30 per page. Debited even if OWNERSHIP_COMPANY_NOT_FOUND is returned.
POST /ownership/stats40 base + ceil(n / 1000) × 5, where n is the number of participating transactions. The base is debited even if OWNERSHIP_COMPANY_NOT_FOUND is returned.
POST /ownership/transaction-idsceil(n / 5) × 10 where n is the number of deduplicated ids (max 200).
POST /screener/ownershipDynamic per request: max(65, 200 − tickerDiscount − shortWindowDiscount + fullHistorySurcharge + 40 × conditions). Range 65–920. See §6.7 for the formula. Debited even if results are empty.
GET /ownership/tickers175 per successful debit.
POST /ownership/names30 per successful debit. Debited even if OWNERSHIP_COMPANY_NOT_FOUND is returned.
GET /ownership/transaction-types0 — static catalog, no charge.
POST /ownership/initial-holdings30 per page. Debited even if OWNERSHIP_COMPANY_NOT_FOUND is returned.
POST /ownership/initial-holdings/stats40 base + ceil(n / 1000) × 5, where n is the number of participating holdings. The base is debited even if OWNERSHIP_COMPANY_NOT_FOUND is returned.
POST /ownership/initial-holding-idsceil(n / 5) × 10 where n is the number of deduplicated ids (max 200).
POST /screener/initial-holdingsDynamic per request, same formula as POST /screener/ownership (§6.7). Range 65–920. Debited even if results are empty.
POST /ownership/institutional-holdings/manager-history30 per successful debit. Debited even if OWNERSHIP_MANAGER_NOT_FOUND is returned.
POST /ownership/institutional-holdings/portfolio30 per page. Debited even if the manager or the quarter is not found.
POST /ownership/institutional-holdings/security30 per page (flat mode); 40 flat with group_by_quarter=true. Debited even if OWNERSHIP_SECURITY_NOT_FOUND is returned.
POST /screener/institutional-holdingsDynamic per request: max(65, 200 + 40 × conditions − narrowWindowDiscount + noWindowSurcharge). Range 160–720. See §6.10 for the formula. Debited even if results are empty.
GET /billing/balance0 — free balance check. Returns {"credits_balance": <int>} for the API key's account. Rate-limited at 30/minute.

Metrics resolution tiers (for /data/line-items and /data/compare/line-items): each requested label is classified into L0–L3, which sets that line item’s credit cost. The chosen tier is echoed on each result as _resolution_level ("L0" through "L3"). The response may include _correction and _warnings when resolution is non-trivial.


3. Rate limits

Per-account limits (requests per minute, per route):

MethodPathLimit
POST/data/filings120
POST/data/company120
GET/data/company/list120
POST/data/line-items100
POST/data/facts100
POST/data/statement120
POST/data/filing-statements120
POST/data/income-statement120
POST/data/comprehensive-income120
POST/data/balance-sheet120
POST/data/cash-flow-statement120
POST/data/equity-statement120
POST/data/facts/dimensional-breakdown60
POST/data/line-items/dimensional-breakdown60
POST/data/compare/line-items60
POST/data/compare/facts60
GET/data/filings/{filing_id}/excel20
POST/metric/filings100
POST/metric/all60
POST/metric/all/filing-date60
POST/metric/items60
POST/metric/profitability60
POST/metric/growth60
POST/metric/financial-health60
POST/metric/efficiency60
POST/metric/cash-flow60
POST/metric/valuation60
POST/metric/valuation/filing-date60
POST/metric/historical60
POST/screener/metrics10
GET/screener/metrics/filters60
POST/screener/ownership10
POST/ownership/transactions120
POST/ownership/stats120
POST/ownership/transaction-ids120
GET/ownership/tickers120
POST/ownership/names120
GET/ownership/transaction-types60
POST/ownership/initial-holdings120
POST/ownership/initial-holdings/stats120
POST/ownership/initial-holding-ids120
POST/screener/initial-holdings10
POST/ownership/institutional-holdings/manager-history120
POST/ownership/institutional-holdings/portfolio120
POST/ownership/institutional-holdings/security120
POST/screener/institutional-holdings10

4. Data API

Filing caveats apply to every endpoint in this section. When a filing carries a free-text disclaimer, it is echoed as a caveat field on the filing information and mirrored to the response's _warnings list. See §1.6 Filing caveats for the exact shape; per-endpoint sections below only call it out where the placement differs (lists, compare).


4.1 POST /data/filings

Purpose: List filings available for one company and one fiscal year, optionally filtered by form type and quarter.

Request:

FieldTypeRequiredNotes
tickerstringYes1–32 characters; matched case-insensitively.
fiscal_yearintegerYes1990–2100.
form_typestringNoMax 32 characters. US forms: 10-K, 10-Q. Foreign-issuer annual reports: 20-F (US-listed foreign companies), 40-F (Canadian filers). Korean (DART), Japanese (EDINET), European (ESEF) and China A-share filings use the same values — 10-K for the annual report, 10-Q for the quarterly report. If omitted, all forms for that ticker and year are considered.
quarterstringNoMax 4 characters (e.g. Q1). Use when you need a single quarterly filing among several.

Response:

FieldMeaning
credits_usedAlways 10 when successful.
fiscal_yearEcho of request.
form_typePresent only if you sent form_type.
quarterPresent only if you sent quarter.
companyCompany profile (ticker, cik, legal_name) or null if unknown.
filingsArray of filings: id, ticker, form_type, fiscal_year, quarter, total_facts, total_blocks, has_excel, caveat (see §1.6).

Optional amendment_context may appear on a filing item when restatement or amendment information is available (English summary and optional references).

Errors:

HTTPerror_codeWhen
402CREDITS_INSUFFICIENTNot enough credits.
422Validation (body rules).

Example Request:

{
  "ticker": "AAPL",
  "fiscal_year": 2024,
  "form_type": "10-K"
}

Example MCP tool call:

list_filings(ticker="AAPL", fiscal_year=2024, form_type="10-K")

Example Response:

{
  "credits_used": 10,
  "fiscal_year": 2024,
  "company": {
    "ticker": "AAPL",
    "cik": "0000320193",
    "legal_name": "Apple Inc."
  },
  "filings": [
    {
      "id": 12345,
      "ticker": "AAPL",
      "form_type": "10-K",
      "fiscal_year": 2024,
      "quarter": "FY",
      "total_facts": 1500,
      "total_blocks": 12,
      "has_excel": true
    }
  ]
}

4.2 POST /data/company

Purpose: Resolve one company by ticker, cik, dart_corp_code, or edinet_code and return its identity plus a coverage summary — every form_type × fiscal_year × quarter we hold for that issuer. Use this as the entry point when you only know a company name/ticker and need to discover what filings exist.

Request:

FieldTypeRequiredNotes
tickerstringConditionalExactly one of ticker, cik, dart_corp_code, or edinet_code must be provided. 1–32 characters; case-insensitive. European tickers are the composite form <ticker>_<country> (e.g. VIRI_F); China A-share tickers are <6-digit code>_CN (e.g. 600519_CN).
cikstringConditionalNumeric string; zero-padded to 10 digits on the server side. SEC-listed companies only.
dart_corp_codestringConditionalNumeric string; zero-padded to 8 digits on the server side. Korean DART-listed companies only.
edinet_codestringConditionalEDINET issuer code (E + 5 digits). Japanese EDINET-listed companies only.

Response:

FieldMeaning
ticker, cik, dart_corp_code, edinet_code, lei, uscc, legal_nameCompany identity. Only the applicable identifier is present — cik for SEC-listed companies, dart_corp_code for Korean companies, edinet_code for Japanese companies, lei for European companies, uscc (统一社会信用代码, 18 chars) for China A-share companies; the others are omitted. legal_name may be absent for rare records.
jurisdiction"US" for SEC-listed companies; "KR" for Korean DART-listed companies; "JP" for Japanese EDINET-listed companies; "EU" for European ESEF-listed companies; "CN" for China A-share companies.
sec_filings_urlEDGAR public browse URL for the company, derived from CIK. Omitted for companies with no CIK (e.g. Korean and Japanese companies).
dart_filings_urlDART public browse URL for the company, derived from dart_corp_code. Omitted for companies with no DART corp code (e.g. US and Japanese companies).
edinet_filings_urlEDINET public browse URL for the company, derived from edinet_code. Omitted for companies with no EDINET code (e.g. US and Korean companies).
esef_filings_urlfilings.xbrl.org public browse URL for the company, derived from lei. Omitted for companies with no LEI.
cninfo_filings_urlcninfo (巨潮资讯) public browse URL for the company, derived from the 6-digit stock code. Omitted for non-A-share companies.
filings_countTotal filings we hold for this company across all forms and years.
coverageObject keyed by filing-type name. US: SEC form names ("10-K", "10-Q", "20-F", "40-F"). KR / JP / EU / CN: jurisdiction-neutral labels ("annual", "quarterly"). Each value has fiscal_years (sorted list), earliest, latest, fiscal_year_quarters (year → list of quarter labels: "FY", "Q1""Q4"), and normalized_form — a uniform identifier ("annual" / "quarterly") you can use to iterate across jurisdictions without checking the key.
credits_usedAlways 8 when successful.

Charging: A DATA_COMPANY_NOT_FOUND response is still charged 8 credits.

Errors:

HTTPerror_codeWhen
404DATA_COMPANY_NOT_FOUNDNo company on file for the given identifier. Still debits 8 credits.
403PLAN_TIER_INSUFFICIENT_COVERAGEThe requested company is outside your plan's coverage scope.
402CREDITS_INSUFFICIENTNot enough credits.
422Validation (zero or more than one of ticker/cik/dart_corp_code/edinet_code supplied; non-numeric cik or dart_corp_code).

Example Request:

{
  "ticker": "AAPL"
}

Example MCP tool call:

lookup_company(ticker="AAPL")

Example Response:

{
  "ticker": "AAPL",
  "jurisdiction": "US",
  "cik": "0000320193",
  "legal_name": "Apple Inc.",
  "sec_filings_url": "https://www.sec.gov/cgi-bin/browse-edgar?action=getcompany&CIK=0000320193&type=&dateb=&owner=include&count=40",
  "filings_count": 12,
  "coverage": {
    "10-K": {
      "fiscal_years": [2020, 2021, 2022, 2023, 2024],
      "earliest": 2020,
      "latest": 2024,
      "fiscal_year_quarters": {
        "2020": ["FY"],
        "2021": ["FY"],
        "2022": ["FY"],
        "2023": ["FY"],
        "2024": ["FY"]
      },
      "normalized_form": "annual"
    },
    "10-Q": {
      "fiscal_years": [2023, 2024],
      "earliest": 2023,
      "latest": 2024,
      "fiscal_year_quarters": {
        "2023": ["Q1", "Q2", "Q3"],
        "2024": ["Q1", "Q2", "Q3"]
      },
      "normalized_form": "quarterly"
    }
  },
  "credits_used": 8
}

4.3 GET /data/company/list

Purpose: Discovery — return every company covered. Cache the result locally and refresh at most once per day.

Request:

QueryTypeDefaultNotes
jurisdictionstring(omitted)Optional. "US", "KR", "JP", "EU", "CN", or "all". When omitted, returns everything your plan includes.

Response:

FieldMeaning
companiesArray of objects sorted by ticker, each with ticker, jurisdiction, and the one identifier that applies — cik (SEC-listed), dart_corp_code (Korean), edinet_code (Japanese), lei (European), or uscc (China A-share); the others are omitted. All are omitted for the rare row whose identifier is not yet on file.
companies[].classificationIndustry classification block — Pro+ only, omitted otherwise. See §1.10.
credits_usedAlways 175 when successful.

Errors:

HTTPerror_codeWhen
403PLAN_TIER_INSUFFICIENT_COVERAGEThe requested jurisdiction is outside your plan's coverage scope.
402CREDITS_INSUFFICIENTNot enough credits.
400JURISDICTION_INVALIDjurisdiction is not one of US, KR, JP, EU, CN, all.
422VALIDATION_ERRORA query parameter other than jurisdiction was supplied. Not charged.

Example Request:

GET /api/v1/data/company/list
X-API-Key: <your-api-key>

Example MCP tool call:

list_companies()

Example Response:

{
  "companies": [
    {"ticker": "AAPL",   "jurisdiction": "US", "cik": "0000320193",
     "classification": {"sectors": ["Technology"], "source": {"scheme": "US_SIC", "code": "3571", "url": "https://www.sec.gov/search-filings/standard-industrial-classification-sic-code-list"}}},
    {"ticker": "MSFT",   "jurisdiction": "US", "cik": "0000789019"},
    {"ticker": "005930", "jurisdiction": "KR", "dart_corp_code": "00126380"},
    {"ticker": "1332",   "jurisdiction": "JP", "edinet_code": "E00014"},
    {"ticker": "VIRI_F", "jurisdiction": "EU", "lei": "969500FCVQ5SLAAUJV59"},
    {"ticker": "600519_CN", "jurisdiction": "CN", "uscc": "9152000071430580XT"}
  ],
  "credits_used": 175
}

4.4 POST /data/line-items

Purpose: Return structured facts for one filing by line-item name (e.g. revenue, net income, operating expenses). Names are resolved through a tiered L0–L3 path; per-line-item credit pricing.

Filing selection: supply filing_id, or supply ticker, fiscal_year, form_type (default 10-K), and optional quarter. If filing_id is present with identity fields, filing_id wins.

Request:

FieldTypeRequiredNotes
filing_idintegerConditional1–10⁹. If set, ticker/year fields are optional.
tickerstringConditionalRequired if filing_id omitted. 1–32 characters.
form_typestringNoDefault 10-K, max 32.
fiscal_yearintegerConditionalRequired if filing_id omitted. 1990–2100.
quarterstringNoMax 4 characters.
line_itemsarray of stringYesNon-empty; max 50 entries; each entry max 256 characters.
light_weight_modebooleanNoDefault false. When true, each results[*].dimensional_breakdowns is set to null; saves context when you already know exactly what you need. A notice is appended to _warnings. Charged identically.

Response: ticker, form_type, fiscal_year, quarter, source_url_prefix, results, credits_used, optional _correction / _warnings, optional amendment_context. Each entry in results carries metric, concept, value, raw_value, unit, period, dimensions, dimensional_breakdowns, restated / prior (same meaning as on POST /data/facts; null when the fact was not touched by an amendment), _resolution_level ("L0", "L1", "L2", or "L3"), and one of:

  • fact_id (string) + source_locator (string) — the number appears at exactly one position in the source filing.
  • fact_ids (list of {fact_id, source_locator} objects) — the same logical fact (matching concept, value, period, dimensions, and breakdowns) is reported at multiple positions in the source filing (e.g. income statement + equity statement + cash flow). All positions are listed equal-rank.

The two fields are mutually exclusive; each result row carries exactly one of them.

When one line-item name matches more than one concept, results come pre-ordered by Akkru smart ranking, and the multi-tag _warnings entry lists the matched concepts in that same order. The order is a recommendation only — review all returned results and judge which one you need.

Results are consolidated totals only. A value reported on a dimension (a single product line, segment, or region) is never returned by name, even when a printed statement row carries that name. Two ways to read slice values: POST /data/facts/dimensional-breakdown / POST /data/line-items/dimensional-breakdown starting from the total's fact_id, or POST /data/statement to read the full statement table.

is_consolidated_total is a string: "true" (the source filing explicitly tags the value as a consolidated total), "equivalent" (the source filing does not explicitly tag the value as a consolidated total; the attribute was inferred by the akkru engine — a note is appended to _warnings), or "false".

revenue follows each filing's own reported top line. For financial-sector companies (banks, brokers, insurers) that top line is a net figure (e.g. net interest income plus net fee income, or insurance revenue), so it is not directly comparable to the gross sales reported by non-financial companies.

Some filings tag per-share items (dividends per share, share counts) only per share class or dividend type; rows carrying such classifications do not resolve by name. They remain readable in the source statements and notes via POST /data/filing-statements + POST /data/statement.

Credits: tiered L0=10 … L3=50 per line item, partial-credit billing. Zero-balance → HTTP 402.

Errors: DATA_FILING_NOT_FOUND, DATA_FILING_QUARTER_REQUIRED, CREDITS_ZERO_BALANCE.

Example Request:

{
  "filing_id": 12345,
  "line_items": ["revenue", "net income"],
  "light_weight_mode": true
}

Example MCP tool call:

query_line_items(filing_id=12345, line_items=["revenue", "net income"], light_weight_mode=True)

Example response excerpt (one single-position row + one multi-position row):

{
  "results": [
    {
      "metric": "depreciation",
      "concept": "us-gaap_Depreciation",
      "fact_id": "f-665",
      "source_locator": "aapl-20250927.htm#fact-identifier-780",
      "value": 8000000000.0,
      "raw_value": "8.0",
      "unit": "usd",
      "period": "2024-09-29 ~ 2025-09-27",
      "is_consolidated_total": "true",
      "_resolution_level": "L1"
    },
    {
      "metric": "revenue",
      "concept": "us-gaap_RevenueFromContractWithCustomerExcludingAssessedTax",
      "fact_ids": [
        { "fact_id": "f-78",   "source_locator": "aapl-20250927.htm#fact-identifier-95"  },
        { "fact_id": "f-392",  "source_locator": "aapl-20250927.htm#fact-identifier-113" },
        { "fact_id": "f-1021", "source_locator": "aapl-20250927.htm#fact-identifier-121" },
        { "fact_id": "f-1113", "source_locator": "aapl-20250927.htm#fact-identifier-143" }
      ],
      "value": 416161000000.0,
      "raw_value": "416,161",
      "unit": "usd",
      "period": "2024-09-29 ~ 2025-09-27",
      "is_consolidated_total": "true",
      "_resolution_level": "L1"
    }
  ],
  "credits_used": 40
}

4.5 POST /data/facts

Purpose: Return structured facts for one filing by fact_id. For line-item-name queries (e.g. revenue, net income) use POST /data/line-items instead.

Filing selection: supply filing_id, or supply ticker, fiscal_year, form_type (default 10-K), and optional quarter. If filing_id is present with identity fields, filing_id wins.

Request:

FieldTypeRequiredNotes
filing_idintegerConditional1–10⁹. If set, ticker/year fields are optional.
tickerstringConditionalRequired if filing_id omitted. 1–32 characters.
form_typestringNoDefault 10-K, max 32.
fiscal_yearintegerConditionalRequired if filing_id omitted. 1990–2100.
quarterstringNoMax 4 characters.
fact_idsarray of stringYesNon-empty; max 500 strings; each max 128 characters.
light_weight_modebooleanNoDefault false. Leaner response — see Light-weight mode below; saves context when you already know exactly what you need. Charged identically.

Response:

FieldMeaning
ticker, form_type, fiscal_year, quarterFiling identity.
source_url_prefixSource-document URL base for this filing on its regulator's platform (SEC viewer for US filings; DART, EDINET, filings.xbrl.org, cninfo for KR / JP / EU / CN). May be null. The API does not return full source URLs; callers concatenate source_url_prefix with each fact's source_locator.
resultsArray of facts (each includes metric, concept, fact_id, optional source_locator, values, units, period fields, plus dimensions, dimensional_breakdowns and is_consolidated_total — same meaning as in §4.4). source_locator may be null or a fragment / relative path (amendments may use a ../-relative locator); callers concatenate it with source_url_prefix as-is. Amendment-affected facts also carry restated: true plus a prior object: for a value-changed fact prior holds the superseded value (raw_value / calculated_value / unit / decimals / fact_id / source_locator); for a fact added by the amendment prior is the sentinel { "added_by_amendment": "This fact was not present in the original filing; it was added by an amendment." }. Both fields are always present; on original/unaffected facts they are null.
credits_usedceil(deduped_fact_id_count / 5) × 10.
amendment_contextOptional; same idea as under filings when applicable.
_warningsOptional strings (duplicate ids deduplicated, missing ids not found in the filing, plus the Light-weight mode notice when that flag is on).

Light-weight mode (light_weight_mode=true): each results[*].dimensional_breakdowns is set to null. A notice is appended to _warnings.

Errors:

HTTPerror_codeWhen
400DATA_FILING_QUARTER_REQUIREDSeveral filings match without a quarter; message lists available quarters.
404DATA_FILING_NOT_FOUNDNo filing for the given id or identity.
402CREDITS_INSUFFICIENTNot enough credits.
422Validation (empty fact_ids, limits, missing filing selector).

Example Request:

{
  "filing_id": 12345,
  "fact_ids": ["ix_1", "ix_2"]
}

Example MCP tool call:

get_filing_facts(filing_id=12345, fact_ids=["ix_1", "ix_2"])

4.6 POST /data/statement

Purpose: Return one or more financial statement block(s) (JSON) for a filing. Two mutually exclusive lookup modes:

  • role_label mode — the filer's original XBRL role string (varies per filer; e.g. "CONSOLIDATED STATEMENTS OF OPERATIONS" for Apple). Returns the one matched block.
  • statement_type mode — the canonical statement name (e.g. "Income Statement", "Balance Sheet", "Comprehensive Income", "Stockholders Equity", "Cash Flow Statement"). Call POST /data/filing-statements for the valid values in a specific filing. Case-insensitive; trailing (N) suffix is ignored. Returns every matching block; a block that combines several statements matches each of its names. Available for SEC filings only; use role_label mode for other jurisdictions.

For the 5 main statements prefer the dedicated statement endpoints (/data/income-statement etc.) — same response shape, with the target spelled in the URL.

Filing selection: same pattern as POST /data/facts (filing_id or ticker + fiscal_year + form_type + optional quarter).

Request:

FieldTypeRequiredNotes
filing_idintegerConditionalSame rules as facts.
tickerstringConditional
form_typestringNoDefault 10-K.
fiscal_yearintegerConditional
quarterstringNo
role_labelstringXOR statement_type1–4000 characters; original filer XBRL role string.
statement_typestringXOR role_label1–4000 characters; canonical statement-type label.
light_weight_modebooleanNoDefault false. Leaner response — see Light-weight mode below; saves context when you already know exactly what you need. Charged identically.

Credits:

  • role_label mode: tiered 28 / 48. 28 is debited before the filing is resolved (balance below 28 → HTTP 402); the extra 20 of the higher (48-credit) tier is debited after matching, up to your remaining balance.
  • statement_type mode: 28 flat, debited before the filing is resolved (balance below 28 → HTTP 402).

Response:

FieldMeaning
ticker, form_type, fiscal_year, quarterFiling identity.
matchesArray of match objects (length 1 for role_label mode; length 1+ for statement_type mode). Each has block_index, role_label, statement_type (array of names; more than one when the block combines several statements), matched_via (describes how it was selected), and block (the full statement block content).
credits_usedNumber of credits deducted.
amendment_contextOptional; restatement or amendment information.
_correctionOptional; present on the 48-credit tier.
_warningsOptional; includes the Light-weight mode notice when that flag is on.

Light-weight mode (light_weight_mode=true) — applied to every match's block:

  • block.child_components → replaced by a placeholder string
  • In every block.parent_xbrl_table.mapped_xbrl_facts[*]:
    • xbrl_fact: concept_ns, concept_local, item_type, decimals, sign_attr, sign_from_xbrl, format
    • html_locator: xlsx_cell

A notice is appended to _warnings.

Errors:

HTTPerror_codeWhen
400DATA_FILING_QUARTER_REQUIREDAmbiguous quarterly filings (charged).
404DATA_FILING_NOT_FOUNDFiling not found. Still charged 28 credits.
404DATA_STATEMENT_ROLE_LABEL_UNRESOLVEDrole_label mode: no block matched; charged for the match tier reached.
404DATA_STATEMENT_NOT_AVAILABLE_IN_FILINGstatement_type mode: no block has this statement_type (charged).
400DATA_STATEMENT_TYPE_UNSUPPORTED_FOR_KRstatement_type mode: Korean (DART) filings not yet supported — coming soon (charged).
400DATA_STATEMENT_TYPE_UNSUPPORTED_FOR_JPstatement_type mode: Japanese (EDINET) filings not yet supported — coming soon (charged).
400DATA_STATEMENT_TYPE_UNSUPPORTED_FOR_EUstatement_type mode: European (ESEF) filings not yet supported — coming soon (charged).
400DATA_STATEMENT_TYPE_UNSUPPORTED_FOR_CNstatement_type mode: not available for China A-share filings; use role_label mode (charged).
404DATA_STATEMENT_BLOCK_JSON_MISSINGLabel matched but the block content is unavailable (charged).
402CREDITS_INSUFFICIENTBalance below 28.
422Validation (e.g. both role_label and statement_type given, or neither).

Example Request (role_label mode):

{
  "ticker": "AAPL",
  "form_type": "10-K",
  "fiscal_year": 2024,
  "role_label": "CONSOLIDATED STATEMENTS OF OPERATIONS"
}

Example Request (statement_type mode):

{
  "ticker": "AAPL",
  "form_type": "10-K",
  "fiscal_year": 2024,
  "statement_type": "Income Statement"
}

Example MCP tool call:

get_filing_statement(ticker="AAPL", form_type="10-K", fiscal_year=2024,
                    statement_type="Income Statement")

Example Response:

{
  "ticker": "AAPL",
  "form_type": "10-K",
  "fiscal_year": 2024,
  "quarter": "FY",
  "matches": [
    {
      "block_index": 1,
      "role_label": "CONSOLIDATED STATEMENTS OF OPERATIONS",
      "statement_type": ["Income Statement"],
      "matched_via": {
        "source": "statement_type",
        "query": "Income Statement",
        "matched_statement_type": "Income Statement"
      },
      "block": { "elements": [ "... truncated ..." ] }
    }
  ],
  "credits_used": 28
}

4.7 POST /data/filing-statements

Purpose: Discovery — list every statement block in a filing with its block_index, statement_type (array of canonical statement-type labels; more than one when the block combines several statements; null for non-financial blocks such as the cover page), and role_label (filer-specific XBRL string). Use this to find out exactly which statement_type / role_label values a specific filing exposes before calling POST /data/statement or the convenience endpoints.

Filing selection: standard (filing_id or ticker + fiscal_year + form_type + optional quarter).

Request:

FieldTypeRequiredNotes
filing_idintegerConditional
tickerstringConditional
form_typestringNoDefault 10-K.
fiscal_yearintegerConditional
quarterstringNo

Response:

FieldMeaning
ticker, form_type, fiscal_year, quarterFiling identity.
statementsArray of {block_index, statement_type, role_label}, ordered by block_index.
credits_usedAlways 10 when successful.

Errors:

HTTPerror_codeWhen
400DATA_FILING_QUARTER_REQUIREDAmbiguous quarterly filings.
404DATA_FILING_NOT_FOUNDFiling not found. Still charged 10 credits (this matches /data/filings and /data/company — discovery endpoints charge to cover the lookup attempt).
402CREDITS_INSUFFICIENTInsufficient credits.
422Validation.

Example Request:

{
  "ticker": "AAPL",
  "form_type": "10-K",
  "fiscal_year": 2024
}

Example MCP tool call:

list_filing_statements(ticker="AAPL", form_type="10-K", fiscal_year=2024)

Example Response:

{
  "ticker": "AAPL",
  "form_type": "10-K",
  "fiscal_year": 2024,
  "quarter": "FY",
  "statements": [
    { "block_index": 0, "statement_type": null,                    "role_label": "Cover Page" },
    { "block_index": 1, "statement_type": ["Income Statement"],    "role_label": "CONSOLIDATED STATEMENTS OF OPERATIONS" },
    { "block_index": 2, "statement_type": ["Comprehensive Income"],"role_label": "CONSOLIDATED STATEMENTS OF COMPREHENSIVE INCOME" },
    { "block_index": 3, "statement_type": ["Balance Sheet"],       "role_label": "CONSOLIDATED BALANCE SHEETS" },
    { "block_index": 4, "statement_type": ["Stockholders Equity"], "role_label": "CONSOLIDATED STATEMENTS OF SHAREHOLDERS' EQUITY" },
    { "block_index": 5, "statement_type": ["Cash Flow Statement"], "role_label": "CONSOLIDATED STATEMENTS OF CASH FLOWS" },
    { "block_index": 6, "statement_type": "Earnings Per Share",  "role_label": "Earnings Per Share - Computation of Basic and Diluted..." }
  ],
  "credits_used": 10
}

4.8 Statement endpoints (/data/<statement>)

Five endpoints that fetch one specific statement directly by URL. Each is equivalent to POST /data/statement with the matching statement_type — fixed by the URL path, so role_label and statement_type are not accepted in the body. Flat 28 credits per successful debit, debited before the filing is resolved (a missing filing or statement is still charged); rate limit 120/minute. Available for SEC filings only.

EndpointStatement returned
POST /data/income-statementIncome Statement
POST /data/comprehensive-incomeStatement of Comprehensive Income
POST /data/balance-sheetBalance Sheet
POST /data/cash-flow-statementCash Flow Statement
POST /data/equity-statementStatement of Stockholders' / Shareholders' Equity

Request body: same fields as POST /data/statement minus role_label and statement_type.

FieldTypeRequiredNotes
filing_idintegerConditional
tickerstringConditional
form_typestringNoDefault 10-K.
fiscal_yearintegerConditional
quarterstringNo
light_weight_modebooleanNoDefault false. Saves context when you already know exactly what you need.

Response: identical to POST /data/statement (matches: [...]). matched_via.source is always "statement_type".

Errors: identical to POST /data/statement (statement_type mode).

Example request:

{ "ticker": "AAPL", "form_type": "10-K", "fiscal_year": 2024 }

Example MCP tool calls:

get_income_statement(ticker="AAPL", form_type="10-K", fiscal_year=2024, light_weight_mode=True)
get_comprehensive_income(ticker="AAPL", form_type="10-K", fiscal_year=2024)
get_balance_sheet(ticker="AAPL", form_type="10-K", fiscal_year=2024)
get_cash_flow_statement(ticker="AAPL", form_type="10-K", fiscal_year=2024)
get_equity_statement(ticker="AAPL", form_type="10-K", fiscal_year=2024)

4.9 POST /data/facts/dimensional-breakdown

Purpose: Return one consolidated fact plus every slice fact it breaks down into. Slice facts are grouped by the set of XBRL axes their dimensions sit on.

Filing selection: standard (filing_id or ticker + fiscal_year + form_type + optional quarter).

Request:

FieldTypeRequiredNotes
filing_idintegerConditional
tickerstringConditional
form_typestringNoDefault 10-K.
fiscal_yearintegerConditional
quarterstringNo
fact_idstringYesThe fact_id of a consolidated fact.
recursivebooleanNoDefault true. When false, only the immediate children are returned.

Response:

FieldMeaning
ticker, form_type, fiscal_year, quarter, source_url_prefixFiling identity.
rootThe fact identified by fact_id: concept, value, raw_value, unit, period, dimensions, is_consolidated_total, fact_id, source_locator. The metric, fact_ids, restated, prior, and dimensional_breakdowns fields of POST /data/facts are not returned here.
groupsArray of {axes, facts} entries. axes is the sorted list of XBRL axis keys shared by every fact in facts; facts is the list of slice facts. Sorted by descending fact count, ties broken lexicographically by axes.
groups[].facts[].groupsPresent only when recursive=true. Same shape, nested per level.
_warningsOptional.
credits_usedceil((1 + N) / 5) × 10, where N is the number of returned slice facts.

Member granularity within a group: A single axis may carry both summary members and their detail components. Summary members overlap their detail components, so summing all facts in one group can double-count.

Credits: ceil((1 + N) / 5) × 10. 10 credits are charged on DATA_FACT_NOT_FOUND. A root with no breakdowns returns 200 with groups: [] and is charged 10 credits.

Errors:

HTTPerror_codeWhen
400DATA_FILING_QUARTER_REQUIREDAmbiguous quarterly filings.
404DATA_FILING_NOT_FOUNDFiling not found.
404DATA_FACT_NOT_FOUNDfact_id is not present in this filing. Still charged 10 credits.
402CREDITS_INSUFFICIENTNot enough credits.
422Validation.

Example Request:

{
  "ticker": "AAPL",
  "form_type": "10-K",
  "fiscal_year": 2025,
  "fact_id": "f-78"
}

Example MCP tool call:

get_dimensional_breakdown_by_fact_id(
    ticker="AAPL", form_type="10-K", fiscal_year=2025, fact_id="f-78"
)

Example Response (abridged):

{
  "ticker": "AAPL", "form_type": "10-K",
  "fiscal_year": 2025, "quarter": "FY",
  "source_url_prefix": "...",
  "root": {
    "concept": "us-gaap_RevenueFromContractWithCustomerExcludingAssessedTax",
    "fact_id": "f-78",
    "value": 416161000000.0,
    "raw_value": "416,161",
    "unit": "usd",
    "period": "2024-09-29 ~ 2025-09-27",
    "is_consolidated_total": "true",
    "dimensions": []
  },
  "groups": [
    {
      "axes": ["srt_ProductOrServiceAxis"],
      "facts": [
        {"concept": "us-gaap_RevenueFromContractWithCustomerExcludingAssessedTax",
         "fact_id": "f-72", "value": 307003000000.0,
         "dimensions": [{"axis": "srt_ProductOrServiceAxis","member": "us-gaap_ProductMember"}],
         "groups": []},
        {"fact_id": "f-377", "value": 209586000000.0,
         "dimensions": [{"axis": "srt_ProductOrServiceAxis","member": "aapl_IPhoneMember"}],
         "groups": []}
      ]
    },
    {
      "axes": ["srt_ConsolidationItemsAxis","us-gaap_StatementBusinessSegmentsAxis"],
      "facts": [
        {"fact_id": "f-1016", "value": 178353000000.0,
         "dimensions": [
           {"axis":"srt_ConsolidationItemsAxis","member":"us-gaap_OperatingSegmentsMember"},
           {"axis":"us-gaap_StatementBusinessSegmentsAxis","member":"aapl_AmericasSegmentMember"}
         ],
         "groups": []}
      ]
    },
    {
      "axes": ["srt_StatementGeographicalAxis"],
      "facts": [
        {"fact_id": "f-1104", "value": 151790000000.0,
         "dimensions": [{"axis":"srt_StatementGeographicalAxis","member":"country_US"}],
         "groups": []}
      ]
    }
  ],
  "credits_used": 28
}

4.10 POST /data/line-items/dimensional-breakdown

Purpose: Resolve a line-item name (e.g. revenue, net income) and return the dimensional breakdown of every consolidated fact that matches. Each match is one root with its axis-grouped slice facts. When the name matches more than one concept, matches come pre-ordered by Akkru smart ranking (same ordering as POST /data/line-items); the order is a recommendation only — review all matches and judge which one you need.

Filing selection: standard (filing_id or ticker + fiscal_year + form_type + optional quarter).

Request:

FieldTypeRequiredNotes
filing_idintegerConditional
tickerstringConditional
form_typestringNoDefault 10-K.
fiscal_yearintegerConditional
quarterstringNo
line_itemstringYesA single line-item name (e.g. "revenue").
recursivebooleanNoDefault true.

Response:

FieldMeaning
ticker, form_type, fiscal_year, quarter, source_url_prefixFiling identity.
matchesArray of {root, groups, duplicate_root_fact_ids?} entries.
matches[].rootSame shape as root in POST /data/facts/dimensional-breakdown, plus metric (echoes the request line_item) and _resolution_level ("L0""L3").
matches[].groupsSame shape and ordering as groups in POST /data/facts/dimensional-breakdown. Each fact also carries metric and _resolution_level.
matches[].duplicate_root_fact_idsOptional. Other fact_id values that resolved to the same logical fact as root.
_correctionOptional. Same shape as on POST /data/line-items.
_warningsOptional.
credits_usedResolver tier credit + ceil(N_total / 5) × 10, where N_total is the slice facts returned across all roots.

Member granularity within a group: Same as POST /data/facts/dimensional-breakdown — summary members and their detail components may coexist; summing all facts in one group can double-count.

Credits: Tiered resolution credit (L0=10 … L3=50) + ceil(N_total / 5) × 10. Partial billing applies.

Errors:

HTTPerror_codeWhen
400DATA_FILING_QUARTER_REQUIREDAmbiguous quarterly filings.
404DATA_FILING_NOT_FOUNDFiling not found.
402CREDITS_ZERO_BALANCEBalance is zero.
402CREDITS_INSUFFICIENTInsufficient credits.
422Validation.

Example Request:

{
  "ticker": "AAPL",
  "form_type": "10-K",
  "fiscal_year": 2025,
  "line_item": "revenue"
}

Example MCP tool call:

get_dimensional_breakdown_by_line_item(
    ticker="AAPL", form_type="10-K", fiscal_year=2025, line_item="revenue"
)

Example Response (abridged):

{
  "ticker": "AAPL", "form_type": "10-K",
  "fiscal_year": 2025, "quarter": "FY",
  "source_url_prefix": "...",
  "matches": [
    {
      "root": {
        "metric": "revenue",
        "concept": "us-gaap_RevenueFromContractWithCustomerExcludingAssessedTax",
        "fact_id": "f-78",
        "value": 416161000000.0,
        "period": "2024-09-29 ~ 2025-09-27",
        "is_consolidated_total": "true",
        "dimensions": [],
        "_resolution_level": "L1"
      },
      "duplicate_root_fact_ids": ["f-392","f-1021","f-1113"],
      "groups": [ /* same shape as 4.9 */ ]
    },
    {
      "root": { "metric": "revenue", "fact_id": "f-79",
                "value": 391035000000.0, "period": "2023-10-01 ~ 2024-09-28", "_resolution_level": "L1", "..." : "..." },
      "duplicate_root_fact_ids": ["f-393","f-1050","f-1114"],
      "groups": [ /* ... */ ]
    },
    {
      "root": { "metric": "revenue", "fact_id": "f-80",
                "value": 383285000000.0, "period": "2022-09-25 ~ 2023-09-30", "_resolution_level": "L1", "..." : "..." },
      "duplicate_root_fact_ids": ["f-394","f-1079","f-1115"],
      "groups": [ /* ... */ ]
    }
  ],
  "credits_used": 110
}

4.11 POST /data/compare/line-items

Purpose: Compare a list of line-item names (e.g. revenue, net income) across up to 25 filings. Names are resolved through the same L0–L3 tiered path as POST /data/line-items; per-line-item × per-filing pricing applies. Results are consolidated totals only, same as §4.4.

Request:

FieldTypeRequiredNotes
filingsarrayYes1–25 rows. Each row: filing_id or (ticker + fiscal_year + form_type + optional quarter), same resolution rules as POST /data/facts. No fact_ids field on rows.
line_itemsarray of stringYesNon-empty; max 50 strings; each max 256 chars.
light_weight_modebooleanNoDefault false. Leaner response — see Light-weight mode below; saves context when you already know exactly what you need. Charged identically.

Response:

FieldMeaning
amendment_contextsArray parallel to results; each entry is an object or null.
resultsEach element: ticker, form_type, fiscal_year, quarter, source_url_prefix (filing-level SEC URL base, may be null), optional caveat (per-row; see §1.6), facts (array of fact objects; each fact includes optional source_locator as in POST /data/facts, plus _resolution_level = "L0""L3" indicating which tier matched that line item), and — for Pro+ callers — a per-row classification block (see §1.10).
credits_usedPer credit rules in Section 2.
_correction, _warningsOptional; same general meaning as POST /data/line-items. Multi-concept line items are ordered by Akkru smart ranking within each row's facts, same as POST /data/line-items (a recommendation only — review all results). A _warnings entry is appended when the compared filings' fiscal period end dates differ by more than 45 days. The dimensional-breakdown notice is aggregated into a single string listing affected filings + fact ids. Per-row caveats are also aggregated into top-level _warnings (deduplicated; see §1.6).

Light-weight mode (light_weight_mode=true): each results[*].facts[*].dimensional_breakdowns is set to null. A notice is appended to top-level _warnings.

Partial-credit behavior: This endpoint charges per line item × per filing with partial-credit billing. If your balance is too low to cover the full request mid-run, later line items will return as unresolved rather than abort the whole call; check _warnings / _correction to see which were skipped, then top up and re-issue for the rest.

Errors:

HTTPerror_codeWhen
400DATA_FILING_QUARTER_REQUIREDA row needs quarter to disambiguate.
404DATA_FILING_NOT_FOUNDA row’s filing does not exist (message may reference row index).
402CREDITS_ZERO_BALANCEZero balance.
422Limits, missing line_items, or other validation.

Example Request:

{
  "filings": [
    { "ticker": "AAPL", "form_type": "10-K", "fiscal_year": 2024 },
    { "ticker": "AAPL", "form_type": "10-K", "fiscal_year": 2023 }
  ],
  "line_items": ["revenue"]
}

Example MCP tool call:

compare_line_items(
    filings=[
        {"ticker": "AAPL", "form_type": "10-K", "fiscal_year": 2024},
        {"ticker": "AAPL", "form_type": "10-K", "fiscal_year": 2023},
    ],
    line_items=["revenue"],
)

Example Response:

{
  "amendment_contexts": [null, null],
  "results": [
    {
      "ticker": "AAPL",
      "form_type": "10-K",
      "fiscal_year": 2024,
      "quarter": "FY",
      "source_url_prefix": "https://www.sec.gov/ix?doc=/Archives/edgar/data/.../aapl-20240928.htm",
      "facts": [
        {
          "metric": "revenue",
          "concept": "us-gaap_Revenue...",
          "fact_id": "f-1",
          "source_locator": "#fact-identifier-f-1",
          "value": 383285000000.0
        }
      ]
    },
    {
      "ticker": "AAPL",
      "form_type": "10-K",
      "fiscal_year": 2023,
      "quarter": "FY",
      "source_url_prefix": "https://www.sec.gov/ix?doc=/Archives/edgar/data/.../aapl-20230930.htm",
      "facts": [
        {
          "metric": "revenue",
          "concept": "us-gaap_Revenue...",
          "fact_id": "f-1",
          "source_locator": "#fact-identifier-f-1",
          "value": 394328000000.0
        }
      ]
    }
  ],
  "credits_used": 80
}

4.12 POST /data/compare/facts

Purpose: Compare XBRL fact_ids across up to 25 filings. Each filing row carries its own fact_ids list.

Request:

FieldTypeRequiredNotes
filingsarrayYes1–25 rows. Each row: filing_id or (ticker + fiscal_year + form_type + optional quarter), plus a required non-empty fact_ids list (max 500 per row; 2500 total ids across the whole request; each id ≤ 128 chars).
light_weight_modebooleanNoDefault false. Leaner response — see Light-weight mode below; saves context when you already know exactly what you need. Charged identically.

Response: Same shape as POST /data/compare/line-items. A _warnings entry is appended when the compared filings' fiscal period end dates differ by more than 45 days.

Light-weight mode (light_weight_mode=true): each results[*].facts[*].dimensional_breakdowns is set to null. A notice is appended to top-level _warnings.

Partial-credit behavior: Full request cost is ceil(total_deduped_fact_ids / 5) × 10 credits. The endpoint uses partial-credit billing, so if your balance can only cover part of the request you'll be charged that much and the response serves a proportional subset of the fact_ids (each 10 credits buy up to 5 ids; filings are processed in request order — once the budget runs out the remaining filings come back with facts: []). A _warnings[0] line states how many ids were served vs requested, and credits_used reflects what was actually spent. Zero balance → HTTP 402.

Errors:

HTTPerror_codeWhen
400DATA_FILING_QUARTER_REQUIREDA row needs quarter to disambiguate.
404DATA_FILING_NOT_FOUNDA row’s filing does not exist.
402CREDITS_INSUFFICIENTBalance is zero.
422Limits, missing fact_ids, or other validation.

Example Request:

{
  "filings": [
    { "filing_id": 12345, "fact_ids": ["ix_1", "ix_2"] },
    { "filing_id": 12344, "fact_ids": ["ix_1"] }
  ]
}

Example MCP tool call:

compare_facts(
    filings=[
        {"filing_id": 12345, "fact_ids": ["ix_1", "ix_2"]},
        {"filing_id": 12344, "fact_ids": ["ix_1"]},
    ],
)

4.13 GET /data/filings/{filing_id}/excel

Purpose: Obtain a time-limited download URL for the filing’s Excel attachment when the file is available.

Path parameter: filing_id (integer).

Response:

FieldMeaning
ticker, fiscal_yearFiling identity.
download_urlThe time-limited URL to download the Excel file.
expires_inExpiration time of the URL in seconds (e.g., 3600).
credits_usedAlways 300 when successful.

Errors:

HTTPerror_codeWhen
404DATA_FILING_NOT_FOUNDUnknown filing_id.
404DATA_EXCEL_NOT_AVAILABLE_FOR_FILINGNo Excel attachment on file.
404DATA_EXCEL_OBJECT_NOT_IN_STORAGEThe Excel file is not available.
503DATA_EXCEL_PUBLIC_URL_UNAVAILABLEA download URL cannot be provided for this request.
402CREDITS_INSUFFICIENTInsufficient credits.

Example MCP tool call:

get_filing_excel(filing_id=12345)

Example Response:

{
  "ticker": "AAPL",
  "fiscal_year": 2024,
  "download_url": "https://api.akkrudata.ai/...",
  "expires_in": 3600,
  "credits_used": 300
}

5. Metrics API

All routes accept X-API-Key as in Section 1. Endpoints in this section require the Starter plan or higher; Free callers receive 403 PLAN_TIER_INSUFFICIENT (see Section 8). The formula_override request field is additionally gated to the Pro plan or higher — Starter callers can use these endpoints but must omit formula_override.


Response conventions

Every metric returned by /metric/* endpoints carries a status field and a derivation field. The rest of the object's contents depend on these two.

status

ValueMeaning
okMetric was computed; value is set.
not_applicableMetric does not apply to this filing. Carries a reason string; value is null.
missing_inputA required XBRL fact is missing. Carries a missing_symbols list; value is null.
needs_price_dataPrice-sensitive metric called without current_price. value is null; pass current_price to upgrade to ok.
needs_user_formulaThe filing uses a non-standard concept combination. Pass accept_suggested_formula=true or supply formula_override to compute. value is null; a suggested_formula field is included.
needs_historyA prior-period value is required (e.g. growth rates) but is not available from this filing's payload. value is null.
divide_by_zeroDenominator was zero. value is null.
eval_errorFormula execution failed. value is null.

not_applicable takes precedence over every other status — once an NA rule fires for a metric, the response will be not_applicable regardless of what would otherwise apply.

derivation

ValueMeaning
derivedComputed from multiple XBRL facts via the standard formula.
as_reportedSingle XBRL fact taken at face value, no formula run.
compositeBuilt from multiple non-standard concepts (e.g. REIT CapEx = REInvestment + Maintenance).
segment_sumNo consolidated total in the filing; summed across segment members.
class_sumSummed across asset / liability class members.
company_overrideA company-specific override rule produced the value.
proxy_substitutedA proxy fact was used in place of the primary one (most often on ADR / foreign-issuer price-sensitive metrics).
TTM_rollforwardOn quarterly filings, the engine has rolled the metric forward to a trailing-12-month value. Comparable to annual filings of the same metric without further adjustment.
user_formula_acceptedResult of accept_suggested_formula=true — the engine's own suggested_formula was applied.
user_formula_customResult of a caller-supplied formula_override.
user_must_computeCompanion to status="needs_user_formula". Engine cannot compute automatically.
not_applicableCompanion to status="not_applicable".

When a metric cannot be computed, derivation does not name a computation path — it mirrors that metric's status, so values such as missing_input and needs_price_data also appear here. Branch on status first.

Currency and FX

A metric object may carry these three currency-related fields:

FieldMeaning
unitDisplay unit. Either a currency code (usd, eur, twd, …) for absolute monetary metrics, or ratio / percent / days / shares etc. for non-monetary metrics.
currencySource currency for absolute monetary metrics. Absent on ratio / percent / unitless metrics.
fx_requiredtrue when the metric is denominated in a non-USD currency (caller may want to convert to USD before using the value). false when no conversion is needed (already USD, or unitless).

For price-sensitive metrics on foreign-issuer filings (20-F / 40-F whose reporting_currency is not USD), the metric object also carries a price_used block:

SubfieldMeaning
closeThe price actually used in the formula (in the filer's reporting currency).
dateDate of close.
sourceIdentifier for the source of the price used.
original_adr_price_usdThe USD ADR price supplied (or filing-date USD price).
adr_ratioADR ratio (number of common shares per ADR).
fx_rate_local_per_usdConversion factor used for the period.
reporting_ccyFiler's reporting currency (e.g. EUR, TWD, CAD).

To convert a foreign-issuer absolute metric to USD:

value_usd = value / fx_rate_local_per_usd

For USD-reporting filings, fx_required is false, currency (when present) is usd, and price_used contains only close, date, source.

Light-weight mode

All /metric/* endpoints accept light_weight_mode (boolean, default false). When true, each returned metric object is reduced to its essential fields. The following per-metric fields are removed:

FieldRemoved in light-weight mode
components
fact_refs
formula_expression
computed_as
tried_concepts
caveat
missing_symbols

Fields retained: value, status, derivation, unit, currency, fx_required, fx_rate_used, formula, price_used, and any per-metric flags (split_adjusted_value etc.).

A notice is appended to _warnings. Credits are charged identically. Re-issue with light_weight_mode=false (or omit it) for the full payload.


5.0 Supported metric catalog

The API exposes 43 metrics, listed below by category. Use the name column verbatim wherever the API or MCP tools take a metric id (e.g. metric_names on POST /metric/items, formula_override keys, metric_names on POST /metric/historical). Names marked are price-sensitive — their realtime values require current_price in the request body (see §5.2).

Profitability (4)

NameUnitFormula
gross_marginratio(Revenue - CostOfRevenue) / Revenue
operating_marginratioOperatingIncome / Revenue
net_marginratioNetIncome / Revenue
ebitda_marginratio(OperatingIncome + DepreciationAndAmortization) / Revenue

Returns (4)

NameUnitFormula
return_on_equityratioNetIncome / ((Equity + EquityPrior) / 2)
return_on_assetsratioNetIncome / ((Assets + AssetsPrior) / 2)
return_on_invested_capitalratioNetIncome / (((Equity + LongTermDebt + ShortTermDebt) + (EquityPrior + LongTermDebtPrior + ShortTermDebtPrior)) / 2)
return_on_tangible_equityratioNetIncome / (((Equity - Goodwill - Intangibles) + (EquityPrior - GoodwillPrior - IntangiblesPrior)) / 2)

Leverage (4)

NameUnitFormula
debt_to_equityratio(LongTermDebt + ShortTermDebt) / Equity
debt_to_assetsratio(LongTermDebt + ShortTermDebt) / Assets
debt_to_ebitdaratio(LongTermDebt + ShortTermDebt) / (OperatingIncome + DepreciationAndAmortization)
interest_coverageratioOperatingIncome / InterestExpense

Liquidity (3)

NameUnitFormula
current_ratioratioCurrentAssets / CurrentLiabilities
quick_ratioratio(CurrentAssets - Inventory) / CurrentLiabilities
cash_ratioratioCash / CurrentLiabilities

Efficiency / activity (7)

NameUnitFormula
asset_turnoverratioRevenue / ((Assets + AssetsPrior) / 2)
inventory_turnoverratioCostOfRevenue / Inventory
receivables_turnoverratioRevenue / AccountsReceivable
days_inventorydaysPeriodDays * Inventory / CostOfRevenue
days_receivabledaysPeriodDays * AccountsReceivable / Revenue
days_payabledaysPeriodDays * AccountsPayable / CostOfRevenue
cash_conversion_cycledaysdays_inventory + days_receivable − days_payable

Cash flow & shareholder returns (3)

NameUnitFormula
free_cash_flowreporting currencyCFO - Capex
fcf_marginratio(CFO - Capex) / Revenue
payout_ratioratioDividends / NetIncome

Valuation — price-sensitive (12) ★

These require current_price in the request body to compute their realtime values; without it the realtime block returns the standard missing-price hint instead.

Tip: populate current_price from any realtime quote source (e.g. Finnhub, Alpha Vantage, yfinance).

NameUnitFormula
market_capreporting currencySharesOutstanding * Price
enterprise_valuereporting currencyMarketCap + LongTermDebt + ShortTermDebt - Cash
pe_ratioratioPrice / EPS
price_to_bookratioMarketCap / Equity
price_to_salesratioMarketCap / Revenue
price_to_cash_flowratioMarketCap / CFO
ev_to_ebitdaratioEnterpriseValue / (OperatingIncome + DepreciationAndAmortization)
ev_to_revenueratioEnterpriseValue / Revenue
ev_to_fcfratioEnterpriseValue / (CFO - Capex)
fcf_yieldratio(CFO - Capex) / MarketCap
dividend_yieldratioDividendsPerShare / Price
buyback_yieldratioStockRepurchases / MarketCap

Growth (6)

Year-over-year (yoy) growth compares the current period to the same period one year earlier; quarter-over-quarter (qoq) compares the current quarter to the immediately preceding quarter.

NameUnitFormula
revenue_growth_yoyratio(Revenue_t - Revenue_{t-4Q}) / Revenue_{t-4Q}
revenue_growth_qoqratio(Revenue_t - Revenue_{t-1Q}) / Revenue_{t-1Q}
revenue_growth_qoq_single_quarterratio(Revenue_Qn_single - Revenue_Q(n-1)_single) / Revenue_Q(n-1)_single
eps_growth_yoyratio(EPS_t - EPS_{t-4Q}) / EPS_{t-4Q}
net_income_growth_yoyratio(NI_t - NI_{t-4Q}) / NI_{t-4Q}
fcf_growth_yoyratio(FCF_t - FCF_{t-4Q}) / FCF_{t-4Q}

Notes:

  • A given filing may not have every metric — values requiring symbols absent from that filing simply do not appear in the response. The catalog above lists everything the API can return, not what every filing contains.
  • Non-USD reporters (20-F / 40-F filings whose reporting_currency is e.g. brl, eur) report free_cash_flow and market_cap / enterprise_value in their local currency; the per-metric unit field carries the actual currency.

5.1 POST /metric/filings

Purpose: List filings for a ticker that have metrics available, returning one row per filing with identifiers you use as metric_group_id on other metric routes.

Request:

FieldTypeRequiredNotes
tickerstringYes1–32 characters.
fiscal_yearintegerConditional1990–2100. You must supply fiscal_year or a valid as_of_date (YYYY-MM-DD). A blank or invalid date does not satisfy the requirement.
form_typesarray of stringNoMax 8 entries; each max 32 characters.
quarterstringNoMax 4 characters.
as_of_datestringNoIf non-empty and invalid, it is echoed as "error" in the response and ignored for filtering; a warning may be returned.

Response:

FieldMeaning
credits_usedAlways 10 when successful.
fiscal_yearEcho of request.
as_of_dateEcho of request (or "error" if invalid).
companyCompany profile (ticker, cik, legal_name) or null.
metric_groupsArray of objects; each includes metric_group_id, filing identity fields, dates, reporting currency, and optional amendment flags.
form_types, quarterPresent only if you sent them in the request.
_warningsOptional; present when dates exclude all rows or are invalid.

Errors:

HTTPerror_codeWhen
400METRICS_UNSUPPORTED_FOR_KRKorean (DART) metrics not yet supported — coming soon (not charged).
400METRICS_UNSUPPORTED_FOR_JPJapanese (EDINET) metrics not yet supported — coming soon (not charged).
400METRICS_UNSUPPORTED_FOR_EUEuropean (ESEF) metrics not yet supported — coming soon (not charged).
400METRICS_UNSUPPORTED_FOR_CNComputed metrics are not available for China A-share filings (not charged).
402CREDITS_INSUFFICIENTInsufficient credits.
422Validation (e.g. neither valid fiscal year nor valid as_of_date).

Example Request:

{
  "ticker": "AAPL",
  "fiscal_year": 2024
}

Example MCP tool call:

list_metric_snapshots(ticker="AAPL", fiscal_year=2024)

Example Response:

{
  "credits_used": 10,
  "fiscal_year": 2024,
  "as_of_date": null,
  "company": {
    "ticker": "AAPL",
    "cik": "0000320193",
    "legal_name": "Apple Inc."
  },
  "metric_groups": [
    {
      "metric_group_id": 9876,
      "ticker": "AAPL",
      "form_type": "10-K",
      "fiscal_year": 2024,
      "quarter": "FY",
      "period_end": "2024-09-28",
      "filing_date": "2024-11-01",
      "reporting_currency": "USD"
    }
  ]
}

5.2 POST /metric/all

Purpose: Return the full metrics object for one metric_group_id, including realtime price-sensitive metrics when the caller supplies current_price, and optional formula overrides.

Request:

FieldTypeDefaultNotes
metric_group_idintegerRequired. 1–10⁹. From POST /metric/filings.
as_of_datestringnullYYYY-MM-DD: exclude this filing if its filing date is after this date (amendments are pre-merged into the primary filing — no version switching). Invalid non-empty values echo as "error" and may produce warnings.
accept_suggested_formulabooleanfalseWhen true, applies suggested formula hints included with the filing’s metrics (if any).
formula_overrideobjectnullPer-metric overrides. Keys are metric names (e.g. "operating_margin"). Values are objects containing "concepts" (array of strings, at most 50 entries per metric) and "operators" (array of strings, e.g. ["+", "-"], length must be exactly len(concepts) - 1). A lone top-level { "concepts": ... } object is invalid.
current_pricenumbernullUSD price used to compute realtime price-sensitive metrics (market_cap, pe_ratio, enterprise_value, price_to_book, price_to_sales, price_to_cash_flow, ev_to_ebitda, ev_to_revenue, ev_to_fcf, fcf_yield, dividend_yield, buyback_yield). Must be > 0, ≤ 10,000,000, with at most 4 decimal places. Pass the USD price as-is for all filings, including foreign-issuer ADRs. Invalid values return HTTP 422 without charging credits. When omitted, the realtime block is replaced by { "status": "missing", "hint": "..." } and the same hint appears in _warnings.
current_fx_ratenumbernullOptional fallback FX rate (units of the filing's reporting_currency per 1 USD), used only when an up-to-date conversion rate is temporarily unavailable for foreign-issuer ADR filings. Normally not required. Must be > 0, ≤ 1,000,000, with at most 6 decimal places. Invalid values return HTTP 422 without charging credits.
light_weight_modebooleanfalseWhen true, strips per-metric audit fields from every entry. A notice is appended to _warnings. Charged identically. See Light-weight mode.

Response:

FieldMeaning
credits_usedAlways 148 when successful.
metric_group_idThe metric group ID actually used (may be null if excluded by as_of_date).
valuation_contextEcho of flags and formula inputs.
ticker, form_type, fiscal_year, quarter, cik, source_accession, primary_document, source_url_prefixFiling identity and SEC base URL. source_url_prefix may be null; combine it with each fact’s source_locator (see below) to build the SEC viewer URL.
segmentsArray of segment data.
price_insensitive_metricsObject containing metrics that do not depend on stock price. Within each metric, nested fact_refs / components entries that expose fact_id also expose source_locator (may be null).
price_sensitive_metricsObject containing metrics that depend on stock price. Always includes both a realtime sub-object (computed from the request's current_price; when realtime cannot be computed it becomes { "status": "missing" | "missing_fx_fallback", "hint": "..." } instead) and a filing_date_price + historical pair (the same metrics computed from the filing-date stock price). For foreign-issuer ADR filings each computed metric's price_used block carries the ADR ratio, the filer's reporting currency, and the FX rate used — see Response conventions. Same source_locator convention on nested fact references where fact_id is present. If you only need the filing-date computation, call POST /metric/all/filing-date instead.
price_contextPresent whenever the response would include a realtime block. status is "ok" (price applied), "missing" (no current_price supplied), or "missing_fx_fallback" (foreign-issuer filing and an up-to-date conversion rate is temporarily unavailable). When ok, also includes price, price_date, source: "user_supplied", and fx_fallback_used: true if the caller-supplied current_fx_rate was used because an up-to-date rate was unavailable. mode is always present; on the two non-ok statuses a message states what to send.
ttm_composite, dei_correctedOptional root fields, present if they exist in the payload.
amendedPresent and true only when this filing had a later amendment merged in. The returned metric values are already the amended figures.
corporate_actionsOptional root field, present when the ticker has corporate action events in the lookback window. Contains events_in_lookback and events_after_period_end (relative to this filing's period end); each event carries ex_date, ratio, type (forward / reverse), event_type (e.g. stock_split, stock_dividend), affects_total_shares, affects_holder_share_count, and relevant_to_metrics. Also carries adjustment_factor_to_today (factor converting this filing's per-share basis to the current basis), adjustment_factor_anchor (the date the factor is anchored on), and adjustment_factor_anchor_basis (how the anchor is chosen; period_end). When adjustment_factor_to_today is not 1, three per-share metrics — pe_ratio, dividend_yield, eps_growth_yoy — additionally carry split_adjusted_value, split_adjustment_factor, and comparable_to_post_split_basis, so values from this filing can be compared on the current per-share basis; when it is 1 the filing is already on that basis and those three fields are absent. Total values (revenue, market_cap, etc.) are unaffected. Tickers with no events in the window omit the field entirely.
reporting_currencyThe currency the filer reports in (e.g. usd, brl, eur). US filers (10-K / 10-Q) are always usd; foreign filers (20-F / 40-F) may be any local currency. Each metric's actual unit is on its own unit field; non-USD absolute metrics also carry currency and fx_required: true. See Response conventions.
_warningsOptional; warnings about amendments, formulas, or invalid dates.

Errors:

HTTPerror_codeWhen
404METRIC_GROUP_NOT_FOUNDUnknown metric_group_id.
404METRIC_SUMMARY_NOT_FOUNDFiling has no metrics summary.
404METRIC_SUMMARY_OBJECT_MISSINGThe metrics summary could not be retrieved.
500METRIC_SUMMARY_INVALID_FORMATThe metrics summary data is invalid.
402CREDITS_INSUFFICIENTInsufficient credits.
409METRIC_FORMULA_OVERRIDE_INVALIDInvalid formula_override.
422METRIC_FORMULA_APPLY_FAILEDFormula application failed.
422VALIDATION_ERRORcurrent_price is non-numeric, non-finite, ≤ 0, > 10,000,000, or has more than 4 decimal places; or current_fx_rate is non-numeric, non-finite, ≤ 0, > 1,000,000, or has more than 6 decimal places.

Example Request:

{
  "metric_group_id": 12345,
  "current_price": 225.0,
  "formula_override": {
    "operating_margin": {
      "concepts": ["us-gaap_GrossProfit", "us-gaap_SellingGeneralAndAdministrativeExpense"],
      "operators": ["-"]
    }
  }
}

Example MCP tool call:

get_metrics_bundle(
    metric_group_id=12345,
    current_price=225.0,
    formula_override={
        "operating_margin": {
            "concepts": ["us-gaap_GrossProfit", "us-gaap_SellingGeneralAndAdministrativeExpense"],
            "operators": ["-"],
        }
    },
)

Example Response:

{
  "credits_used": 148,
  "metric_group_id": 12345,
  "valuation_context": {    "as_of_date": null,
    "accept_suggested_formula": false,
    "formula_override": null
  },
  "ticker": "AAPL",
  "form_type": "10-K",
  "fiscal_year": 2024,
  "quarter": "FY",
  "cik": "0000320193",
  "source_accession": "0000320193-24-000123",
  "primary_document": "aapl-20240928.htm",
  "source_url_prefix": "https://www.sec.gov/ix?doc=/Archives/edgar/data/.../aapl-20240928.htm",
  "segments": [],
  "price_insensitive_metrics": {
    "revenue": { "value": 383285000000.0, "unit": "USD" }
  },
  "price_sensitive_metrics": {
    "realtime": {
      "market_cap": { "value": 3404250000000.0, "unit": "USD" }
    }
  },
  "price_context": {
    "mode": "user_supplied",
    "status": "ok",
    "price": 225.0,
    "price_date": "2026-05-18",
    "source": "user_supplied"
  },
  "_warnings": []
}

Example Response (filing affected by a stock split):

{
  "ticker": "NVDA",
  "fiscal_year": 2025,
  "quarter": "Q1",
  "corporate_actions": {
    "events_after_period_end": [
      { "ex_date": "2024-06-10", "ratio": 10.0, "type": "forward", "event_type": "stock_split",
        "affects_total_shares": true, "affects_holder_share_count": true, "relevant_to_metrics": true }
    ],
    "events_in_lookback": [
      { "ex_date": "2021-07-20", "ratio": 4.0,  "type": "forward", "event_type": "stock_split",
        "affects_total_shares": true, "affects_holder_share_count": true, "relevant_to_metrics": true },
      { "ex_date": "2024-06-10", "ratio": 10.0, "type": "forward", "event_type": "stock_split",
        "affects_total_shares": true, "affects_holder_share_count": true, "relevant_to_metrics": true }
    ],
    "adjustment_factor_to_today": 10.0,
    "adjustment_factor_anchor": "2024-04-28",
    "adjustment_factor_anchor_basis": "period_end"
  },
  "price_sensitive_metrics": {
    "realtime": {
      "pe_ratio": {
        "value": 24.25,
        "split_adjusted_value": 2.43,
        "split_adjustment_factor": 10.0,
        "comparable_to_post_split_basis": false
      }
    }
  }
}

5.3 POST /metric/all/filing-date

Purpose: Same metrics bundle as POST /metric/all, but returns only the filing-date price block — no realtime computation. Use this when you don't need today's market price (analyzing historical filings, batch loads, or any case where current stock price is irrelevant).

Request: Same body fields as POST /metric/all minus current_price and current_fx_rate. See the note below.

FieldTypeDefaultNotes
metric_group_idintegerRequired. 1–10⁹. From POST /metric/filings.
as_of_datestringnullSame as POST /metric/all.
accept_suggested_formulabooleanfalseSame as POST /metric/all.
formula_overrideobjectnullSame as POST /metric/all.
light_weight_modebooleanfalseSame as POST /metric/all. See Light-weight mode.

Note on realtime-only fields: Sending current_price or current_fx_rate returns 422 VALIDATION_ERROR (type: extra_forbidden) without charging credits. If you need realtime price-sensitive metrics, call POST /metric/all instead.

Response: Same shape as POST /metric/all except price_sensitive_metrics contains only filing_date_price + historical (no realtime); price_context is not present.

Credits: Same flat 148 as POST /metric/all.

Errors: Same as POST /metric/all.

Example Request:

{
  "metric_group_id": 12345
}

Example MCP tool call:

get_metrics_bundle_filing_date(metric_group_id=12345)

5.4 POST /metric/items

Purpose: Same sourcing as POST /metric/all, but returns only the metric names you list.

Request: Same as POST /metric/all, plus:

FieldTypeRequiredNotes
metric_namesarray of stringYes1–100 names; each max 256 characters. Each name must be a supported metric name and appear in that filing’s metrics (otherwise 400).
light_weight_modebooleanNoSame as POST /metric/all. See Light-weight mode.

Credits: 148 per successful debit.

Response:

FieldMeaning
credits_usedAlways 148 when successful.
metric_group_idThe metric group ID actually used.
valuation_contextEcho of flags, formula inputs, and requested metric_names.
ticker, form_type, fiscal_year, quarter, cik, source_accession, primary_document, source_url_prefixFiling identity and SEC base URL. source_url_prefix may be null; combine it with each fact’s source_locator (see below) to build the SEC viewer URL.
price_insensitive_metricsObject containing the requested price-insensitive metrics. Nested fact_refs / components entries with fact_id also expose source_locator (may be null).
price_sensitive_metricsObject containing the requested price-sensitive metrics. Its realtime sub-object follows the same convention as POST /metric/all: metric rows when current_price is supplied, { "status": "missing", "hint": "..." } otherwise. Same source_locator convention on nested fact references where fact_id is present.
price_contextPresent whenever the response would include a realtime block (same shape as in POST /metric/all).
segmentsArray of segment data.
ttm_composite, dei_correctedOptional root fields, present if they exist in the payload.
corporate_actionsOptional root field; same shape and semantics as in POST /metric/all. The same per-metric split variants appear on pe_ratio / dividend_yield / eps_growth_yoy when you request them.
_warningsOptional; warnings about amendments, formulas, or invalid dates.

Errors: Same classes as POST /metric/all, plus:

HTTPerror_codeWhen
400METRIC_INVALID_METRIC_NAMEUnknown name or name not in this filing’s payload.
402CREDITS_INSUFFICIENTInsufficient credits.

Example Request:

{
  "metric_group_id": 12345,
  "metric_names": ["revenue", "net_income"]
}

Example MCP tool call:

get_metrics_subset(metric_group_id=12345, metric_names=["revenue", "net_income"])

Example Response:

{
  "credits_used": 148,
  "metric_group_id": 12345,
  "metric_group_id": 12345,
  "valuation_context": {    "as_of_date": null,
    "accept_suggested_formula": false,
    "formula_override": null,
    "metric_names": ["revenue", "net_income"]
  },
  "ticker": "AAPL",
  "form_type": "10-K",
  "fiscal_year": 2024,
  "quarter": "FY",
  "cik": "0000320193",
  "source_accession": "0000320193-24-000123",
  "primary_document": "aapl-20240928.htm",
  "source_url_prefix": "https://www.sec.gov/ix?doc=/Archives/edgar/data/.../aapl-20240928.htm",
  "price_insensitive_metrics": {
    "revenue": { "value": 383285000000.0, "unit": "USD" },
    "net_income": { "value": 93736000000.0, "unit": "USD" }
  },
  "price_sensitive_metrics": {}
}

5.5 POST /metric/historical

Purpose: Return metrics for many periods (quarterly or annual) for one ticker, paginated. Price-sensitive values use filing-date figures only (no live market refresh).

Request:

FieldTypeDefaultNotes
tickerstringRequired. 1–32 characters (returned uppercased).
period_typestringquarterlyEither quarterly or annual. annual covers 10-K plus the foreign-issuer annual reports 20-F and 40-F; quarterly covers 10-Q only (foreign issuers have no quarterly counterpart).
start_period_startstringnullOptional filter: period start ISO date (YYYY-MM-DD). Invalid values echo as "error" in query_context and are ignored for filtering.
end_period_endstringnullOptional filter: same date rules.
metric_namesarraynullIf omitted or null, all metrics returned for each period; if set, only those names (must be supported and present in each returned period—otherwise 400). Max 100 names.
as_of_datestringnullSame meaning as /metric/all.
accept_suggested_formulabooleanfalse
formula_overrideobjectnullSame structure rules as /metric/all (including ≤ 50 concepts per metric).
sortstringperiod_end_ascperiod_end_asc or period_end_desc.
pageinteger1Page index, 1–10⁶.
page_sizeinteger31–5 (maximum page size).
light_weight_modebooleanfalseSame as POST /metric/all but applied to every metric object inside every periods[*]. See Light-weight mode.

Credits: 55 (base) + 148 × (number of rows in periods for this response). If the base debit succeeds but the per-row debit fails, you receive 402 with an explanation; the base 55 credits are spent.

Response:

FieldMeaning
page_infoObject with pagination details (current_page, total_pages, page_size, total_items, next_page_hint).
credits_usedNumber of credits deducted for this request.
tickerEcho of request.
query_contextEcho of the request parameters used for the query.
periodsArray of period objects. Each includes filing metadata (including source_url_prefix per period, may be null), price_insensitive_metrics, price_sensitive_metrics (as static maps), and optional root meta fields. Within each metric object, fact_refs / components entries that expose fact_id also expose source_locator (may be null). Each period may carry its own corporate_actions field, an amended flag (true when that period's filing had a merged amendment), and per-metric split variants as described in POST /metric/all; when comparing a per-share metric across periods that straddle a split, use split_adjusted_value instead of raw value.
_warningsOptional; warnings about amendments, formulas, or invalid dates.

Errors:

HTTPerror_codeWhen
400METRIC_INVALID_METRIC_NAMEInvalid or missing names in a period when metric_names is set.
400METRICS_UNSUPPORTED_FOR_KRKorean (DART) metrics not yet supported — coming soon (not charged).
400METRICS_UNSUPPORTED_FOR_JPJapanese (EDINET) metrics not yet supported — coming soon (not charged).
400METRICS_UNSUPPORTED_FOR_EUEuropean (ESEF) metrics not yet supported — coming soon (not charged).
400METRICS_UNSUPPORTED_FOR_CNComputed metrics are not available for China A-share filings (not charged).
402CREDITS_INSUFFICIENTInsufficient credits for base or per-row charges.
409METRIC_FORMULA_OVERRIDE_INVALIDInvalid formula_override.
422METRIC_FORMULA_APPLY_FAILEDFormula application failed; or validation (period_type, sort, limits).

Example Request:

{
  "ticker": "AAPL",
  "period_type": "quarterly",
  "page": 1,
  "page_size": 2
}

Example MCP tool call:

get_metrics_timeseries(ticker="AAPL", period_type="quarterly", page=1, page_size=2)

Example Response:

{
  "page_info": {
    "current_page": 1,
    "total_pages": 5,
    "page_size": 2,
    "total_items": 10,
    "next_page_hint": "Use the same request body with \"page\": 2."
  },
  "credits_used": 351,
  "ticker": "AAPL",
  "query_context": {
    "period_type": "quarterly",
    "start_period_start": null,
    "end_period_end": null,
    "as_of_date": null,    "accept_suggested_formula": false,
    "formula_override": null,
    "metric_names": null,
    "sort": "period_end_asc"
  },
  "periods": [
    {
      "metric_group_id": 9876,
      "period_start": "2024-07-01",
      "period_end": "2024-09-28",
      "filing_date": "2024-11-01",
      "ticker": "AAPL",
      "form_type": "10-K",
      "fiscal_year": 2024,
      "quarter": "Q4",
      "cik": "0000320193",
      "source_accession": "0000320193-24-000123",
      "primary_document": "aapl-20240928.htm",
      "source_url_prefix": "https://www.sec.gov/ix?doc=/Archives/edgar/data/.../aapl-20240928.htm",
      "segments": [],
      "price_insensitive_metrics": {
        "revenue": { "value": 94930000000.0, "unit": "USD" }
      },
      "price_sensitive_metrics": {
        "filing_date_price": 222.91,
        "historical": {
          "market_cap": { "value": 3300000000000.0, "unit": "USD" }
        }
      }
    }
  ]
}

5.6 Category endpoints (/metric/<category>)

Seven endpoints returning curated metric sets — margins, growth, leverage, efficiency, cash-flow, valuation. Use these when you want a coherent slice of metrics without enumerating names. Flat 148 credits, rate limit 60/minute.

EndpointMetrics returned
POST /metric/profitabilitygross_margin, operating_margin, net_margin, ebitda_margin, return_on_equity, return_on_assets, return_on_invested_capital, return_on_tangible_equity, fcf_margin (9)
POST /metric/growthrevenue_growth_yoy, revenue_growth_qoq, revenue_growth_qoq_single_quarter, eps_growth_yoy, net_income_growth_yoy, fcf_growth_yoy (6)
POST /metric/financial-healthdebt_to_equity, debt_to_assets, debt_to_ebitda, interest_coverage, current_ratio, quick_ratio, cash_ratio (7)
POST /metric/efficiencyasset_turnover, inventory_turnover, receivables_turnover, days_inventory, days_receivable, days_payable, cash_conversion_cycle (7)
POST /metric/cash-flowfree_cash_flow, fcf_margin, payout_ratio (3 — fcf_margin also in /metric/profitability)
POST /metric/valuationAll 12 price-sensitive ratios: market_cap, enterprise_value, pe_ratio, price_to_book, price_to_sales, price_to_cash_flow, ev_to_ebitda, ev_to_revenue, ev_to_fcf, fcf_yield, dividend_yield, buyback_yield. Accepts current_price for realtime; returns both realtime and filing_date_price blocks.
POST /metric/valuation/filing-dateSame 12 valuation ratios as above but only the filing-date price block — current_price and current_fx_rate are rejected with 422 VALIDATION_ERROR.

Request body (5 simple categories + /metric/valuation): metric_group_id required (1–10⁹). Optional: accept_suggested_formula, formula_override, as_of_date, current_price, current_fx_rate, light_weight_mode — same semantics as on POST /metric/all. metric_names is not accepted (the category fixes the metric set; sending it returns 422 VALIDATION_ERROR).

Request body (/metric/valuation/filing-date): same as above minus current_price / current_fx_rate — see POST /metric/all/filing-date. light_weight_mode is accepted on this endpoint as well.

Response shape: ticker, form_type, fiscal_year, quarter, cik, source_accession, primary_document, metric_group_id, source_url_prefix, valuation_context, segments, price_insensitive_metrics, price_sensitive_metrics, credits_used, plus the conditional price_context and the optional root fields ttm_composite, dei_corrected, corporate_actions and _warnings. For /metric/valuation and /metric/valuation/filing-date the price_insensitive_metrics block is always {} (all 12 valuation ratios are price-sensitive).

Errors: METRIC_GROUP_NOT_FOUND, CREDITS_INSUFFICIENT, standard 422 VALIDATION_ERROR.

Example MCP tool call:

get_profitability_metrics(metric_group_id=46)

6. Screener API

Query the universe of US-listed filers by composing metric conditions ("ROE > 20% for the last 5 years AND PE < 20"). Supports OR/NOT, time-window modifiers (for_latest / for_consecutive / for_at_least), 1–120 period lookback, USD-normalized values for ADR foreign filers, and paging up to 500 cumulative results.

§6.5 screens insider trades rather than metrics; its rows use the transaction object defined in §7. §6.9 screens institutional 13F filings; its rows use the snapshot object, also defined in §7.

Plan-tier gate: Every endpoint in this section requires the Pro plan or higher; Free / Starter callers receive 403 PLAN_TIER_INSUFFICIENT (see Section 8). The MCP wrappers (search_stocks, list_screener_filters, search_insider_trades) forward the same REST endpoints and surface the same 403 envelope.

Pricing note: Filters that touch price-sensitive metrics (market_cap, enterprise_value, all 12 valuation ratios) use the price observed on each filer's filing date; these dates differ across filers. For same-day cross-ticker comparison, call POST /metric/all per ticker with a common current_price.

6.1 POST /screener/metrics

Purpose: Return filings that match a DSL filter tree, grouped by ticker (default) or flattened.

Request body (APIRequest, extra="forbid"):

FieldTypeDefaultNotes
as_of_dateISO datetoday (UTC)Must be ≤ today. Filings with filing_date > as_of_date are excluded (avoids backtest leakage).
lookbackint 1–1201Most recent N filings per ticker within scope.
include_quarterlyboolfalsefalse → annual only (10-K / 20-F / 40-F). true adds 10-Q.
tickersstring[]omittedWhitelist, max 100. Case-insensitive (normalized to upper). Empty or omitted = full universe.
exclude_tickersstring[][]Blacklist, max 100.
usd_onlyboolfalseWhen true, exclude foreign-currency reporters.
sectorsstring[]omittedRestrict the universe to these canonical sector buckets (the 12 in §1.10). Omitted = no sector restriction.
where.filterDSL tree(required)See §6.3. Leaf count 1–10, nesting depth ≤ 4.
where.sort_bystringsee §6.3Metric name, "ticker", "period_end", "filing_date", or "match_count".
where.sort_order"asc" | "desc""asc"
include_metrics_using_filing_date_pricebooltruefalse rejects price-sensitive metrics in filter / sort_by / include_metrics.
exclude_derivationsstring[][]Subset of derived, as_reported, composite, class_sum, segment_sum, company_override, proxy_substituted, TTM_rollforward.
include_metricsstring[][]Extra metric names (≤ 10) to include in the response beyond filter-referenced ones.
group_by_tickerbooltruetrue → grouped by ticker with nested filings[]. false → flat per-filing rows.
pageint ≥ 111-indexed.
page_sizeint 1–10050Counts tickers (when grouped) or filings (when flat).

Pagination cap: page × page_size ≤ 500 (validation 422). Use larger page_size rather than more pages. Tighten filters to look beyond the first 500 results.

Response (group_by_ticker=true, default):

{
  "page": 1, "page_size": 50,
  "has_more": true,
  "next_page": 2,
  "as_of_date_applied": "2024-12-31",
  "lookback_applied": 5,
  "include_quarterly_applied": false,
  "results": [
    {
      "ticker": "AAPL",
      "match_count": 5,
      "filings": [
        {
          "metric_id": 46,
          "form_type": "10-K",
          "fiscal_year": 2024, "quarter": "FY",
          "period_end": "2024-09-28",
          "filing_date": "2024-11-01",
          "reporting_currency": "usd",
          "metrics": {
            "return_on_equity": {"value": 1.5774, "derivation": "derived", "unit": "ratio"},
            "pe_ratio": {"value": 33.21, "derivation": "derived", "unit": "ratio", "price_date": "2024-11-01"},
            "market_cap": {"value": 3.37e12, "derivation": "as_reported", "unit": "usd", "price_date": "2024-11-01"}
          }
        }
        /* T-1, T-2, … up to lookback filings within ticker */
      ]
    }
  ],
  "credits_used": 242
}

Response (group_by_ticker=false): identical envelope, but results[] is a flat list of {ticker, metric_id, form_type, fiscal_year, quarter, period_end, filing_date, reporting_currency, metrics} — one row per matching filing.

Each results[] entry (grouped or flat) also carries an industry classification block — see §1.10.

match_count is the number of filings within lookback that satisfy the whole filter tree on a per-filing basis (using each filing's own metric values).

Foreign-currency filers (ADRs) carry fx_rate_used + currency on FX-converted metric entries:

"market_cap": {
  "value": 2.42e11,            // USD-converted from JPY
  "derivation": "as_reported",
  "unit": "usd",
  "currency": "jpy",
  "fx_rate_used": 145.2,
  "price_date": "2024-06-30"
}

All screener filtering, sorting, and comparison use the USD-converted value. USD reporters omit fx_rate_used and currency.

Within-ticker filings[] ordering is fixed at filing_date DESC, period_end DESC (newest first), independent of where.sort_order. For time-series ordering, use group_by_ticker=false with sort_by="period_end" or "filing_date".

Errors: 422 VALIDATION_ERROR (schema), 402 CREDITS_INSUFFICIENT, 504 QUERY_TIMEOUT when the query exceeds the 30-second server timeout (the request is charged; tighten filters and retry).

Example MCP tool call:

search_stocks(lookback=5, include_quarterly=False,
              where={"filter": {"metric": "return_on_equity", "op": ">", "value": 0.2, "for_latest": 5}},
              page_size=10)

6.2 GET /screener/metrics/filters

Purpose: Discovery — returns the supported metric catalog, operators, temporal modifiers, form types, derivations, and one complete example request. 10 credits.

{
  "metrics": [
    {"name": "return_on_equity", "unit": "ratio", "price_sensitive": false},
    {"name": "market_cap", "unit": "usd", "price_sensitive": true}
    /* ... 43 total ... */
  ],
  "operators": ["<", "<=", ">", ">=", "between"],
  "temporal_modifiers": ["for_latest", "for_consecutive", "for_at_least"],
  "form_types": ["10-K", "10-Q", "20-F", "40-F"],
  "derivations": ["TTM_rollforward", "as_reported", "class_sum", "company_override", "composite", "derived", "proxy_substituted", "segment_sum"],
  "sectors": ["Technology", "Healthcare", "Finance", "Consumer Discretionary", "Consumer Staples", "Communications", "Industrials", "Energy", "Utilities", "Materials", "Real Estate", "Other"],
  "example_request": { /* full POST /screener/metrics body */ }
}

sectors lists the 12 canonical buckets accepted by the POST /screener/metrics sectors filter (§1.10).

Example MCP tool call:

list_screener_filters()

6.3 Filter DSL (/screener/metrics)

Leaf node

{"metric": "<name>", "op": "<operator>", "value": <number | [lo, hi]>,
 "for_latest": <N> | "for_consecutive": <N> | "for_at_least": <N>}
OperatorValue shapeNotes
>, >=, <, <=single number
between[lo, hi] (lo ≤ hi)Inclusive on both ends.

= / != are not supported in v1. For equality matching use between [v − ε, v + ε].

value must be numeric. null is rejected. Filings where the metric value is missing are excluded from filter comparisons (no synthetic match).

Temporal modifiers (mutually exclusive, at most one per leaf)

ModifierMeaning
(none)Latest filing in lookback must satisfy. Equivalent to for_latest: 1.
for_latest: NMost recent N filings (right-anchored) all satisfy.
for_consecutive: NSome N adjacent filings within lookback all satisfy (sliding window over filing_date).
for_at_least: NAt least N filings within lookback satisfy (any positions).

N ≥ 1 and N ≤ lookback. Tickers without enough filings in lookback to evaluate the modifier are filtered out.

Composite nodes

{"and": [<node>, <node>, …]}
{"or":  [<node>, <node>, …]}
{"not": <node>}

where.filter may itself be a bare leaf (no wrapper required for single-condition queries).

Limits

  • Leaf nodes total: 1–10 (0 → rejected as "filter required"; >10 → rejected as "too complex")
  • Nesting depth: ≤ 4
  • include_metrics length: ≤ 10
  • tickers, exclude_tickers: each ≤ 100 entries

6.4 Credit formula (/screener/metrics)

POST /screener/metrics charges per call (paginate ⇒ each page bills independently):

credits = max(65, 425
              − tickerDiscount             // ceil(200 × (100 − n_tickers) / 100); 0 (whole universe, or ≥ 100 tickers) … 198 (1 ticker)
              − lookbackDiscount           // 0 (lookback ≥ 30) … 78 (lookback = 1)
              − quarterlyDiscount          // 60 when include_quarterly=false, else 0
              + lookbackSurcharge          // 0 (lookback ≤ 30) … 240 (lookback = 120)
              + filterSurcharge            // 40 × (leaves − 1), 0 … 360
              + temporalSurcharge          // per-leaf 60 (for_latest / for_at_least) or 100 (for_consecutive), capped 600
              + includeMetricsSurcharge)   // 20 × |include_metrics \ filter_metrics|, 0 … 200

Examples:

ScenarioCredits
1 ticker, lookback=1, annual only, 1 leaf (best case)89
Whole universe, lookback=30, quarterly+annual, 1 leaf425
2 tickers, lookback=5, annual, 2 leaves, 1 for_latest, 2 extra include_metrics242
Whole universe, lookback=120, 10 leaves all for_consecutive, 10 extra include_metrics1825 (worst case)

Charge applies even when results is empty, and on 504 QUERY_TIMEOUT. No charge only on 422 VALIDATION_ERROR, 402 CREDITS_INSUFFICIENT, or 403 PLAN_TIER_INSUFFICIENT (all rejected before any deduction).

GET /screener/metrics/filters charges 10 credits flat.

6.5 POST /screener/ownership

Purpose: Full-library transaction screening. Trade-level conditions plus company-level aggregate gates; returns the matching transactions.

Request:

FieldTypeDefaultNotes
start_date, as_of_dateISO dateas_of_date ≤ today; start_dateas_of_date.
tickers, exclude_tickersstring[]omitted≤ 100 each.
sectorsstring[]omittedThe 12 canonical buckets (§1.10).
trade_filtersobjectomittedSee §6.6.
aggregate_filtersobject[]omitted≤ 8. Company-level gates — see §6.6.
group_by_tickerbooltruetrue → grouped by ticker. false → flat rows.
sort_bystringGrouped: ticker, txn_count. Flat: transaction_date, filing_date, transaction_value, shares, price_per_share, own_pct_change, split_adjusted_shares, split_adjusted_price.
sort_order"desc" | "asc""desc"
pageint ≥ 11
page_sizeint 1–10050

Pagination cap: page × page_size ≤ 500 (422).

Response:

FieldMeaning
page, page_size, has_more, next_pagePagination.
as_of_date_applied, start_date_appliedWindow actually used.
resultsgroup_by_ticker=true. Each entry: ticker, issuer, issuer_cik, txn_count (the company's full hit count, not the page's), transactions.
transactionsgroup_by_ticker=false. Flat rows, each additionally carrying ticker, issuer, and issuer_cik.
anomalies_excluded_countTransactions excluded by the consistency checks; 0 when trade_filters.include_anomalies=true.
credits_used, _warnings

Every row carries accession_number, filing_date, source_url_prefix, insiders, the transaction object, and computed.

Errors: 422 VALIDATION_ERROR, 402 CREDITS_INSUFFICIENT, 403 PLAN_TIER_INSUFFICIENT below Pro, 504 QUERY_TIMEOUT at the 30-second server timeout (charged).

Example MCP tool call:

search_insider_trades(start_date="2026-04-01", tickers=["AAPL"],
                      trade_filters={"transaction_code": ["P", "S"]}, page_size=10)

6.6 Filters (/screener/ownership)

trade_filters:

FieldTypeNotes
transaction_codestring[]≤ 20. Unknown codes dropped with a warning.
relationshipstring[]is_director, is_officer, is_ten_percent_owner, is_other. OR semantics.
is_derivativebool
principal_amount_not_sharesboolOmit for no filter, true for debt-principal rows only, false to exclude them.
include_anomaliesboolDefault false.
exclude_likely_mergedboolDefault false.
include_unresolved_amendmentsboolDefault false.
conditionsobject[]≤ 8. {field, op, value}. fieldtransaction_value, price_per_share, shares, own_pct_change, split_adjusted_shares, split_adjusted_price.

aggregate_filters: {metric, op, value}, metricvalue_acquired, value_disposed, net_value, shares_acquired, shares_disposed, net_shares, txn_count, txn_count_acquired, txn_count_disposed, max_txn_value_acquired, max_txn_value_disposed, distinct_insiders.

Operators (both filter types): >, >=, <, <=, between ([lo, hi], lo ≤ hi).

6.7 Credit formula (/screener/ownership)

POST /screener/ownership charges per call:

credits = max(65, 200
              − tickerDiscount        // 100 − min(n_tickers, 100); 0 when tickers is omitted
              − shortWindowDiscount   // 40 when the window is ≤ 90 days
              + fullHistorySurcharge  // 80 when start_date is omitted
              + 40 × conditions)      // trade conditions + aggregate filters

Range 65–920. Charged even when the result set is empty, and on 504 QUERY_TIMEOUT. No charge on 422 VALIDATION_ERROR, 402 CREDITS_INSUFFICIENT, or 403 PLAN_TIER_INSUFFICIENT (all rejected before any deduction).

6.8 POST /screener/initial-holdings

Purpose: Full-library screening of initial holdings (Form 3). Holding-level conditions plus company-level aggregate gates; returns the matching holdings. Requires Pro or higher.

Request:

FieldTypeDefaultNotes
start_date, as_of_dateISO dateWindow on filing_date. as_of_date ≤ today; start_dateas_of_date.
tickers, exclude_tickersstring[]omitted≤ 100 each.
sectorsstring[]omittedThe 12 canonical buckets (§1.10).
holding_filtersobjectomittedSee below.
aggregate_filtersobject[]omitted≤ 8. Company-level gates — see below.
group_by_tickerbooltruetrue → grouped by ticker. false → flat rows.
sort_bystringGrouped: ticker, holdings_count, shares_owned_total. Flat: filing_date, shares_owned, split_adjusted_shares_owned, underlying_security_shares, conversion_or_exercise_price.
sort_order"desc" | "asc""desc"
pageint ≥ 11
page_sizeint 1–10050

Pagination cap: page × page_size ≤ 500 (422).

holding_filters:

FieldTypeNotes
relationshipstring[]is_director, is_officer, is_ten_percent_owner, is_other. OR semantics.
is_derivativebool
direct_or_indirect"D" | "I"
include_anomaliesboolDefault false.
exclude_likely_mergedboolDefault false.
include_unresolved_amendmentsboolDefault false.
conditionsobject[]≤ 8. {field, op, value}. fieldshares_owned, split_adjusted_shares_owned, underlying_security_shares, split_adjusted_underlying_security_shares, conversion_or_exercise_price.

aggregate_filters: {metric, op, value}, metricfiling_count, no_securities_filing_count, distinct_insiders, holdings_count, shares_owned_total. filing_count and no_securities_filing_count count filings, including filings that report no holdings; holdings_count and shares_owned_total are measured on the matching holdings.

Operators (both filter types): >, >=, <, <=, between ([lo, hi], lo ≤ hi).

Response:

FieldMeaning
page, page_size, has_more, next_pagePagination.
as_of_date_applied, start_date_appliedWindow actually used.
resultsgroup_by_ticker=true. Each entry: ticker, issuer, issuer_cik, holdings_count and shares_owned_total (the company's full hit values, not the page's), holdings.
holdingsgroup_by_ticker=false. Flat rows, each additionally carrying ticker, issuer, and issuer_cik.
anomalies_excluded_countHoldings excluded by the consistency checks; 0 when holding_filters.include_anomalies=true.
credits_used, _warnings

Every row carries accession_number, filing_date, period_of_report, no_securities_owned, source_url_prefix, insiders, and the holding object.

Credits: the §6.7 formula, with conditions = holding conditions + aggregate filters. Range 65–920.

Errors: 422 VALIDATION_ERROR, 402 CREDITS_INSUFFICIENT, 403 PLAN_TIER_INSUFFICIENT below Pro, 504 QUERY_TIMEOUT at the 30-second server timeout (charged).

Example MCP tool call:

search_initial_holdings(tickers=["TSLA"], holding_filters={"is_derivative": False}, page_size=10)

6.9 POST /screener/institutional-holdings

Purpose: Screen SEC Form 13F institutional filings across the whole library. One row = one manager-quarter, carrying that quarter's headline numbers (the snapshot object defined in §7, plus the manager's cik and name). An empty body is the full listing, ordered by total_positions_value descending. Requires Pro or higher.

Request:

FieldTypeDefaultNotes
start_date, end_dateISO dateomittedBound the calendar quarter end: quarters whose period end falls inside the range participate. Give one date to bound one side only; omit both to scan every quarter.
conditionsobject[]omitted≤ 8 of {field, op, value} — see below.
is_amendedboolomittedtrue → only quarters with merged amendments; false → only quarters without.
confidentialboolomittedFilter on the confidential-treatment flag.
is_combination_reportboolomittedtrue → 13F COMBINATION REPORT quarters (the filer also reports holdings managed by other managers); false → 13F HOLDINGS REPORT quarters.
sort_bystringtotal_positions_valueOne of total_positions_value, positions_count, derivatives_count, total_derivatives_notional, portfolio_value_qoq_pct, top1_security_pct, top10_security_pct, est_turnover, period, filing_date.
sort_order"desc" | "asc""desc"
pageint ≥ 11
page_sizeint 1–10050

Pagination cap: page × page_size ≤ 500 (422).

conditions: each is {field, op, value} with op>, >=, <, <=, between ([lo, hi], lo ≤ hi, inclusive on both ends). field is one of total_positions_value, positions_count, derivatives_count, total_derivatives_notional, portfolio_value_qoq_pct, top1_security_pct, top10_security_pct, est_turnover, cover_table_value, new_count, add_count, reduce_count, hold_count, sold_out_count (the five counters read the quarter's activity_counts), or filing_date (values as ISO date strings).

A quarter where the compared field is null never matches. In particular, each manager's earliest quarter in the data window has null portfolio_value_qoq_pct, est_turnover and activity_counts (no prior quarter to compare against), so conditions on those fields never match it.

Response: matches (snapshot rows with cik / name), total_matches, page, page_size, credits_used, and — exactly when the returned rows cover more than one quarter — a _warnings entry saying the rows span quarters and the same manager can appear once per quarter.

Errors: 422 VALIDATION_ERROR, 402 CREDITS_INSUFFICIENT, 403 PLAN_TIER_INSUFFICIENT below Pro (all rejected before any deduction), 504 QUERY_TIMEOUT at the 30-second server timeout (charged).

Example MCP tool call:

search_institutional_holdings(start_date="2026-01-01", end_date="2026-03-31",
                    conditions=[{"field": "total_positions_value", "op": ">=", "value": 100000000000}],
                    page_size=10)

6.10 Credit formula (/screener/institutional-holdings)

POST /screener/institutional-holdings charges per call (paginate ⇒ each page bills independently):

credits = max(65, 200
              + 40 × conditions        // numeric conditions + boolean filters actually passed
              − narrowWindowDiscount   // 40 when both dates are given and span ≤ 184 days (at most two quarters)
              + noWindowSurcharge)     // 80 when neither date is given

Range 160–720.

ScenarioCredits
Empty body (full listing)280
One quarter (start_date = end_date), 1 condition200
1 condition + is_amended, no dates360

Charged even when matches is empty, and on 504 QUERY_TIMEOUT. No charge on 422 VALIDATION_ERROR, 402 CREDITS_INSUFFICIENT, or 403 PLAN_TIER_INSUFFICIENT (all rejected before any deduction).


7. Ownership API

Insider trades (Form 4), initial beneficial-ownership statements (Form 3), and institutional holdings reports (Form 13F) reported to the SEC. US filings only. For the Form 4 / Form 3 endpoints, the plan coverage scope (§1.9) and history window (§1.8) apply as they do elsewhere, on the filing's filing_date; the 13F endpoints are organized by the filing manager (institution), not by company. The endpoints in this section are available on every plan; full-library screening is POST /screener/ownership, POST /screener/initial-holdings and POST /screener/institutional-holdings in Section 6, which require Pro or higher.

Credits are deducted before the query runs, so a 404 or 403 raised afterwards is still charged.

Transaction object

Returned by POST /ownership/transactions, POST /ownership/transaction-ids, and POST /screener/ownership.

FieldMeaning
idTransaction id. Pass to POST /ownership/transaction-ids.
is_derivativeDerivative table row (true) or non-derivative (false).
transaction_form_type"4" or "5".
transaction_date, transaction_codeAs filed.
transaction_typeOfficial SEC name for transaction_code.
transaction_type_groupOne of the five SEC groupings — see §7.6.
acquired_disposed_code"A" acquired, "D" disposed, or null. Read direction from this field, not from transaction_code.
shares, price_per_share, transaction_value, shares_owned_followingAs filed. transaction_value may be null or 0.
transaction_noteFiler-side note explaining a null / 0 value. null when absent.
principal_amount_not_sharestrue when shares holds a debt principal amount, not a share count.
security_title, direct_or_indirect, nature_of_ownershipAs filed.
footnote_refsFootnote ids for this transaction. Resolve against the filing's footnotes map.
source_locatorCombine with the filing's source_url_prefix to build the SEC URL.
restatednull, "cancelled", "modified", or "added" — set when an amendment changed this transaction.
priorPresent only when restated is set. The pre-amendment values.
split_adjustedPresent only when the filed values are not on the current per-share basis. See below.
data_quality_flagsPresent only when at least one rule fires. See below.

Derivative rows additionally carry conversion_or_exercise_price, exercise_date, expiration_date, underlying_security_title, underlying_security_shares, underlying_security_value, and value_owned_following.

split_adjusted

shares and price_per_share are in the units of the transaction's own trade date. When those differ from the current per-share basis, the block is present:

"split_adjusted": {
  "shares": 4000.0,
  "price_per_share": 125.86,
  "shares_owned_following": 48000.0,
  "split_adjustment_factor": 4.0,
  "comparable_to_post_split_basis": false
}

Absent means the filed values are already on the current per-share basis. split_adjustment_factor and comparable_to_post_split_basis carry the same meaning and the same presence rule as on the metrics API (§5.2).

data_quality_flags

Rows that fail a consistency check carry one or more of:

future_transaction_date, future_deemed_execution_date, zero_price_open_market, derivative_date_order, negative_shares, negative_price, negative_transaction_value, negative_shares_owned_following, value_mismatch, manual_flags.

Rows flagged manual_flags also carry a manual_flags array of {code, note} entries describing the issue.

Flagged rows are excluded from POST /ownership/transactions, POST /ownership/stats and POST /screener/ownership unless include_anomalies=true (trade_filters.include_anomalies on the screener). Each endpoint reports how many it withheld: the listing in anomalies_excluded_on_page (this page only), stats and the screener in anomalies_excluded_count (the whole requested range).

computed

POST /screener/ownership rows additionally carry a computed block with shares_owned_before and own_pct_change. Each entry has value, status (ok / unavailable), unit, formula, computed_as, and fact_refs pointing at the inputs. When an input is missing, value is null, status is "unavailable", and computed_as states the reason.


7.1 POST /ownership/transactions

Purpose: Anchored listing of insider-trade filings and their transactions. Requires ticker and/or insider_cik; unanchored queries belong to §6.5.

Request:

FieldTypeDefaultNotes
tickerstringUppercased automatically.
insider_cikstringDigits only, ≤ 10; left-padded to 10.
transaction_codestring[]omitted≤ 20 entries. Unknown codes are dropped with a _warnings entry.
transaction_form_type"4" | "5"omitted
relationshipstring[]omittedAny of is_director, is_officer, is_ten_percent_owner, is_other. OR semantics, evaluated per filing.
include_unresolved_amendmentsboolfalse
exclude_likely_mergedboolfalse
include_anomaliesboolfalse
pageint ≥ 11
page_sizeint 1–10050Counts filings.

At least one of ticker / insider_cik is required (422 otherwise).

Response:

FieldMeaning
page, page_size, has_more, next_pagePagination.
anomalies_excluded_on_pageHow many transactions on this page were withheld because they failed a consistency check. 0 when include_anomalies=true. Page-scoped: it counts only the rows hidden inside the filings this page returned, and is independent of the whole-range anomalies_excluded_count on POST /ownership/stats.
filingsArray. Each carries id, ticker, issuer, issuer_cik, accession_number, form_type, filing_date, period_of_report, date_of_original_submission, merge_status, remarks, source_url_prefix, insiders, footnotes, transactions, and amendments (present only when amendments were merged).
filings[].issuer_cikThe issuer CIK declared by the filing itself. Compare it with the company's own CIK from GET /ownership/tickers to verify the filing belongs to this company. null on filings imported before issuer identity was available.
filings[].insiderscik, name, is_director, is_officer, is_ten_percent_owner, is_other, officer_title, other_text.
filings[].footnotesMap of footnote id → text for this filing.
_warningsOptional.
credits_usedAlways 30.

Credits: 30 per page.

Errors: 404 OWNERSHIP_COMPANY_NOT_FOUND (charged), 403 PLAN_TIER_INSUFFICIENT_COVERAGE when the ticker is outside your plan's coverage scope (charged), 422 VALIDATION_ERROR, 402 CREDITS_INSUFFICIENT.

Example MCP tool call:

list_insider_transactions(ticker="AAPL", transaction_code=["P", "S"], page_size=5)

7.2 POST /ownership/stats

Purpose: Aggregate statistics over one company and/or one insider, plus the ids of every transaction that contributed.

Request:

FieldTypeDefaultNotes
tickerstring
insider_cikstring
start_date, as_of_dateISO dateas_of_date ≤ today; start_dateas_of_date.
transaction_codestring[]omitted≤ 20 entries.
method"ad" | "ps""ad"ad splits on acquired_disposed_code. ps treats P as a buy and S as a sell, and narrows the scope to those two codes.
include_anomaliesboolfalse
relationshipstring[]omittedAny of is_director, is_officer, is_ten_percent_owner, is_other. OR semantics, evaluated per filing.
is_derivativeboolomitted
exclude_likely_mergedboolfalse
include_unresolved_amendmentsboolfalse
ids_pageint ≥ 11Paginates transaction_ids only.
ids_page_sizeint 1–1000200

At least one of ticker / insider_cik is required.

Response: stats, method_applied, start_date_applied, as_of_date_applied, anomalies_excluded_count, credits_used, optional corporate_actions, optional _warnings, then ids_total, ids_page, ids_has_more, transaction_ids.

Key names inside stats follow method: acquired / disposed for ad, bought / sold for ps.

stats fieldMeaning
value_acquired, value_disposed, net_valueCash value totals. Transactions with no cash value contribute 0.
shares_acquired, shares_disposed, net_sharesShare totals on the split-adjusted basis, excluding rows where principal_amount_not_shares is true.
avg_price_acquired, avg_price_disposedTotal value ÷ total split-adjusted shares over the transactions that have a cash value, on the same basis as shares_*. null when there are none.
txn_count, txn_count_acquired, txn_count_disposedCounts.
txn_count_with_valueTransactions carrying a non-zero cash value.
no_value_txn_countTransactions with no cash value.
ad_code_missing_countTransactions counted in neither direction.
principal_amount_txn_countDebt-principal rows excluded from shares_* and avg_price_*.
distinct_insidersDistinct reporting owners in scope.
filings_with_multiple_filersJoint filings in scope.
max_txn_value_acquired, max_txn_value_disposedLargest single transaction per side. null when the side is empty.
avg_value_per_txn_acquired, avg_value_per_txn_disposedMean over transactions that have a cash value.
earliest_transaction_date, latest_transaction_dateRange actually covered.
corporate_action_crossingtrue when the window spans a corporate action.

corporate_actions is present only when the request is anchored on a ticker that has corporate actions on file: an array of {ex_date, ratio, type, event_type}.

_warnings names the count and the parameter that changes it whenever transactions were excluded, skipped, or carry no value.

Credits: 40 base, plus ceil(n / 1000) × 5 where n is the number of participating transactions. Both charges are recorded as one usage entry.

Errors: 404 OWNERSHIP_COMPANY_NOT_FOUND (charged), 403 PLAN_TIER_INSUFFICIENT_COVERAGE when the ticker is outside your plan's coverage scope (charged), 422 VALIDATION_ERROR, 402 CREDITS_INSUFFICIENT.

Example MCP tool call:

get_insider_stats(ticker="AAPL", start_date="2025-01-01", method="ad")

7.3 POST /ownership/transaction-ids

Purpose: Fetch transactions by id — the detail companion to the transaction_ids returned by §7.2.

Request:

FieldTypeDefaultNotes
transaction_idsint[]Required. 1–100 positive integers. Duplicates are removed with a _warnings entry.
pageint ≥ 11
page_sizeint 1–100100Counts filings.

Response: same envelope as §7.1, plus missing_ids when some ids were not found and restricted_ids when some exist but are outside your plan's scope. Both are charged for.

Credits: ceil(n / 5) × 10 on the deduplicated id count (max 200).

Errors: 404 OWNERSHIP_TRANSACTION_NOT_FOUND when none of the requested ids exist (charged; the response carries missing_ids). 403 PLAN_TIER_INSUFFICIENT_HISTORY when every requested id that exists is outside your plan's scope (charged; the response carries restricted_ids). Partial misses and partial restrictions return 200. 422 VALIDATION_ERROR, 402 CREDITS_INSUFFICIENT.

Example MCP tool call:

get_insider_transactions_by_id(transaction_ids=[123456, 123457])

7.4 GET /ownership/tickers

Purpose: Discovery — every ticker with insider-trade or initial-holdings coverage. Unpaginated; cache the result.

Response: tickers (array of {ticker, jurisdiction, cik, forms}), credits_used, and optional _warnings. forms lists what the ticker has on file: "4" insider transactions, "3" initial holdings.

Credits: 175.

Errors: 402 CREDITS_INSUFFICIENT.

Example MCP tool call:

list_insider_tickers()

7.5 POST /ownership/names

Purpose: All insiders of one company, aggregated per CIK across its Form 4 and Form 3 filings.

Request:

FieldTypeNotes
tickerstringRequired.
relationshipstring[]Any of ever_director, ever_officer, ever_ten_percent_owner, ever_other. OR semantics. This endpoint aggregates across every filing, so the filter means "ever reported in this role"; the per-filing is_* form is used by §7.2 and §6.5.

Response: names, credits_used, and optional _warnings. Each name carries:

FieldMeaning
owner_cik, owner_nameSpelling from this insider's most recent filing.
name_changedtrue when earlier filings spelled the name differently.
caveatPresent only when name_changed is true.
ever_director, ever_officer, ever_ten_percent_owner, ever_othertrue when any filing reported that role.
latest_officer_titleMost recent non-null officer title. null when never reported.
officer_title_as_ofFiling date latest_officer_title came from.
filing_countFilings of this company naming this insider, Form 4 and Form 3 together.
form4_filing_count, form3_filing_countThe same count per form.
earliest_filing_date, latest_filing_dateRange.

Credits: 30.

Errors: 404 OWNERSHIP_COMPANY_NOT_FOUND (charged), 403 PLAN_TIER_INSUFFICIENT_COVERAGE when the ticker is outside your plan's coverage scope (charged).

Example MCP tool call:

list_company_insiders(ticker="AAPL", relationship=["ever_officer"])

7.6 GET /ownership/transaction-types

Purpose: The SEC transaction-code catalog — 20 codes with their official name and grouping.

Response: transaction_types (array of {code, name, group}), source_url (the SEC form the wording is copied from), and credits_used.

Credits: 0. No charge, no usage entry.

Example MCP tool call:

list_insider_transaction_types()

Holding object

Returned by POST /ownership/initial-holdings, POST /ownership/initial-holding-ids, and POST /screener/initial-holdings. A Form 3 reports positions held on becoming an insider, so a holding has no transaction date, code, price, or direction.

FieldMeaning
idHolding id. Pass to POST /ownership/initial-holding-ids.
is_derivativeDerivative table row (true) or non-derivative (false).
security_title, direct_or_indirect, nature_of_ownershipAs filed.
shares_ownedAmount of securities beneficially owned, as filed. null on derivative rows (the form has no such column for them) and on cancelled rows.
footnote_refsFootnote ids for this holding. Resolve against the filing's footnotes map.
source_locatorCombine with the filing's source_url_prefix to build the SEC URL.
restatednull, "cancelled", "modified", or "added" — set when an amendment changed this holding.
priorPresent only when restated is set. The pre-amendment values.
split_adjustedPresent only when the filed values are not on the current per-share basis. See below.
data_quality_flagsPresent only when at least one rule fires. See below.

Derivative rows additionally carry conversion_or_exercise_price, exercise_date, expiration_date, underlying_security_title, underlying_security_shares, and underlying_security_value.

split_adjusted

Same meaning and presence rule as on the transaction object: present only when the filed values are not on the current per-share basis.

"split_adjusted": {
  "shares_owned": 4000.0,
  "underlying_security_shares": null,
  "conversion_or_exercise_price": null,
  "split_adjustment_factor": 4.0,
  "comparable_to_post_split_basis": false
}

data_quality_flags

Rows that fail a consistency check carry one or more of:

missing_shares_owned, missing_underlying_amount, derivative_date_order, negative_shares_owned, negative_underlying_security_shares, negative_underlying_security_value, negative_conversion_or_exercise_price, manual_flags.

Rows flagged manual_flags also carry a manual_flags array of {code, note} entries describing the issue.

Flagged rows are excluded from POST /ownership/initial-holdings, POST /ownership/initial-holdings/stats and POST /screener/initial-holdings unless include_anomalies=true (holding_filters.include_anomalies on the screener). Each endpoint reports how many it withheld: the listing in anomalies_excluded_on_page (this page only), stats and the screener in anomalies_excluded_count (the whole requested range).


7.7 POST /ownership/initial-holdings

Purpose: Anchored listing of initial beneficial-ownership filings (Form 3) and their holdings. Requires ticker and/or insider_cik; unanchored queries belong to §6.8.

Request:

FieldTypeDefaultNotes
tickerstringUppercased automatically.
insider_cikstringDigits only, ≤ 10; left-padded to 10.
relationshipstring[]omittedAny of is_director, is_officer, is_ten_percent_owner, is_other. OR semantics, evaluated per filing.
no_securities_ownedboolomittedtrue → only filings that report no holdings; false → only filings with holdings; omitted → both.
include_unresolved_amendmentsboolfalse
exclude_likely_mergedboolfalse
include_anomaliesboolfalse
pageint ≥ 11
page_sizeint 1–10050Counts filings.

At least one of ticker / insider_cik is required (422 otherwise).

Response:

FieldMeaning
page, page_size, has_more, next_pagePagination.
anomalies_excluded_on_pageHow many holdings on this page were withheld because they failed a consistency check. 0 when include_anomalies=true. Page-scoped, independent of the whole-range anomalies_excluded_count on POST /ownership/initial-holdings/stats.
filingsArray. Each carries id, ticker, issuer, issuer_cik, accession_number, form_type, filing_date, period_of_report, date_of_original_submission, merge_status, remarks, no_securities_owned, source_url_prefix, insiders, footnotes, holdings, and amendments (present only when amendments were merged).
filings[].no_securities_ownedtrue when the filer reported holding no securities; such filings have an empty holdings array.
filings[].insiderscik, name, is_director, is_officer, is_ten_percent_owner, is_other, officer_title, other_text.
filings[].footnotesMap of footnote id → text for this filing.
_warningsOptional.
credits_usedAlways 30.

Credits: 30 per page.

Errors: 404 OWNERSHIP_COMPANY_NOT_FOUND (charged), 403 PLAN_TIER_INSUFFICIENT_COVERAGE when the ticker is outside your plan's coverage scope (charged), 422 VALIDATION_ERROR, 402 CREDITS_INSUFFICIENT.

Example MCP tool call:

list_initial_holdings(ticker="TSLA", page_size=5)

7.8 POST /ownership/initial-holdings/stats

Purpose: Aggregate statistics over the Form 3 filings of one company and/or one insider, plus the ids of every holding that contributed.

Request:

FieldTypeDefaultNotes
tickerstring
insider_cikstring
start_date, as_of_dateISO dateWindow on filing_date. as_of_date ≤ today; start_dateas_of_date.
include_anomaliesboolfalse
relationshipstring[]omittedAny of is_director, is_officer, is_ten_percent_owner, is_other. OR semantics, evaluated per filing.
is_derivativeboolomittedRestricts the holding totals; filing counts are unaffected.
exclude_likely_mergedboolfalse
include_unresolved_amendmentsboolfalse
ids_pageint ≥ 11Paginates holding_ids only.
ids_page_sizeint 1–1000200

At least one of ticker / insider_cik is required.

Response: stats, start_date_applied, as_of_date_applied, anomalies_excluded_count, credits_used, optional corporate_actions, optional _warnings, then ids_total, ids_page, ids_has_more, holding_ids.

stats fieldMeaning
filing_countForm 3 filings in scope.
no_securities_filing_countOf those, filings that report no holdings.
distinct_insidersDistinct reporting owners in scope.
filings_with_multiple_filersJoint filings in scope.
holdings_count, holdings_count_non_derivative, holdings_count_derivativeHolding rows in scope.
shares_owned_totalSum of shares_owned over non-derivative rows, on the split-adjusted basis.
underlying_shares_totalSum of underlying_security_shares over derivative rows, on the split-adjusted basis.
earliest_filing_date, latest_filing_dateRange actually covered.
corporate_action_crossingtrue when the window spans a corporate action.

corporate_actions is present only when the request is anchored on a ticker that has corporate actions on file: an array of {ex_date, ratio, type, event_type}.

_warnings names the count and the parameter that changes it whenever holdings were excluded.

Credits: 40 base, plus ceil(n / 1000) × 5 where n is the number of participating holdings. Both charges are recorded as one usage entry.

Errors: 404 OWNERSHIP_COMPANY_NOT_FOUND (charged), 403 PLAN_TIER_INSUFFICIENT_COVERAGE when the ticker is outside your plan's coverage scope (charged), 422 VALIDATION_ERROR, 402 CREDITS_INSUFFICIENT.

Example MCP tool call:

get_initial_holding_stats(ticker="TSLA", start_date="2020-01-01")

7.9 POST /ownership/initial-holding-ids

Purpose: Fetch holdings by id — the detail companion to the holding_ids returned by §7.8.

Request:

FieldTypeDefaultNotes
holding_idsint[]Required. 1–100 positive integers. Duplicates are removed with a _warnings entry.
pageint ≥ 11
page_sizeint 1–100100Counts filings.

Response: same envelope as §7.7, plus missing_ids when some ids were not found and restricted_ids when some exist but are outside your plan's scope. Both are charged for.

Credits: ceil(n / 5) × 10 on the deduplicated id count (max 200).

Errors: 404 OWNERSHIP_HOLDING_NOT_FOUND when none of the requested ids exist (charged; the response carries missing_ids). 403 PLAN_TIER_INSUFFICIENT_HISTORY when every requested id that exists is outside your plan's scope (charged; the response carries restricted_ids). Partial misses and partial restrictions return 200. 422 VALIDATION_ERROR, 402 CREDITS_INSUFFICIENT.

Example MCP tool call:

get_initial_holdings_by_id(holding_ids=[1234, 1235])

Snapshot object

Returned by POST /screener/institutional-holdings (as matches[], with cik and name) and POST /ownership/institutional-holdings/manager-history (as quarters[], without them — the manager identity sits once at the top of that response). One row = one manager × one calendar quarter, after amendments are merged.

FieldMeaning
cik, nameThe filing manager. Screener rows only.
periodCalendar quarter end the report covers.
filing_date, accessionThe filing this quarter's data comes from.
is_combination_reporttrue = 13F COMBINATION REPORT (the filer also reports holdings managed by other managers), false = 13F HOLDINGS REPORT.
confidentialThe quarter carries confidential-treatment holdings.
is_amendedAmendments were merged into this quarter. The full archive is on the portfolio endpoint's quarter header.
unit_multiplier1, or the whole-quarter unit-correction multiplier applied to the filed values. When it is not 1, unit_multiplier_reason (corrected_error or pre2023_rule) is present; the key is omitted when null.
total_positions_valueTotal value of the stock holdings, USD.
total_derivatives_notionalTotal notional of the option holdings, USD.
cover_table_valueThe cover-page total as filed, verbatim.
positions_count, derivatives_countLive stock / option rows in the quarter.
portfolio_value_qoq_pctQuarter-over-quarter change of total_positions_value, percent.
top1_security_pct, top10_security_pctPortfolio share of the largest / ten largest stock holdings, percent (stock holdings only).
est_turnoverEstimated traded value versus the prior quarter, USD.
activity_countsMap of row activity → count: NEW, ADD, REDUCE, HOLD, SOLD_OUT, CUSIP_CHANGE.
sec_urlThe URL opens the filing's EDGAR index page; see the files listed there for full details.

Each manager's earliest quarter in the data window has no prior quarter to compare against: its portfolio_value_qoq_pct, est_turnover and activity_counts are null and must not be read as everything being new.

Institutional holding object

Returned by POST /ownership/institutional-holdings/portfolio and POST /ownership/institutional-holdings/security (flat mode) as transactions[]. Security rows additionally carry manager_cik / manager_name. Three row kinds, told apart by type:

  • positions — a stock holding.
  • derivatives — an option holding (put_call says which side).
  • exited — a position closed out this quarter: identity plus the closing deltas only (d_shares, and d_value or d_notional_value_usd).
FieldMeaning
type, periodRow kind and calendar quarter end.
cusip, ticker, ticker_status, issuer, issuer_norm, class, security_typeSecurity identity. issuer is the name as filed, issuer_norm the normalized name, class the share-class text as filed. ticker_status is us_listing, when_issued, non_us_listing, none (no matching listed ticker), or null.
put_call"Put" / "Call" on option rows; null on stock rows. When the row kinds are mixed it is one of the fields telling them apart.
shares_or_principal_amountSH = the row's shares is a share count; PRN = a principal amount in USD (debt securities), not a share count; null = a row cancelled by an amendment, or missing in the original filing.
sharesShare count or principal amount, per the previous field.
vote_sole, vote_shared, vote_noneVoting-authority split as filed.
discretionInvestment discretion as filed (SOLE, DFND, OTR and combinations).
source_accessionsThe amendment filings this row's current values come from; null = the quarter's main filing.
activityNEW / ADD / REDUCE / HOLD / CUSIP_CHANGE versus the prior quarter. Null on each manager's earliest data-window quarter. Exited rows carry no activity label — the exit is the row itself.
predecessor_cusipOn CUSIP_CHANGE rows: the CUSIP this security was held under in the prior quarter.
shares_before_cusip_changeShares held under the predecessor CUSIP; present only when non-null, directly after predecessor_cusip.
d_pctShare change versus the prior quarter, percent (d_shares is the absolute change).
unit_multiplierRow-level unit-correction multiplier (can be fractional, e.g. 0.001); present when this row's filed value was individually corrected.
restatedadded / modified / cancelled when an amendment changed this row; null otherwise. A cancelled row is a tombstone: its current-value fields are null and the old values sit in prior_versions.
prior_versionsPre-amendment field values, newest first.
submgr_breakdownSub-manager split of the position: {submgr_index, submgr_name, shares, pct_of_position}.

Stock rows additionally carry value (USD), weight (this holding's share of the quarter's total_positions_value — a percent string with two decimals, e.g. "61.88%"; null on cancelled rows), rank (1 = the quarter's largest stock holding), avg_price, and d_value. Option rows carry notional_value_usd, underlying_price_implied, and d_notional_value_usd.

Warnings (_warnings, present only when non-empty) on the portfolio / security endpoints flag:

  • an amendment whose claimed action type differs from its actual action (portfolio only — see the claimed_type and action fields in quarter.amendments_merged);
  • unit-correction multipliers in the returned result, whole-quarter or row-level — see the unit_multiplier fields;
  • CUSIP_CHANGE rows in the returned result — see each row's predecessor_cusip;
  • a manager's earliest data-window quarter in the returned result — activity, d_shares, d_value, d_pct and the quarter's est_turnover, portfolio_value_qoq_pct, activity_counts are null there and must not be read as everything being new.

7.10 POST /ownership/institutional-holdings/manager-history

Purpose: One manager's 13F history — one snapshot object per quarter filed, newest first by default.

Request:

FieldTypeDefaultNotes
cikstring13F filer CIK, digits verbatim (not zero-padded). Provide exactly one of cik / name.
namestringManager name, filed or normalized spelling. Whitespace and case are ignored; otherwise the match is exact.
sort_order"desc" | "asc""desc"By period.
pageint ≥ 11
page_sizeint 1–10050Counts quarters.

Response: manager (cik, name, sec_url_prefix — the manager's EDGAR directory prefix), quarters (snapshot rows), total_quarters, page, page_size, credits_used.

Credits: 30.

Errors: 404 OWNERSHIP_MANAGER_NOT_FOUND when no single manager matches (charged) — several managers can file under the same or a similar name; query by CIK instead. 422 VALIDATION_ERROR, 402 CREDITS_INSUFFICIENT.

Example MCP tool call:

get_institutional_manager_history(cik="1000097", page_size=8)

7.11 POST /ownership/institutional-holdings/portfolio

Purpose: One manager × one quarter — the holdings detail as institutional holding objects, under a quarter header that repeats the snapshot numbers and carries the amendment archive.

Request:

FieldTypeDefaultNotes
cik / namestringExactly one, as in §7.10.
quarterstringRequired. Calendar quarter label YYYYQn, e.g. 2026Q1 (Q1 = Mar 31, Q2 = Jun 30, Q3 = Sep 30, Q4 = Dec 31).
typestringomittedpositions / derivatives / exited. Omitted = all three; each row carries its own type. The response echoes the filter as types.
activitystring[]omitted≤ 6 of NEW, ADD, REDUCE, HOLD, CUSIP_CHANGE. Unknown values are dropped with a _warnings entry. Exited rows carry no activity label, so combined with type="exited" the filter matches nothing (a warning says so).
restatedstring[]omitted≤ 3 of added, modified, cancelled.
cusipstringomitted9 characters; pins one security inside the quarter. Give cusip or ticker, not both.
tickerstringomittedUppercased automatically.
sort_bystringomittedperiod, d_shares, ticker, issuer_norm, type (row kind as text, alphabetical: derivatives < exited < positions). Omitted = the filed row order.
sort_order"desc" | "asc""desc"
pageint ≥ 11
page_sizeint 1–10050Counts rows after filtering, all kinds together.

Response: manager (as in §7.10); quarter — a snapshot object plus accessions (every filing applied to the quarter, in order), sec_locators (accession → EDGAR index-page path; combine with the manager's sec_url_prefix), amendments_merged (see below) and prior_versions (superseded cover pages); then types, transactions, total_transactions, page, page_size, credits_used, and _warnings (see the institutional holding object).

amendments_merged — one entry per amendment applied to the quarter: accession, filing_date, claimed_type (the type the amendment declared for itself, or null), action (what it actually did: REPLACE / MERGE_ADD / DUPLICATE_SUPERSEDED / REJECTED), cover_total, confidential, and positions_added / positions_restated / positions_cancelled.

Credits: 30 per page.

Errors: 404 OWNERSHIP_MANAGER_NOT_FOUND (charged); 404 OWNERSHIP_MANAGER_QUARTER_NOT_FOUND when the manager exists but no 13F data was found for that quarter (charged); 422 VALIDATION_ERROR, 402 CREDITS_INSUFFICIENT.

Example MCP tool call:

get_institutional_portfolio(cik="1000097", quarter="2026Q1", type="positions", page_size=50)

7.12 POST /ownership/institutional-holdings/security

Purpose: One security's holder rows across managers — who holds it, quarter by quarter. Flat mode returns institutional holding objects with manager_cik / manager_name on each row; group_by_quarter=true switches to one aggregate row per quarter.

Request:

FieldTypeDefaultNotes
cusipstring9 characters. Provide exactly one of cusip / ticker.
tickerstringUppercased automatically. A ticker can match several CUSIPs (share classes, renumberings); rows for all of them are included, securities lists each one, and a _warnings entry says how many matched.
quarterstringomittedYYYYQn. Omitted = every quarter, newest first.
typestringomittedAs in §7.11.
activitystring[]omittedAs in §7.11.
group_by_quarterboolfalsetrue → one aggregate row per quarter (period, holders, total_shares, total_value, computed over live stock rows), unpaged; type / activity / sort_by / page are ignored with a warning.
sort_bystringomittedperiod, d_shares, ticker, issuer_norm, type. Omitted = newest quarter first.
sort_order"desc" | "asc""desc"
pageint ≥ 11
page_sizeint 1–10050

Response: securities — one entry per matched CUSIP: cusip, ticker, ticker_status, issuer_norm, security_type, first_seen / last_seen (first / latest quarter end the security appears in), latest_holders (holder count at last_seen); then group_by_quarter, credits_used, and either the flat fields (types, transactions, total_transactions, page, page_size) or the grouped ones (transactions, total_transactions — no paging fields).

Credits: 30 per page (flat mode); 40 flat (group_by_quarter=true, unpaged).

Errors: 404 OWNERSHIP_SECURITY_NOT_FOUND (charged), 422 VALIDATION_ERROR, 402 CREDITS_INSUFFICIENT.

Example MCP tool call:

get_institutional_security_holders(ticker="AAPL", quarter="2026Q1", page_size=50)

8. API key, account, and plan errors

HTTPWhen
401AUTH_API_KEY_MISSING — no X-API-Key header and no bearer token.
403AUTH_API_KEY_INVALID — unknown or inactive key.
403AUTH_USER_INACTIVE — the key's account is inactive or deleted.
403AUTH_EMAIL_NOT_VERIFIED — the key's account has not verified its email.
403AUTH_API_KEY_EXPIRED — key past its expiry.
403AUTH_API_KEY_INACTIVE — key disabled by inactivity policy.
403PLAN_TIER_INSUFFICIENT — the endpoint is not available on the caller's current plan.
403PLAN_TIER_INSUFFICIENT_HISTORY — the requested filing is older than what the caller's current plan covers. Body also carries filing_fiscal_year and earliest_allowed_fiscal_year.
403PLAN_TIER_INSUFFICIENT_FORMULA_OVERRIDE — the formula_override request field is not available on the caller's current plan. Omit formula_override to proceed, or upgrade.
403PLAN_TIER_INSUFFICIENT_COVERAGE — the requested company or filing is outside the caller's plan's coverage scope. Body also carries coverage_band.

Every PLAN_TIER_* response includes required_tier and current_tier strings (lowercase plan names) in the detail body so clients can prompt for an upgrade without parsing the message text.


9. Request limits (validation)

These caps apply at validation time (422 when exceeded):

LimitValue
Line items per request (/data/line-items, /data/compare/line-items)50
Fact ids per request (/data/facts)500
Fact ids per row (/data/compare/facts)500
Total fact ids (/data/compare/facts)2500
Filings per compare request25
Metric names (/metric/items, optional /metric/historical)100
Concepts per metric in formula_override (/metric/all, /metric/items, /metric/historical)50
Form types (/metric/filings)8
Historical page size5

10. MCP access

The Data and Metrics API is also exposed as a Model Context Protocol (MCP) server at:

https://api.akkrudata.ai/mcp

Authenticate via one of the two methods below. Both share your AkkruData account, credits, and rate limits. A tool call that includes an argument the tool does not declare is rejected before it runs and is not charged.

For AI clients with built-in MCP support (Claude Desktop, Claude Web, etc.):

  1. In your AI client, add https://api.akkrudata.ai/mcp as a custom MCP connector.
  2. Click Connect. Your browser will open an AkkruData sign-in page.
  3. Sign in with the same credentials you use for the dashboard (email/password, Google, or GitHub).
  4. Review the connecting AI client's reported identity, then click Authorize.
  5. Done. The AI client now holds a token and can call AkkruData on your behalf. Token renewal is automatic.

You can list and disconnect any authorized AI client at any time from the dashboard's Connected AI assistants panel. A single account may have up to 10 simultaneous AI client connections.

10.2 Connect via X-API-Key (programmatic use)

Available only on deployments where MCP OAuth is disabled.

For scripted MCP clients, local development, or any setup where you cannot run the OAuth browser flow:

URL:     https://api.akkrudata.ai/mcp
Header:  X-API-Key: <your-api-key>

The same API key used for REST works for MCP. Create and rotate keys from the dashboard.

10.3 Tool catalog

MCP toolDocumentation
list_filingsPOST /data/filings
lookup_companyPOST /data/company
list_companiesGET /data/company/list
query_line_itemsPOST /data/line-items
get_filing_factsPOST /data/facts
get_filing_statementPOST /data/statement
list_filing_statementsPOST /data/filing-statements
get_income_statementPOST /data/income-statement
get_comprehensive_incomePOST /data/comprehensive-income
get_balance_sheetPOST /data/balance-sheet
get_cash_flow_statementPOST /data/cash-flow-statement
get_equity_statementPOST /data/equity-statement
get_dimensional_breakdown_by_fact_idPOST /data/facts/dimensional-breakdown
get_dimensional_breakdown_by_line_itemPOST /data/line-items/dimensional-breakdown
compare_line_itemsPOST /data/compare/line-items
compare_factsPOST /data/compare/facts
get_filing_excelGET /data/filings/{filing_id}/excel
list_metric_snapshotsPOST /metric/filings
get_metrics_bundlePOST /metric/all
get_metrics_bundle_filing_datePOST /metric/all/filing-date
get_metrics_subsetPOST /metric/items
get_profitability_metricsPOST /metric/profitability
get_growth_metricsPOST /metric/growth
get_financial_health_metricsPOST /metric/financial-health
get_efficiency_metricsPOST /metric/efficiency
get_cash_flow_metricsPOST /metric/cash-flow
get_valuation_metricsPOST /metric/valuation
get_valuation_metrics_filing_datePOST /metric/valuation/filing-date
get_metrics_timeseriesPOST /metric/historical
search_stocksPOST /screener/metrics
list_screener_filtersGET /screener/metrics/filters
list_insider_transactionsPOST /ownership/transactions
get_insider_statsPOST /ownership/stats
get_insider_transactions_by_idPOST /ownership/transaction-ids
search_insider_tradesPOST /screener/ownership
list_insider_tickersGET /ownership/tickers
list_company_insidersPOST /ownership/names
list_insider_transaction_typesGET /ownership/transaction-types
list_initial_holdingsPOST /ownership/initial-holdings
get_initial_holding_statsPOST /ownership/initial-holdings/stats
get_initial_holdings_by_idPOST /ownership/initial-holding-ids
search_initial_holdingsPOST /screener/initial-holdings
get_institutional_manager_historyPOST /ownership/institutional-holdings/manager-history
get_institutional_portfolioPOST /ownership/institutional-holdings/portfolio
get_institutional_security_holdersPOST /ownership/institutional-holdings/security
search_institutional_holdingsPOST /screener/institutional-holdings

Each linked section includes an Example MCP tool call with the exact tool name, arguments to pass, and the response shape to expect.


AkkruData — API & MCP user guide.