---
title: "Earnings quality score (Piotroski, Sloan, Beneish)"
method: GET
path: "/api/v1/equities/{symbol}/earnings-quality"
tags: ["Equities Indices"]
---

# Earnings quality score (Piotroski, Sloan, Beneish)

`GET /api/v1/equities/{symbol}/earnings-quality`

First-party earnings-quality analytics computed from SEC EDGAR XBRL companyfacts (annual filings 10-K/20-F/40-F). Three published academic models with the full methodology disclosed in the payload: Piotroski (2000) F-score with ROA and turnover scaled by beginning-of-year assets; Sloan (1996) accruals in the cash-flow-statement form (Hribar-Collins 2002); Beneish (1999) M-score M8 and M5 with simplified AQI and neutral-1.0 handling of uncomputable indices. Composite 0-100 = 0.40 Piotroski + 0.30 Sloan + 0.30 Beneish, weights renormalized over available components (2 of 3 required), letter bands A >= 80 / B / C / D / F < 35. The Beneish verdict additionally travels as a SEPARATE manipulation_flag (GREEN / GRAY / RED / UNKNOWN / NOT_APPLICABLE) so it is never diluted by a good F-score. ANNUAL only by construction. Financial issuers (SIC 6000-6999): Sloan and Beneish suppressed, Piotroski degrades to 5 defensible signals, no composite letter. MODEL ESTIMATE derived from public filings - DESCRIPTIVE analytics, not investment advice.

## Path parameters

- `symbol` string, required — Ticker symbol.

## Query parameters

- `years` integer — Fiscal years to score, newest first. Rows need a prior-year baseline, so years_available may be lower than requested.

## Response `200`

Per fiscal year: Piotroski F-score (9 disclosed signals), Sloan accruals ratio, Beneish M-score (8 disclosed indices), an open 0.40/0.30/0.30 composite with letter grade, and a separate manipulation flag.

- EnvelopeEarningsQualityData
  - `data` EarningsQualityData, required — DATA-5.2: earnings quality score payload.
    - `symbol` string, required
    - `cik` string, nullable
    - `entity_name` string, nullable
    - `sic` integer, nullable — SEC SIC code (from EDGAR submissions; null when unavailable).
    - `is_financial` boolean, required — SIC 6000-6999: Sloan and Beneish suppressed, Piotroski partial.
    - `years_requested` integer, required
    - `years_available` integer, required — May be fewer than requested - each row needs a prior-year baseline.
    - `periods` EqPeriod[], required
      - `fiscal_year_end` string, required
      - `prior_year_end` string, nullable — The baseline year the deltas compare against.
      - `row_status` string, required — ok (rows without a usable prior year are not emitted).
      - `composite` EqComposite, required — Sugra composite score - weights are published, not proprietary.
        - `score` number, nullable — 0-100; weights renormalized over available components; 2 of 3 required.
        - `letter` string, nullable — A >= 80, B >= 65, C >= 50, D >= 35, F < 35.
        - `weights` object, nullable — Effective weights used for this row.
        - `components_used` string[]
        - `reason` string, nullable — financial_issuer | insufficient_components when score is null.
      - `manipulation_flag` string, required — The Beneish verdict, SEPARATE from the composite so it is never diluted.
      - `piotroski` EqPiotroski, required — Piotroski (2000) F-score block.
        - `status` string, required — ok | partial | suppressed.
        - `reason` string, nullable — financial_issuer | missing_inputs when not ok.
        - `f_score` integer, nullable — 0-9; null for financial issuers (partial signal set).
        - `partial_score` integer, nullable — 0-5 over the 5 defensible signals (financial issuers only).
        - `signals` object, required — All computed signals with values and scores.
        - `missing_signals` integer, required — Signals whose inputs were unavailable.
        - `subscore` number, nullable — F/9*100; null when 3+ signals are missing.
      - `sloan` EqSloan, required — Sloan (1996) accruals block (cash-flow form per Hribar-Collins 2002).
        - `status` string, required — ok | unavailable | suppressed.
        - `reason` string, nullable
        - `accruals_ratio` number, nullable — (NI - CFO) / average total assets; positive = lower quality.
        - `zone` string, nullable — red_flag | elevated | normal | strong_cash_backing | writedown_caution.
        - `subscore` number, nullable — 0-100; capped at 80 when accruals < -0.20 (write-down noise).
      - `beneish` EqBeneish, required — Beneish (1999) M-score block.
        - `status` string, required — ok | suppressed.
        - `reason` string, nullable — financial_issuer | insufficient_inputs when suppressed.
        - `m8` number, nullable — 8-variable M-score; above -1.78 = RED, -2.22..-1.78 = GRAY, below -2.22 = GREEN.
        - `m5` number, nullable — 5-variable variant.
        - `indices` object — dsri/gmi/aqi/sgi/depi/sgai/lvgi (winsorized to [0.1, 10]) and tata.
        - `neutralized` string[] — Indices set to the neutral value because inputs were missing.
        - `flag` string, nullable — GREEN | GRAY | RED | UNKNOWN | NOT_APPLICABLE.
      - `inputs` object — Raw input values used for this row (auditable).
    - `concepts_used` object — Which XBRL concept and taxonomy won per input (reproducibility).
    - `methodology` object — Formulas, composite weights, letter bands, citations, disclaimer.
  - `meta` SugraMeta, required — Metadata attached to every /api/v1/* response envelope.
    - `endpoint` string, required — Requested endpoint path.
    - `data_time` string, required — ISO 8601 UTC timestamp of the source data, not of the request.
    - `response_time` string, required — ISO 8601 UTC timestamp when this response was produced.
    - `provider` string, required — API name and version.
    - `source` string, nullable — Identifier of the primary upstream source used for this response.
    - `attribution` string, nullable — Human-readable attribution mandated by an upstream source (e.g. a securities regulator or self-regulatory organization). Present only on responses whose source requires the owner and source to be clearly identified. Do not remove or alter it when using the response.
    - `fallback_used` boolean, nullable — True when the primary source failed and a fallback produced the data.
    - `fallback_chain` string[], nullable — Ordered list of sources attempted, in the order they were tried.
    - `cached` boolean, nullable — True when this response was served from the internal cache.
    - `stale` boolean, nullable — True when the cached response was returned after the upstream rate-limited or errored. Clients can use this to detect degraded data.

## Other responses

- `400` — Invalid ticker symbol.
- `401` — Missing or invalid `x-api-key` header. JSON body with a stable `code` distinguishing `missing_api_key` (no header sent) from `invalid_api_key` (header sent, key not accepted); any other 401 source carries the generic `unauthorized` with its detail as `reason`. Plus `hint`. `plan` is always null on 401 - an unauthenticated request has no plan; quota exhaustion is 429, not 401.
- `404` — Unknown company, no XBRL data, or fewer than two consecutive fiscal years.
- `422` — Parameter bounds or data condition.
- `429` — Daily rate limit exceeded. Check `X-RateLimit-Reset` for the next window.
- `502` — SEC upstream temporarily unavailable.
- `503` — Upstream source is temporarily unavailable. Retry after a short delay.

---

[API](https://skmtc.net/sugra/apis/sugra-api.md) · [All operations](https://skmtc.net/sugra/apis/sugra-api/llms.txt) · [OpenAPI document](https://skmtc-service-staging.skmtc.workers.dev/v1/apis/sugra/sugra-api/revisions/062b7040e9bc/schema)
