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
| Section | Link |
|---|---|
| 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) | → |
| 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 | → |
| 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:
| Header | Value |
|---|---|
X-API-Key | Your API key (create and manage keys in the product dashboard after sign-in). |
For POST requests with a JSON body, also send:
| Header | Value |
|---|---|
Content-Type | application/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.
A small number of authentication failures (401 missing API key, 403 invalid API key) still return "detail" as a plain string. Any other 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
caveatfield on the filing information itself (top-level for single-filing responses; per-row inresults[]for compare endpoints; per-item infilings[]for the listing endpoint). Eithernull/ absent (no caveat), or a string. - A
_warningsentry of the formFiling <TICKER> <FORM> FY<YEAR>[ <QUARTER>] has caveat: <text>. Compare endpoints aggregate per-filing caveats into a single deduplicated_warningslist.
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 L1 (alias) 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.
| Workflow | Endpoint pattern | Typical credits |
|---|---|---|
| Discover one company (identity + coverage map) | POST /data/company | 8 |
| List all filings for one company-year | POST /data/filings | 10 |
| Pull all three primary statements (income / balance / cash flow) for one filing | POST /data/income-statement + /balance-sheet + /cash-flow-statement | 84 (28 × 3) |
| Pull a few specific line items from one filing (3 items × L1) | POST /data/line-items | 60 (3 × 20) |
| Five-year trend on one metric for one company | POST /data/line-items × 5 filings, 1 item, L1 | 100 (5 × 20) |
| Peer comparison: 5 companies × 1 metric × 1 year (L1) | POST /data/compare/line-items | 100 (1 × 20 × 5) |
| All key metrics snapshot for one company (1 call) | POST /metric/all | 148 |
| 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 workbook | GET /data/filings/{id}/excel | 300 |
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 (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, 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 reports 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" }
}
| Field | Meaning |
|---|---|
sectors | One or two of the 12 canonical buckets — primary first, plus an optional secondary when a code genuinely spans two. |
source.scheme | US_SIC (US, SEC SIC), KR_KSIC (Korea, KSIC), JP_TSE33 (Japan, TSE 33-sector), or EU_ICB (Europe, ICB). |
source.code | The company's official industry code as filed. |
source.url | Official 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.
| Endpoint | Credits |
|---|---|
POST /data/filings | 10 per successful debit. Debited even if the returned filings list is empty. |
POST /data/company | 8 per successful debit. Debited even if DATA_COMPANY_NOT_FOUND is returned. |
GET /data/company/list | 175 per successful debit. |
POST /data/line-items | Sum 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/facts | ceil(n / 5) × 10 where n is the number of deduplicated fact ids. |
POST /data/statement (role_label mode) | Tier exact=28, llm=48. If your balance is less than the tier price, you may be charged up to your remaining balance. |
POST /data/statement (statement_type mode) | 28 flat per successful debit. No charge for DATA_STATEMENT_NOT_AVAILABLE_IN_FILING. |
POST /data/filing-statements | 10 per successful debit. Debited even if the filing is missing. |
POST /data/income-statement | 28 per successful debit. No charge for DATA_STATEMENT_NOT_AVAILABLE_IN_FILING. |
POST /data/comprehensive-income | 28 per successful debit. No charge for DATA_STATEMENT_NOT_AVAILABLE_IN_FILING. |
POST /data/balance-sheet | 28 per successful debit. No charge for DATA_STATEMENT_NOT_AVAILABLE_IN_FILING. |
POST /data/cash-flow-statement | 28 per successful debit. No charge for DATA_STATEMENT_NOT_AVAILABLE_IN_FILING. |
POST /data/equity-statement | 28 per successful debit. No charge for DATA_STATEMENT_NOT_AVAILABLE_IN_FILING. |
POST /data/facts/dimensional-breakdown | ceil((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-breakdown | Tier credit for line_item (L0=10 … L3=50) + ceil(N_total / 5) × 10 for returned slice facts. Partial billing applies. |
POST /data/compare/line-items | For 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/facts | ceil(total_deduplicated_ids / 5) × 10 across all filing rows. |
GET /data/filings/{filing_id}/excel | 300 when the download is issued. |
POST /metric/filings | 10 |
POST /metric/all | 148 |
POST /metric/all/filing-date | 148 |
POST /metric/items | 148 |
POST /metric/profitability | 148 |
POST /metric/growth | 148 |
POST /metric/financial-health | 148 |
POST /metric/efficiency | 148 |
POST /metric/cash-flow | 148 |
POST /metric/valuation | 148 |
POST /metric/valuation/filing-date | 148 |
POST /metric/historical | 55 base fee, plus 148 × (number of filing rows returned on the current page). Default page size is 3 filing rows max. |
POST /screener/metrics | Dynamic 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/filters | 10 per call. |
POST /ownership/transactions | 30 per page. Debited even if OWNERSHIP_COMPANY_NOT_FOUND is returned. |
POST /ownership/stats | 40 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-ids | ceil(n / 5) × 10 where n is the number of deduplicated ids (max 200). |
POST /screener/ownership | Dynamic 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/tickers | 175 per successful debit. |
POST /ownership/names | 30 per successful debit. Debited even if OWNERSHIP_COMPANY_NOT_FOUND is returned. |
GET /ownership/transaction-types | 0 — static catalog, no charge. |
GET /billing/balance | 0 — 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):
| Method | Path | Limit |
|---|---|---|
| POST | /data/filings | 100 |
| POST | /data/company | 100 |
| GET | /data/company/list | 60 |
| POST | /data/line-items | 100 |
| POST | /data/facts | 100 |
| POST | /data/statement | 60 |
| POST | /data/filing-statements | 100 |
| POST | /data/income-statement | 60 |
| POST | /data/comprehensive-income | 60 |
| POST | /data/balance-sheet | 60 |
| POST | /data/cash-flow-statement | 60 |
| POST | /data/equity-statement | 60 |
| POST | /data/facts/dimensional-breakdown | 60 |
| POST | /data/line-items/dimensional-breakdown | 60 |
| POST | /data/compare/line-items | 60 |
| POST | /data/compare/facts | 60 |
| GET | /data/filings/{filing_id}/excel | 20 |
| POST | /metric/filings | 100 |
| POST | /metric/all | 60 |
| POST | /metric/all/filing-date | 60 |
| POST | /metric/items | 60 |
| POST | /metric/profitability | 60 |
| POST | /metric/growth | 60 |
| POST | /metric/financial-health | 60 |
| POST | /metric/efficiency | 60 |
| POST | /metric/cash-flow | 60 |
| POST | /metric/valuation | 60 |
| POST | /metric/valuation/filing-date | 60 |
| POST | /metric/historical | 60 |
| POST | /screener/metrics | 10 |
| GET | /screener/metrics/filters | 60 |
| POST | /screener/ownership | 10 |
| POST | /ownership/transactions | 100 |
| POST | /ownership/stats | 60 |
| POST | /ownership/transaction-ids | 100 |
| GET | /ownership/tickers | 60 |
| POST | /ownership/names | 60 |
| GET | /ownership/transaction-types | 60 |
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
caveatfield on the filing information and mirrored to the response's_warningslist. 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:
| Field | Type | Required | Notes |
|---|---|---|---|
ticker | string | Yes | 1–32 characters; matched case-insensitively. |
fiscal_year | integer | Yes | 1990–2100. |
form_type | string | No | Max 32 characters. US forms: 10-K, 10-Q. Foreign-issuer annual reports: 20-F (US-listed foreign companies), 40-F (Canadian filers). Korean (DART) and Japanese (EDINET) 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. |
quarter | string | No | Max 4 characters (e.g. Q1). Use when you need a single quarterly filing among several. |
Response:
| Field | Meaning |
|---|---|
credits_used | Always 10 when successful. |
fiscal_year | Echo of request. |
form_type | Present only if you sent form_type. |
quarter | Present only if you sent quarter. |
company | Company profile (ticker, cik, legal_name) or null if unknown. |
filings | Array 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:
| HTTP | error_code | When |
|---|---|---|
| 402 | CREDITS_INSUFFICIENT | Not enough credits. |
| 422 | — | Validation (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:
| Field | Type | Required | Notes |
|---|---|---|---|
ticker | string | Conditional | Exactly one of ticker, cik, dart_corp_code, or edinet_code must be provided. 1–32 characters; case-insensitive. |
cik | string | Conditional | Numeric string; zero-padded to 10 digits on the server side. SEC-listed companies only. |
dart_corp_code | string | Conditional | Numeric string; zero-padded to 8 digits on the server side. Korean DART-listed companies only. |
edinet_code | string | Conditional | EDINET issuer code (E + 5 digits). Japanese EDINET-listed companies only. |
Response:
| Field | Meaning |
|---|---|
ticker, cik, dart_corp_code, edinet_code, lei, legal_name | Company 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; 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. |
sec_filings_url | EDGAR public browse URL for the company, derived from CIK. Omitted for companies with no CIK (e.g. Korean and Japanese companies). |
dart_filings_url | DART 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_url | EDINET 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_url | filings.xbrl.org public browse URL for the company, derived from lei. Omitted for companies with no LEI. |
filings_count | Total filings we hold for this company across all forms and years. |
coverage | Object keyed by filing-type name. US: SEC form names ("10-K", "10-Q", "20-F", "40-F"). KR / JP / EU: 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_used | Always 8 when successful. |
Charging: A DATA_COMPANY_NOT_FOUND response is still charged 8 credits.
Errors:
| HTTP | error_code | When |
|---|---|---|
| 404 | DATA_COMPANY_NOT_FOUND | No company on file for the given identifier. Still debits 8 credits. |
| 403 | PLAN_TIER_INSUFFICIENT_COVERAGE | The requested company is outside your plan's coverage scope. |
| 402 | CREDITS_INSUFFICIENT | Not enough credits. |
| 422 | — | Validation (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:
| Query | Type | Default | Notes |
|---|---|---|---|
jurisdiction | string | (omitted) | Optional. "US", "KR", "JP", "EU", or "all". When omitted, returns everything your plan includes. |
Response:
| Field | Meaning |
|---|---|
companies | Array 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), or lei (European); the others are omitted. All are omitted for the rare row whose identifier is not yet on file. |
companies[].classification | Industry classification block — Pro+ only, omitted otherwise. See §1.10. |
credits_used | Always 175 when successful. |
Errors:
| HTTP | error_code | When |
|---|---|---|
| 403 | PLAN_TIER_INSUFFICIENT_COVERAGE | The requested jurisdiction is outside your plan's coverage scope. |
| 402 | CREDITS_INSUFFICIENT | Not enough credits. |
| 400 | JURISDICTION_INVALID | jurisdiction is not one of US, KR, JP, EU, all. |
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"}
],
"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:
| Field | Type | Required | Notes |
|---|---|---|---|
filing_id | integer | Conditional | 1–10⁹. If set, ticker/year fields are optional. |
ticker | string | Conditional | Required if filing_id omitted. 1–32 characters. |
form_type | string | No | Default 10-K, max 32. |
fiscal_year | integer | Conditional | Required if filing_id omitted. 1990–2100. |
quarter | string | No | Max 4 characters. |
line_items | array of string | Yes | Non-empty; max 50 entries; each entry max 256 characters. |
light_weight_mode | boolean | No | Default false. Recommended. When true, each results[*].dimensional_breakdowns is set to null. 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 are mutually exclusive on the wire — a row carries either the singular pair or the plural list, never both. Iterate by reading whichever is present.
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 raw XBRL 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:
| Field | Type | Required | Notes |
|---|---|---|---|
filing_id | integer | Conditional | 1–10⁹. If set, ticker/year fields are optional. |
ticker | string | Conditional | Required if filing_id omitted. 1–32 characters. |
form_type | string | No | Default 10-K, max 32. |
fiscal_year | integer | Conditional | Required if filing_id omitted. 1990–2100. |
quarter | string | No | Max 4 characters. |
fact_ids | array of string | Yes | Non-empty; max 500 strings; each max 128 characters. |
light_weight_mode | boolean | No | Default false. Recommended. Leaner response — see Light-weight mode below. Charged identically. |
Response:
| Field | Meaning |
|---|---|
ticker, form_type, fiscal_year, quarter | Filing identity. |
source_url_prefix | SEC viewer URL base for this filing. May be null. The API does not return full SEC URLs; callers concatenate source_url_prefix with each fact's source_locator. |
results | Array 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_used | ceil(deduped_fact_id_count / 5) × 10. |
amendment_context | Optional; same idea as under filings when applicable. |
_warnings | Optional 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:
| HTTP | error_code | When |
|---|---|---|
| 400 | DATA_FILING_QUARTER_REQUIRED | Several filings match without a quarter; message lists available quarters. |
| 404 | DATA_FILING_NOT_FOUND | No filing for the given id or identity. |
| 402 | CREDITS_INSUFFICIENT | Not enough credits. |
| 422 | — | Validation (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_labelmode — the filer's original XBRL role string (varies per filer; e.g."CONSOLIDATED STATEMENTS OF OPERATIONS"for Apple). Resolved through a tiered exact / llm path against the filing's role labels. Returns the one matched block.statement_typemode — the canonical statement name (e.g."Income Statement","Balance Sheet","Comprehensive Income","Stockholders Equity","Cash Flow Statement"). CallPOST /data/filing-statementsfor the valid values in a specific filing. Case-insensitive; trailing(N)suffix is ignored. Returns every matching block. Not yet available for Korean (DART), Japanese (EDINET), or European (ESEF) filings — coming soon (not charged); userole_labelmode for KR/JP/EU.
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:
| Field | Type | Required | Notes |
|---|---|---|---|
filing_id | integer | Conditional | Same rules as facts. |
ticker | string | Conditional | |
form_type | string | No | Default 10-K. |
fiscal_year | integer | Conditional | |
quarter | string | No | |
role_label | string | XOR statement_type | 1–4000 characters; original filer XBRL role string. |
statement_type | string | XOR role_label | 1–4000 characters; canonical statement-type label. |
light_weight_mode | boolean | No | Default false. Recommended. Leaner response — see Light-weight mode below. Charged identically. |
Credits:
role_labelmode: tiered 28 (exact) / 48 (llm), partial-credit billing. Zero-balance → HTTP 402.statement_typemode: 28 flat. No charge forDATA_STATEMENT_NOT_AVAILABLE_IN_FILING.
Response:
| Field | Meaning |
|---|---|
ticker, form_type, fiscal_year, quarter | Filing identity. |
matches | Array of match objects (length 1 for role_label mode; length 1+ for statement_type mode). Each has block_index, role_label, statement_type, matched_via (describes how it was selected), and block (the full statement block content). |
credits_used | Number of credits deducted. |
amendment_context | Optional; restatement or amendment information. |
_correction | Optional; present on the llm match tier. |
_warnings | Optional; 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,formathtml_locator:xlsx_sheet,xlsx_cell
A notice is appended to _warnings.
Errors:
| HTTP | error_code | When |
|---|---|---|
| 400 | DATA_FILING_QUARTER_REQUIRED | Ambiguous quarterly filings. |
| 404 | DATA_FILING_NOT_FOUND | Filing not found. |
| 404 | DATA_STATEMENT_ROLE_LABEL_UNRESOLVED | role_label mode: no block matched; charged for the match tier reached. |
| 404 | DATA_STATEMENT_NOT_AVAILABLE_IN_FILING | statement_type mode: no block has this statement_type (not charged). |
| 400 | DATA_STATEMENT_TYPE_UNSUPPORTED_FOR_KR | statement_type mode: Korean (DART) filings not yet supported — coming soon (not charged). |
| 400 | DATA_STATEMENT_TYPE_UNSUPPORTED_FOR_JP | statement_type mode: Japanese (EDINET) filings not yet supported — coming soon (not charged). |
| 400 | DATA_STATEMENT_TYPE_UNSUPPORTED_FOR_EU | statement_type mode: European (ESEF) filings not yet supported — coming soon (not charged). |
| 404 | DATA_STATEMENT_BLOCK_JSON_MISSING | Label matched but the block content is unavailable (charged). |
| 402 | CREDITS_INSUFFICIENT / CREDITS_ZERO_BALANCE | statement_type mode: insufficient for the flat price; role_label mode: zero balance. |
| 422 | — | Validation (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 (canonical statement-type label; may be 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:
| Field | Type | Required | Notes |
|---|---|---|---|
filing_id | integer | Conditional | |
ticker | string | Conditional | |
form_type | string | No | Default 10-K. |
fiscal_year | integer | Conditional | |
quarter | string | No |
Response:
| Field | Meaning |
|---|---|
ticker, form_type, fiscal_year, quarter | Filing identity. |
statements | Array of {block_index, statement_type, role_label}, ordered by block_index. |
credits_used | Always 10 when successful. |
Errors:
| HTTP | error_code | When |
|---|---|---|
| 400 | DATA_FILING_QUARTER_REQUIRED | Ambiguous quarterly filings. |
| 404 | DATA_FILING_NOT_FOUND | Filing not found. Still charged 10 credits (this matches /data/filings and /data/company — discovery endpoints charge to cover the lookup attempt). |
| 402 | CREDITS_INSUFFICIENT | Insufficient credits. |
| 422 | — | Validation. |
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, rate limit 60/minute. No charge on DATA_STATEMENT_NOT_AVAILABLE_IN_FILING. Not yet available for Korean (DART), Japanese (EDINET), or European (ESEF) filings — coming soon (not charged).
| Endpoint | Statement returned |
|---|---|
POST /data/income-statement | Income Statement |
POST /data/comprehensive-income | Statement of Comprehensive Income |
POST /data/balance-sheet | Balance Sheet |
POST /data/cash-flow-statement | Cash Flow Statement |
POST /data/equity-statement | Statement of Stockholders' / Shareholders' Equity |
Request body: same fields as POST /data/statement minus role_label and statement_type.
| Field | Type | Required | Notes |
|---|---|---|---|
filing_id | integer | Conditional | |
ticker | string | Conditional | |
form_type | string | No | Default 10-K. |
fiscal_year | integer | Conditional | |
quarter | string | No | |
light_weight_mode | boolean | No | Default false. Recommended. |
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:
| Field | Type | Required | Notes |
|---|---|---|---|
filing_id | integer | Conditional | |
ticker | string | Conditional | |
form_type | string | No | Default 10-K. |
fiscal_year | integer | Conditional | |
quarter | string | No | |
fact_id | string | Yes | The fact_id of a consolidated fact. |
recursive | boolean | No | Default true. When false, only the immediate children are returned. |
Response:
| Field | Meaning |
|---|---|
ticker, form_type, fiscal_year, quarter, source_url_prefix | Filing identity. |
root | The 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. |
groups | Array 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[].groups | Present only when recursive=true. Same shape, nested per level. |
_warnings | Optional. |
credits_used | ceil((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:
| HTTP | error_code | When |
|---|---|---|
| 400 | DATA_FILING_QUARTER_REQUIRED | Ambiguous quarterly filings. |
| 404 | DATA_FILING_NOT_FOUND | Filing not found. |
| 404 | DATA_FACT_NOT_FOUND | fact_id is not present in this filing. Still charged 10 credits. |
| 402 | CREDITS_INSUFFICIENT | Not enough credits. |
| 422 | — | Validation. |
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.
Filing selection: standard (filing_id or ticker + fiscal_year + form_type + optional quarter).
Request:
| Field | Type | Required | Notes |
|---|---|---|---|
filing_id | integer | Conditional | |
ticker | string | Conditional | |
form_type | string | No | Default 10-K. |
fiscal_year | integer | Conditional | |
quarter | string | No | |
line_item | string | Yes | A single line-item name (e.g. "revenue"). |
recursive | boolean | No | Default true. |
Response:
| Field | Meaning |
|---|---|
ticker, form_type, fiscal_year, quarter, source_url_prefix | Filing identity. |
matches | Array of {root, groups, duplicate_root_fact_ids?} entries. |
matches[].root | Same shape as root in POST /data/facts/dimensional-breakdown, plus metric (echoes the request line_item) and _resolution_level ("L0"–"L3"). |
matches[].groups | Same shape and ordering as groups in POST /data/facts/dimensional-breakdown. Each fact also carries metric and _resolution_level. |
matches[].duplicate_root_fact_ids | Optional. Other fact_id values that resolved to the same logical fact as root. |
_correction | Optional. Same shape as on POST /data/line-items. |
_warnings | Optional. |
credits_used | Resolver 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:
| HTTP | error_code | When |
|---|---|---|
| 400 | DATA_FILING_QUARTER_REQUIRED | Ambiguous quarterly filings. |
| 404 | DATA_FILING_NOT_FOUND | Filing not found. |
| 402 | CREDITS_ZERO_BALANCE | Balance is zero. |
| 402 | CREDITS_INSUFFICIENT | Insufficient credits. |
| 422 | — | Validation. |
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.
Request:
| Field | Type | Required | Notes |
|---|---|---|---|
filings | array | Yes | 1–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_items | array of string | Yes | Non-empty; max 50 strings; each max 256 chars. |
light_weight_mode | boolean | No | Default false. Recommended. Leaner response — see Light-weight mode below. Charged identically. |
Response:
| Field | Meaning |
|---|---|
amendment_contexts | Array parallel to results; each entry is an object or null. |
results | Each 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_used | Per credit rules in Section 2. |
_correction, _warnings | Optional; same general meaning as POST /data/line-items. 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:
| HTTP | error_code | When |
|---|---|---|
| 400 | DATA_FILING_QUARTER_REQUIRED | A row needs quarter to disambiguate. |
| 404 | DATA_FILING_NOT_FOUND | A row’s filing does not exist (message may reference row index). |
| 402 | CREDITS_ZERO_BALANCE | Zero balance. |
| 422 | — | Limits, 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:
| Field | Type | Required | Notes |
|---|---|---|---|
filings | array | Yes | 1–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_mode | boolean | No | Default false. Recommended. Leaner response — see Light-weight mode below. Charged identically. |
Response: Same shape as POST /data/compare/line-items.
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:
| HTTP | error_code | When |
|---|---|---|
| 400 | DATA_FILING_QUARTER_REQUIRED | A row needs quarter to disambiguate. |
| 404 | DATA_FILING_NOT_FOUND | A row’s filing does not exist. |
| 402 | CREDITS_INSUFFICIENT | Balance is zero. |
| 422 | — | Limits, 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:
| Field | Meaning |
|---|---|
ticker, fiscal_year | Filing identity. |
download_url | The time-limited URL to download the Excel file. |
expires_in | Expiration time of the URL in seconds (e.g., 3600). |
credits_used | Always 300 when successful. |
Errors:
| HTTP | error_code | When |
|---|---|---|
| 404 | DATA_FILING_NOT_FOUND | Unknown filing_id. |
| 404 | DATA_EXCEL_NOT_AVAILABLE_FOR_FILING | No Excel attachment on file. |
| 404 | DATA_EXCEL_OBJECT_NOT_IN_STORAGE | The Excel file is not available. |
| 503 | DATA_EXCEL_PUBLIC_URL_UNAVAILABLE | A download URL cannot be provided for this request. |
| 402 | CREDITS_INSUFFICIENT | Insufficient 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
| Value | Meaning |
|---|---|
ok | Metric was computed; value is set. |
not_applicable | Metric does not apply to this filing. Carries a reason string; value is null. |
missing_input | A required XBRL fact is missing. Carries a missing_symbols list; value is null. |
needs_price_data | Price-sensitive metric called without current_price. value is null; pass current_price to upgrade to ok. |
needs_user_formula | The 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_history | A prior-period value is required (e.g. growth rates) but is not available from this filing's payload. value is null. |
divide_by_zero | Denominator was zero. value is null. |
eval_error | Formula 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
| Value | Meaning |
|---|---|
derived | Computed from multiple XBRL facts via the standard formula. |
as_reported | Single XBRL fact taken at face value, no formula run. |
composite | Built from multiple non-standard concepts (e.g. REIT CapEx = REInvestment + Maintenance). |
segment_sum | No consolidated total in the filing; summed across segment members. |
class_sum | Summed across asset / liability class members. |
company_override | A company-specific override rule produced the value. |
proxy_substituted | A proxy fact was used in place of the primary one (most often on ADR / foreign-issuer price-sensitive metrics). |
TTM_rollforward | On 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_accepted | Result of accept_suggested_formula=true — the engine's own suggested_formula was applied. |
user_formula_custom | Result of a caller-supplied formula_override. |
user_must_compute | Companion to status="needs_user_formula". Engine cannot compute automatically. |
not_applicable | Companion 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:
| Field | Meaning |
|---|---|
unit | Display unit. Either a currency code (usd, eur, twd, …) for absolute monetary metrics, or ratio / percent / days / shares etc. for non-monetary metrics. |
currency | Source currency for absolute monetary metrics. Absent on ratio / percent / unitless metrics. |
fx_required | true 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:
| Subfield | Meaning |
|---|---|
close | The price actually used in the formula (in the filer's reporting currency). |
date | Date of close. |
source | Source identifier (e.g. local_csv). |
original_adr_price_usd | The USD ADR price supplied (or filing-date USD price). |
adr_ratio | ADR ratio (number of common shares per ADR). |
fx_rate_local_per_usd | Conversion factor used for the period. |
reporting_ccy | Filer'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:
| Field | Removed 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)
| Name | Unit | Formula |
|---|---|---|
gross_margin | ratio | (Revenue - CostOfRevenue) / Revenue |
operating_margin | ratio | OperatingIncome / Revenue |
net_margin | ratio | NetIncome / Revenue |
ebitda_margin | ratio | (OperatingIncome + DepreciationAndAmortization) / Revenue |
Returns (4)
| Name | Unit | Formula |
|---|---|---|
return_on_equity | ratio | NetIncome / ((Equity + EquityPrior) / 2) |
return_on_assets | ratio | NetIncome / ((Assets + AssetsPrior) / 2) |
return_on_invested_capital | ratio | NetIncome / (((Equity + LongTermDebt + ShortTermDebt) + (EquityPrior + LongTermDebtPrior + ShortTermDebtPrior)) / 2) |
return_on_tangible_equity | ratio | NetIncome / (((Equity - Goodwill - Intangibles) + (EquityPrior - GoodwillPrior - IntangiblesPrior)) / 2) |
Leverage (4)
| Name | Unit | Formula |
|---|---|---|
debt_to_equity | ratio | (LongTermDebt + ShortTermDebt) / Equity |
debt_to_assets | ratio | (LongTermDebt + ShortTermDebt) / Assets |
debt_to_ebitda | ratio | (LongTermDebt + ShortTermDebt) / (OperatingIncome + DepreciationAndAmortization) |
interest_coverage | ratio | OperatingIncome / InterestExpense |
Liquidity (3)
| Name | Unit | Formula |
|---|---|---|
current_ratio | ratio | CurrentAssets / CurrentLiabilities |
quick_ratio | ratio | (CurrentAssets - Inventory) / CurrentLiabilities |
cash_ratio | ratio | Cash / CurrentLiabilities |
Efficiency / activity (7)
| Name | Unit | Formula |
|---|---|---|
asset_turnover | ratio | Revenue / ((Assets + AssetsPrior) / 2) |
inventory_turnover | ratio | CostOfRevenue / Inventory |
receivables_turnover | ratio | Revenue / AccountsReceivable |
days_inventory | days | PeriodDays * Inventory / CostOfRevenue |
days_receivable | days | PeriodDays * AccountsReceivable / Revenue |
days_payable | days | PeriodDays * AccountsPayable / CostOfRevenue |
cash_conversion_cycle | days | days_inventory + days_receivable − days_payable |
Cash flow & shareholder returns (3)
| Name | Unit | Formula |
|---|---|---|
free_cash_flow | reporting currency | CFO - Capex |
fcf_margin | ratio | (CFO - Capex) / Revenue |
payout_ratio | ratio | Dividends / 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_pricefrom any realtime quote source (e.g. Finnhub, Alpha Vantage, yfinance).
| Name | Unit | Formula |
|---|---|---|
market_cap ★ | reporting currency | SharesOutstanding * Price |
enterprise_value ★ | reporting currency | MarketCap + LongTermDebt + ShortTermDebt - Cash |
pe_ratio ★ | ratio | Price / EPS |
price_to_book ★ | ratio | MarketCap / Equity |
price_to_sales ★ | ratio | MarketCap / Revenue |
price_to_cash_flow ★ | ratio | MarketCap / CFO |
ev_to_ebitda ★ | ratio | EnterpriseValue / (OperatingIncome + DepreciationAndAmortization) |
ev_to_revenue ★ | ratio | EnterpriseValue / Revenue |
ev_to_fcf ★ | ratio | EnterpriseValue / (CFO - Capex) |
fcf_yield ★ | ratio | (CFO - Capex) / MarketCap |
dividend_yield ★ | ratio | DividendsPerShare / Price |
buyback_yield ★ | ratio | StockRepurchases / 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.
| Name | Unit | Formula |
|---|---|---|
revenue_growth_yoy | ratio | (Revenue_t - Revenue_{t-4Q}) / Revenue_{t-4Q} |
revenue_growth_qoq | ratio | (Revenue_t - Revenue_{t-1Q}) / Revenue_{t-1Q} |
revenue_growth_qoq_single_quarter | ratio | (Revenue_Qn_single - Revenue_Q(n-1)_single) / Revenue_Q(n-1)_single |
eps_growth_yoy | ratio | (EPS_t - EPS_{t-4Q}) / EPS_{t-4Q} |
net_income_growth_yoy | ratio | (NI_t - NI_{t-4Q}) / NI_{t-4Q} |
fcf_growth_yoy | ratio | (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_currencyis e.g.brl,eur) reportfree_cash_flowandmarket_cap/enterprise_valuein their local currency; the per-metricunitfield 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:
| Field | Type | Required | Notes |
|---|---|---|---|
ticker | string | Yes | 1–32 characters. |
fiscal_year | integer | Conditional | 1990–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_types | array of string | No | Max 8 entries; each max 32 characters. |
quarter | string | No | Max 4 characters. |
as_of_date | string | No | If non-empty and invalid, it is echoed as "error" in the response and ignored for filtering; a warning may be returned. |
Response:
| Field | Meaning |
|---|---|
credits_used | Always 10 when successful. |
fiscal_year | Echo of request. |
as_of_date | Echo of request (or "error" if invalid). |
company | Company profile (ticker, cik, legal_name) or null. |
metric_groups | Array of objects; each includes metric_group_id, filing identity fields, dates, reporting currency, and optional amendment flags. |
form_types, quarter | Present only if you sent them in the request. |
_warnings | Optional; present when dates exclude all rows or are invalid. |
Errors:
| HTTP | error_code | When |
|---|---|---|
| 400 | METRICS_UNSUPPORTED_FOR_KR | Korean (DART) metrics not yet supported — coming soon (not charged). |
| 400 | METRICS_UNSUPPORTED_FOR_JP | Japanese (EDINET) metrics not yet supported — coming soon (not charged). |
| 400 | METRICS_UNSUPPORTED_FOR_EU | European (ESEF) metrics not yet supported — coming soon (not charged). |
| 402 | CREDITS_INSUFFICIENT | Insufficient credits. |
| 422 | — | Validation (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:
| Field | Type | Default | Notes |
|---|---|---|---|
metric_group_id | integer | — | Required. 1–10⁹. From POST /metric/filings. |
as_of_date | string | null | YYYY-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_formula | boolean | false | When true, applies suggested formula hints included with the filing’s metrics (if any). |
formula_override | object | null | Per-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_price | number | null | USD 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_rate | number | null | Optional fallback FX rate (units of the filing's reporting_currency per 1 USD), used only when the internal FX feed 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_mode | boolean | false | When true, strips per-metric audit fields from every entry. A notice is appended to _warnings. Charged identically. See Light-weight mode. |
Response:
| Field | Meaning |
|---|---|
credits_used | Always 148 when successful. |
metric_group_id | The metric group ID actually used (may be null if excluded by as_of_date). |
valuation_context | Echo of flags and formula inputs. |
ticker, form_type, fiscal_year, quarter, cik, source_accession, primary_document, source_url_prefix | Filing 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. |
segments | Array of segment data. |
price_insensitive_metrics | Object 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_metrics | Object 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_context | Present 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 the internal FX feed 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 the internal feed was unavailable. mode is always present; on the two non-ok statuses a message states what to send. |
ttm_composite, dei_corrected | Optional root fields, present if they exist in the payload. |
amended | Present and true only when this filing had a later amendment merged in. The returned metric values are already the amended figures. |
corporate_actions | Optional root field, present when the ticker has splits in the lookback window. Contains splits_in_lookback, splits_after_period_end, split_factor_to_today, and a human-readable summary. When split_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 by splits. Tickers with no splits in the window omit the field entirely. |
reporting_currency | The 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. |
_warnings | Optional; warnings about amendments, formulas, or invalid dates. |
Errors:
| HTTP | error_code | When |
|---|---|---|
| 404 | METRIC_GROUP_NOT_FOUND | Unknown metric_group_id. |
| 404 | METRIC_SUMMARY_NOT_FOUND | Filing has no metrics summary. |
| 404 | METRIC_SUMMARY_OBJECT_MISSING | The metrics summary could not be retrieved. |
| 500 | METRIC_SUMMARY_INVALID_FORMAT | The metrics summary data is invalid. |
| 402 | CREDITS_INSUFFICIENT | Insufficient credits. |
| 409 | METRIC_FORMULA_OVERRIDE_INVALID | Invalid formula_override. |
| 422 | METRIC_FORMULA_APPLY_FAILED | Formula application failed. |
| 422 | VALIDATION_ERROR | current_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": {
"splits_after_period_end": [
{ "ex_date": "2024-06-10", "ratio": 10.0, "type": "forward" }
],
"splits_in_lookback": [
{ "ex_date": "2021-07-20", "ratio": 4.0, "type": "forward" },
{ "ex_date": "2024-06-10", "ratio": 10.0, "type": "forward" }
],
"split_factor_to_today": 10.0,
"summary": "10:1 forward split on 2024-06-10. Multiply per-share values from this filing by 10 to compare with current-basis quotes."
},
"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.
| Field | Type | Default | Notes |
|---|---|---|---|
metric_group_id | integer | — | Required. 1–10⁹. From POST /metric/filings. |
as_of_date | string | null | Same as POST /metric/all. |
accept_suggested_formula | boolean | false | Same as POST /metric/all. |
formula_override | object | null | Same as POST /metric/all. |
light_weight_mode | boolean | false | Same 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:
| Field | Type | Required | Notes |
|---|---|---|---|
metric_names | array of string | Yes | 1–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_mode | boolean | No | Same as POST /metric/all. See Light-weight mode. |
Credits: 148 per successful debit.
Response:
| Field | Meaning |
|---|---|
credits_used | Always 148 when successful. |
metric_group_id | The metric group ID actually used. |
valuation_context | Echo of flags, formula inputs, and requested metric_names. |
ticker, form_type, fiscal_year, quarter, cik, source_accession, primary_document, source_url_prefix | Filing 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_metrics | Object containing the requested price-insensitive metrics. Nested fact_refs / components entries with fact_id also expose source_locator (may be null). |
price_sensitive_metrics | Object 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_context | Present whenever the response would include a realtime block (same shape as in POST /metric/all). |
segments | Array of segment data. |
ttm_composite, dei_corrected | Optional root fields, present if they exist in the payload. |
corporate_actions | Optional 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. |
_warnings | Optional; warnings about amendments, formulas, or invalid dates. |
Errors: Same classes as POST /metric/all, plus:
| HTTP | error_code | When |
|---|---|---|
| 400 | METRIC_INVALID_METRIC_NAME | Unknown name or name not in this filing’s payload. |
| 402 | CREDITS_INSUFFICIENT | Insufficient 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:
| Field | Type | Default | Notes |
|---|---|---|---|
ticker | string | — | Required. 1–32 characters (returned uppercased). |
period_type | string | quarterly | Either 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). Korean (DART) and Japanese (EDINET) filings are included via the same form types (annual → 10-K, quarterly → 10-Q). |
start_period_start | string | null | Optional filter: period start ISO date (YYYY-MM-DD). Invalid values echo as "error" in query_context and are ignored for filtering. |
end_period_end | string | null | Optional filter: same date rules. |
metric_names | array | null | If 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_date | string | null | Same meaning as /metric/all. |
accept_suggested_formula | boolean | false | |
formula_override | object | null | Same structure rules as /metric/all (including ≤ 50 concepts per metric). |
sort | string | period_end_asc | period_end_asc or period_end_desc. |
page | integer | 1 | Page index, 1–10⁶. |
page_size | integer | 3 | 1–5 (maximum page size). |
light_weight_mode | boolean | false | Same 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:
| Field | Meaning |
|---|---|
page_info | Object with pagination details (current_page, total_pages, page_size, total_items, next_page_hint). |
credits_used | Number of credits deducted for this request. |
ticker | Echo of request. |
query_context | Echo of the request parameters used for the query. |
periods | Array 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. |
_warnings | Optional; warnings about amendments, formulas, or invalid dates. |
Errors:
| HTTP | error_code | When |
|---|---|---|
| 400 | METRIC_INVALID_METRIC_NAME | Invalid or missing names in a period when metric_names is set. |
| 400 | METRICS_UNSUPPORTED_FOR_KR | Korean (DART) metrics not yet supported — coming soon (not charged). |
| 400 | METRICS_UNSUPPORTED_FOR_JP | Japanese (EDINET) metrics not yet supported — coming soon (not charged). |
| 400 | METRICS_UNSUPPORTED_FOR_EU | European (ESEF) metrics not yet supported — coming soon (not charged). |
| 402 | CREDITS_INSUFFICIENT | Insufficient credits for base or per-row charges. |
| 409 | METRIC_FORMULA_OVERRIDE_INVALID | Invalid formula_override. |
| 422 | METRIC_FORMULA_APPLY_FAILED | Formula 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.
| Endpoint | Metrics returned |
|---|---|
POST /metric/profitability | gross_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/growth | revenue_growth_yoy, revenue_growth_qoq, revenue_growth_qoq_single_quarter, eps_growth_yoy, net_income_growth_yoy, fcf_growth_yoy (6) |
POST /metric/financial-health | debt_to_equity, debt_to_assets, debt_to_ebitda, interest_coverage, current_ratio, quick_ratio, cash_ratio (7) |
POST /metric/efficiency | asset_turnover, inventory_turnover, receivables_turnover, days_inventory, days_receivable, days_payable, cash_conversion_cycle (7) |
POST /metric/cash-flow | free_cash_flow, fcf_margin, payout_ratio (3 — fcf_margin also in /metric/profitability) |
POST /metric/valuation | All 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-date | Same 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.
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.
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, callPOST /metric/allper ticker with a commoncurrent_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"):
| Field | Type | Default | Notes |
|---|---|---|---|
as_of_date | ISO date | today (UTC) | Must be ≤ today. Filings with filing_date > as_of_date are excluded (avoids backtest leakage). |
lookback | int 1–120 | 1 | Most recent N filings per ticker within scope. |
include_quarterly | bool | false | false → annual only (10-K / 20-F / 40-F). true adds 10-Q. |
tickers | string[] | omitted | Whitelist, max 100. Case-insensitive (normalized to upper). Empty or omitted = full universe. |
exclude_tickers | string[] | [] | Blacklist, max 100. |
usd_only | bool | false | When true, exclude foreign-currency reporters. |
sectors | string[] | omitted | Restrict the universe to these canonical sector buckets (the 12 in §1.10). Omitted = no sector restriction. |
where.filter | DSL tree | (required) | See §6.3. Leaf count 1–10, nesting depth ≤ 4. |
where.sort_by | string | see §6.3 | Metric name, "ticker", "period_end", "filing_date", or "match_count". |
where.sort_order | "asc" | "desc" | "asc" | |
include_metrics_using_filing_date_price | bool | true | false rejects price-sensitive metrics in filter / sort_by / include_metrics. |
exclude_derivations | string[] | [] | Subset of derived, as_reported, composite, class_sum, segment_sum, company_override, proxy_substituted, TTM_rollforward. |
include_metrics | string[] | [] | Extra metric names (≤ 10) to include in the response beyond filter-referenced ones. |
group_by_ticker | bool | true | true → grouped by ticker with nested filings[]. false → flat per-filing rows. |
page | int ≥ 1 | 1 | 1-indexed. |
page_size | int 1–100 | 50 | Counts 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 15-second server timeout (the request is charged; tighten filters and retry).
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).
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>}
| Operator | Value shape | Notes |
|---|---|---|
>, >=, <, <= | 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)
| Modifier | Meaning |
|---|---|
| (none) | Latest filing in lookback must satisfy. Equivalent to for_latest: 1. |
for_latest: N | Most recent N filings (right-anchored) all satisfy. |
for_consecutive: N | Some N adjacent filings within lookback all satisfy (sliding window over filing_date). |
for_at_least: N | At 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_metricslength: ≤ 10tickers,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:
| Scenario | Credits |
|---|---|
| 1 ticker, lookback=1, annual only, 1 leaf (best case) | 89 |
| Whole universe, lookback=30, quarterly+annual, 1 leaf | 425 |
2 tickers, lookback=5, annual, 2 leaves, 1 for_latest, 2 extra include_metrics | 242 |
Whole universe, lookback=120, 10 leaves all for_consecutive, 10 extra include_metrics | 1825 (worst case) |
Charge applies even when results is empty, and on 504 QUERY_TIMEOUT (the query runs before it times out — that compute is the billable unit). 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:
| Field | Type | Default | Notes |
|---|---|---|---|
start_date, as_of_date | ISO date | — | as_of_date ≤ today; start_date ≤ as_of_date. |
tickers, exclude_tickers | string[] | omitted | ≤ 100 each. |
sectors | string[] | omitted | The 12 canonical buckets (§1.10). |
trade_filters | object | omitted | See §6.6. |
aggregate_filters | object[] | omitted | ≤ 8. Company-level gates — see §6.6. |
group_by_ticker | bool | true | true → grouped by ticker. false → flat rows. |
sort_by | string | — | Grouped: 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" | |
page | int ≥ 1 | 1 | |
page_size | int 1–100 | 50 |
Pagination cap: page × page_size ≤ 500 (422).
Response:
| Field | Meaning |
|---|---|
page, page_size, has_more, next_page | Pagination. |
as_of_date_applied, start_date_applied | Window actually used. |
results | group_by_ticker=true. Each entry: ticker, issuer, issuer_cik, txn_count (the company's full hit count, not the page's), transactions. |
transactions | group_by_ticker=false. Flat rows, each additionally carrying ticker, issuer, and issuer_cik. |
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 15-second server timeout (charged).
6.6 Filters (/screener/ownership)
trade_filters:
| Field | Type | Notes |
|---|---|---|
transaction_code | string[] | ≤ 20. Unknown codes dropped with a warning. |
relationship | string[] | is_director, is_officer, is_ten_percent_owner, is_other. OR semantics. |
is_derivative | bool | |
principal_amount_not_shares | bool | Omit for no filter, true for debt-principal rows only, false to exclude them. |
include_anomalies | bool | Default false. |
exclude_likely_merged | bool | Default false. |
conditions | object[] | ≤ 8. {field, op, value}. field ∈ transaction_value, price_per_share, shares, own_pct_change, split_adjusted_shares, split_adjusted_price. |
aggregate_filters: {metric, op, value}, metric ∈ value_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).
7. Ownership API
Insider trades reported to the SEC. US filings only. The plan coverage scope (§1.9) and history window (§1.8) apply as they do elsewhere, on the filing's filing_date. The endpoints in this section are available on every plan; full-library screening is POST /screener/ownership in Section 6, which requires 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.
| Field | Meaning |
|---|---|
id | Transaction id. Pass to POST /ownership/transaction-ids. |
is_derivative | Derivative table row (true) or non-derivative (false). |
transaction_form_type | "4" or "5". |
transaction_date, transaction_code | As filed. |
transaction_type | Official SEC name for transaction_code. |
transaction_type_group | One 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_following | As filed. transaction_value may be null or 0. |
transaction_note | Filer-side note explaining a null / 0 value. null when absent. |
principal_amount_not_shares | true when shares holds a debt principal amount, not a share count. |
security_title, direct_or_indirect, nature_of_ownership | As filed. |
footnote_refs | Footnote ids for this transaction. Resolve against the filing's footnotes map. |
source_locator | Combine with the filing's source_url_prefix to build the SEC URL. |
restated | null, "cancelled", "modified", or "added" — set when an amendment changed this transaction. |
prior | Present only when restated is set. The pre-amendment values. |
split_adjusted | Present only when the filed values are not on the current per-share basis. See below. |
data_quality_flags | Present 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.
Flagged rows are excluded from POST /ownership/stats unless include_anomalies=true, and from POST /screener/ownership unless trade_filters.include_anomalies=true.
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:
| Field | Type | Default | Notes |
|---|---|---|---|
ticker | string | — | Uppercased automatically. |
insider_cik | string | — | Digits only, ≤ 10; left-padded to 10. |
transaction_code | string[] | omitted | ≤ 20 entries. Unknown codes are dropped with a _warnings entry. |
transaction_form_type | "4" | "5" | omitted | |
include_unresolved_amendments | bool | false | |
exclude_likely_merged | bool | false | |
page | int ≥ 1 | 1 | |
page_size | int 1–100 | 50 | Counts filings. |
At least one of ticker / insider_cik is required (422 otherwise).
Response:
| Field | Meaning |
|---|---|
page, page_size, has_more, next_page | Pagination. |
filings | Array. 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_cik | The 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[].insiders | cik, name, is_director, is_officer, is_ten_percent_owner, is_other, officer_title, other_text. |
filings[].footnotes | Map of footnote id → text for this filing. |
_warnings | Optional. |
credits_used | Always 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.
7.2 POST /ownership/stats
Purpose: Aggregate statistics over one company and/or one insider, plus the ids of every transaction that contributed.
Request:
| Field | Type | Default | Notes |
|---|---|---|---|
ticker | string | — | |
insider_cik | string | — | |
start_date, as_of_date | ISO date | — | as_of_date ≤ today; start_date ≤ as_of_date. |
transaction_code | string[] | 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_anomalies | bool | false | |
relationship | string[] | omitted | Any of is_director, is_officer, is_ten_percent_owner, is_other. OR semantics, evaluated per filing. |
is_derivative | bool | omitted | |
exclude_likely_merged | bool | false | |
ids_page | int ≥ 1 | 1 | Paginates transaction_ids only. |
ids_page_size | int 1–1000 | 200 |
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 field | Meaning |
|---|---|
value_acquired, value_disposed, net_value | Cash value totals. Transactions with no cash value contribute 0. |
shares_acquired, shares_disposed, net_shares | Share totals on the split-adjusted basis, excluding rows where principal_amount_not_shares is true. |
avg_price_acquired, avg_price_disposed | Total 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_disposed | Counts. |
txn_count_with_value | Transactions carrying a non-zero cash value. |
no_value_txn_count | Transactions with no cash value. |
ad_code_missing_count | Transactions counted in neither direction. |
principal_amount_txn_count | Debt-principal rows excluded from shares_* and avg_price_*. |
distinct_insiders | Distinct reporting owners in scope. |
filings_with_multiple_filers | Joint filings in scope. |
max_txn_value_acquired, max_txn_value_disposed | Largest single transaction per side. null when the side is empty. |
avg_value_per_txn_acquired, avg_value_per_txn_disposed | Mean over transactions that have a cash value. |
earliest_transaction_date, latest_transaction_date | Range actually covered. |
split_crossing | true when the window spans a stock split. |
corporate_actions is present only when the request is anchored on a ticker that has splits: an array of {ex_date, ratio, 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.
7.3 POST /ownership/transaction-ids
Purpose: Fetch transactions by id — the detail companion to the transaction_ids returned by §7.2.
Request:
| Field | Type | Default | Notes |
|---|---|---|---|
transaction_ids | int[] | — | Required. 1–100 positive integers. Duplicates are removed with a _warnings entry. |
page | int ≥ 1 | 1 | |
page_size | int 1–100 | 100 | Counts 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.
7.4 GET /ownership/tickers
Purpose: Discovery — every ticker with insider-trade coverage. Unpaginated; cache the result.
Response: tickers (array of {ticker, jurisdiction, cik}), credits_used, and optional _warnings.
Credits: 175.
Errors: 402 CREDITS_INSUFFICIENT.
7.5 POST /ownership/names
Purpose: All insiders of one company, aggregated per CIK.
Request:
| Field | Type | Notes |
|---|---|---|
ticker | string | Required. |
relationship | string[] | 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:
| Field | Meaning |
|---|---|
owner_cik, owner_name | Spelling from this insider's most recent filing. |
name_changed | true when earlier filings spelled the name differently. |
caveat | Present only when name_changed is true. |
ever_director, ever_officer, ever_ten_percent_owner, ever_other | true when any filing reported that role. |
latest_officer_title | Most recent non-null officer title. null when never reported. |
officer_title_as_of | Filing date latest_officer_title came from. |
filing_count | Filings of this company naming this insider. |
earliest_filing_date, latest_filing_date | Range. |
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).
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.
8. API key, account, and plan errors
| HTTP | When |
|---|---|
| 401 | Missing X-API-Key. |
| 403 | Invalid or inactive key, inactive user, or email not verified. |
| 403 | AUTH_API_KEY_EXPIRED — key past its expiry. |
| 403 | AUTH_API_KEY_INACTIVE — key disabled by inactivity policy. |
| 403 | PLAN_TIER_INSUFFICIENT — the endpoint is not available on the caller's current plan. |
| 403 | PLAN_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. |
| 403 | PLAN_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. |
| 403 | PLAN_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):
| Limit | Value |
|---|---|
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 request | 25 |
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 size | 5 |
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.
10.1 Connect via OAuth (recommended for AI assistants)
For AI clients with built-in MCP support (Claude Desktop, Claude Web, etc.):
- In your AI client, add
https://api.akkrudata.ai/mcpas a custom MCP connector. - Click Connect. Your browser will open an AkkruData sign-in page.
- Sign in with the same credentials you use for the dashboard (email/password, Google, or GitHub).
- Review the connecting AI client's reported identity, then click Authorize.
- 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
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.