---
title: "Screen Etf"
method: POST
path: "/api/etf/{symbol}/screen"
tags: ["etf"]
---

# Screen Etf

`POST /api/etf/{symbol}/screen`

## Request

- Base URL: `https://api.halalterminal.com`
- URL: `https://api.halalterminal.com/api/etf/{symbol}/screen`
- Auth: API key in header `X-API-Key`

Run a Shariah compliance screening on an ETF.

Screens every holding in the ETF against Shariah compliance criteria and
returns an overall compliance status, a weighted-average purification rate,
a compliance summary (counts and weights), and per-holding screening
results. Pass `force_refresh=true` to bypass cached results — available
only for enterprise and internal plans; for other plans the flag is
silently treated as False.

**curl example:**

    curl -X POST "http://localhost:8000/api/etf/VTI/screen?force_refresh=false"

**Python requests example:**

```python
import requests
resp = requests.post("http://localhost:8000/api/etf/VTI/screen", params={"force_refresh": False})
result = resp.json()
print(result["compliance_status"], "- compliant weight:", result["summary"]["compliant_weight"])
```

## Path parameters

- `symbol` string, required: ETF ticker symbol.

## Query parameters

- `force_refresh` boolean: Bypass cached results when true. Only enterprise and internal plans honor this; other plans treat it as false.

## Response `200`

Full Shariah screening result with per-holding compliance details.

- ETFScreeningResponse: Full Shariah screening result for an ETF. Per the v2 cert spec (docs/superpowers/specs/2026-05-08-shariah-methodology- headline-design.md §10–11), ETFs never carry a binary `is_compliant` verdict. Scholars publish verdicts; we publish data. The response carries: - `is_compliant: null` (always, by design) - `disposition`: scholar_certified | data_quality_flag | contested | unrated - `scholar_attestations`: list of board attestations (multi-board friendly) - `holdings_analysis` data via `summary` + `holdings` (unchanged) Clients should switch on `disposition` (or compute their own threshold from `summary.non_compliant_weight`) instead of `is_compliant`.
  - `symbol` string, required: ETF ticker symbol.
  - `name` string: ETF fund name.
  - `is_compliant` boolean, nullable: Always null for ETFs (v2 spec §10.3). Use `disposition` or compute from `summary.non_compliant_weight` instead.
  - `compliance_status` string: Holdings-based bucket label kept for backwards compatibility: 'compliant', 'non_compliant', 'insufficient_data', 'unscreened'. For the verdict-shaped client signal, read `disposition` instead.
  - `disposition` string, nullable: Non-verdict summary derived from scholar attestations + holdings analysis: 'scholar_certified', 'data_quality_flag', 'contested', 'unrated'. See spec §11.
  - `scholar_attestations` object[]: List of scholar-board attestations carrying methodology, position, verified_on, and source_url. Empty when no attestation is on file.
  - `non_compliant_threshold` number: Maximum non-compliant weight allowed, as a fraction: 0.05 means 5%. The weight fields are in percent, so the test the engine runs is summary.non_compliant_weight / 100 against this threshold.
  - `purification_rate` number, nullable: Weighted-average purification rate in percent, computed over the compliant, rated holdings ONLY: non-compliant and unscreened weight is excluded from both the numerator and the denominator. Use `purification_weight_covered` to see what share of the fund that average speaks for. For a figure covering the whole fund, which charges every non-compliant or unscreened holding at 100% by prudence, call POST /api/etf/{symbol}/purification and read `etf_purification_rate`. On a fund holding non-compliant names the two differ by several multiples, and the whole-fund figure is the one to show an investor.
  - `purification_basis` string: Denominator behind `purification_rate`. Always 'compliant_rated_holdings' on this endpoint, against 'whole_fund_conservative' on the purification endpoint.
  - `purification_weight_covered` number, nullable: Share of the fund, in percent, that `purification_rate` averages over. The gap to 100 is the non-compliant, unscreened and unrated weight that this average ignores.
  - `summary` ETFComplianceSummary: Aggregate compliance statistics for an ETF screening run.
    - `total_holdings` integer: Total number of holdings analysed.
    - `screened_count` integer: Number of holdings that were actually screened.
    - `compliant_count` integer: Number of holdings deemed Shariah-compliant.
    - `non_compliant_count` integer: Number of holdings deemed non-compliant.
    - `unscreened_count` integer: Number of holdings with no screening data.
    - `compliant_weight` number: Summed weight of the compliant holdings, in percent: 96.56 means 96.56% of the fund.
    - `non_compliant_weight` number: Summed weight of the non-compliant holdings, in percent: 2.68 means 2.68% of the fund.
    - `unscreened_weight` number: Summed weight of the holdings carrying no screening data, in percent.
  - `holdings` ETFHoldingScreeningResult[]: Per-holding screening results.
    - `symbol` string, nullable: Ticker symbol of the holding, or null for a weighted line with no listing of its own.
    - `name` string: Company or security name.
    - `weight` number: Portfolio weight in percent: 6.5 means 6.5% of the fund.
    - `compliance_status` string: Shariah compliance status: 'compliant', 'non_compliant', or 'unscreened'.
    - `purification_rate` number, nullable: Purification rate for this holding, in percent: 0.88 means 0.88% of income. Null when the holding carries no rate of its own, which is the case on an unscreened line and on a holding that is compliant by nature.
  - `fund_info` ETFFundInfoResponse: General fund-level metadata for an ETF.
    - `symbol` string, required: ETF ticker symbol.
    - `name` string: ETF fund name.
    - `description` string, nullable: Brief fund description.
    - `inception_date` string, nullable: Fund inception date (YYYY-MM-DD).
    - `expense_ratio` number, nullable: Annual expense ratio as a decimal (0.0003 = 0.03%).
    - `nav` number, nullable: Net asset value per share in USD.
    - `total_assets` number, nullable: Total assets under management in USD.
    - `category` string, nullable: Morningstar or provider category.
    - `family` string, nullable: Fund family name (e.g. 'Vanguard').
    - `exchange` string, nullable: Exchange where the ETF is listed (e.g. 'NYSE Arca').
    - `sector_weightings` object, nullable: Mapping of sector names to portfolio weight percentages.
    - `asset_classes` object, nullable: Mapping of asset class labels (equity, bond, etc.) to weight percentages.
    - `country_weightings` object, nullable: Mapping of country codes/names to portfolio weight percentages.
    - `turnover` number, nullable: Annual portfolio turnover rate as a decimal.
  - `data_source` string: Data provider used for screening.
  - `disclaimers` Disclaimer[], nullable: Attached by middleware; see /api/disclaimers.
    - `id` string, required: Stable category identifier — safe for clients to dedupe and cache on.
    - `version` string, required: ISO-8601 date of the most recent edit to `text`. Advances whenever the wording changes, even for typo fixes.
    - `lang` string: BCP-47 language tag for `text`. Today always 'en'; reserved for future i18n.
    - `severity` string, required: Grouping hint for UIs. 'religious' for fatwa/scholar caveats; 'data' for data-freshness, sourcing, or coverage caveats.
    - `text` string, required: Short inline disclaimer text.
    - `url` string, required: Canonical legal page URL (deep-linked to the relevant section).

## Other responses

- `404`: ETF symbol not found or has no holdings data.
- `422`: Validation Error
- `429`: Rate limit exceeded. Try again later.

---

[API](https://skmtc.dev/halalterminal/apis/halal-terminal-api.md) · [All operations](https://skmtc.dev/halalterminal/apis/halal-terminal-api/llms.txt) · [OpenAPI document](https://skmtc.dev/halalterminal/apis/halal-terminal-api/revisions/78768b250943?raw)
