> ## Documentation Index
> Fetch the complete documentation index at: https://docs.halal.sh/llms.txt
> Use this file to discover all available pages before exploring further.

# Handle Pending Analysis

> How to handle stocks that haven't been analysed yet.

## Overview

halal.sh covers a large but finite universe of instruments, and coverage grows over time. When you request `/compliance` for an instrument that hasn't been analysed yet, the API doesn't fail and it doesn't queue work on demand — it returns a well-formed payload with `determination.status: "pending"` and the analysis fields left `null`.

This guide shows how to detect that state and handle it gracefully.

<Note>
  All **12 sandbox instruments are already analysed**, so you won't see a
  `pending` status while testing against the sandbox key. The handling below
  matters once you're live against the full universe.
</Note>

## What a pending response looks like

A pending instrument returns `status: "pending"` with every analysis field `null` — `screens`, `revenue`, `purification`, `stability`, and `filing`:

```json theme={null}
{
  "data": {
    "symbol": "EXMPL",
    "determination": { "status": "pending" },
    "screens": null,
    "revenue": null,
    "purification": null,
    "stability": null,
    "filing": null
  }
}
```

<Warning>
  There is **no auto-queue and no `retry_after`** on a pending response.
  Re-requesting the same symbol in a loop won't trigger analysis or change the
  result — it just burns rate limit. (The only place `retry_after` appears is on
  `429` rate-limit errors, which is unrelated to pending coverage.)
</Warning>

## Detect pending

Branch on `determination.status` and treat `pending` as "compliance unknown" rather than an error.

<Tabs>
  <Tab title="Node.js">
    ```typescript theme={null}
    async function getCompliance(symbol: string) {
      const res = await fetch(
        `https://api.halal.sh/v1/instruments/${symbol}/compliance`,
        { headers: { "X-API-Key": process.env.HALALSH_API_KEY } }
      );
      const { data } = await res.json();

      if (data.determination.status === "pending") {
        // Not analysed yet — screens/revenue/etc. are all null.
        return { symbol, status: "pending" };
      }

      return { symbol, status: data.determination.status, screens: data.screens };
    }
    ```
  </Tab>

  <Tab title="Python">
    ```python theme={null}
    import os
    import requests

    def get_compliance(symbol: str) -> dict:
        res = requests.get(
            f"https://api.halal.sh/v1/instruments/{symbol}/compliance",
            headers={"X-API-Key": os.environ["HALALSH_API_KEY"]},
        )
        data = res.json()["data"]

        if data["determination"]["status"] == "pending":
            # Not analysed yet — screens/revenue/etc. are all None.
            return {"symbol": symbol, "status": "pending"}

        return {"symbol": symbol, "status": data["determination"]["status"], "screens": data["screens"]}
    ```
  </Tab>

  <Tab title="React">
    ```jsx theme={null}
    function StockCompliance({ symbol }) {
      const [data, setData] = useState(null);

      useEffect(() => {
        // Calls your backend proxy, which holds the API key.
        fetch(`/api/compliance/${symbol}`)
          .then((res) => res.json())
          .then(({ data }) => setData(data));
      }, [symbol]);

      if (!data) return null;

      const { status } = data.determination;

      if (status === "pending") {
        return <span className="text-gray-500">Compliance not yet available</span>;
      }

      return <span>Status: {status}</span>;
    }
    ```
  </Tab>
</Tabs>

## Pending in a portfolio screen

`POST /screen` can return `compliance_status: "pending"` for any symbol that isn't analysed yet. Partition the results and decide what each bucket means for your UI.

```typescript theme={null}
const { data } = await screen(symbols);

const compliant = data.filter((r) => r.compliance_status === "compliant");
const nonCompliant = data.filter((r) => r.compliance_status === "non-compliant");
const pending = data.filter((r) => r.compliance_status === "pending");

// `pending` symbols have no screens yet — surface them as "unknown",
// don't count them as either compliant or non-compliant.
```

## What to show users

| Status          | Suggested UX                                                |
| --------------- | ----------------------------------------------------------- |
| `compliant`     | Compliant badge; optionally show the three screens          |
| `non-compliant` | Non-compliant badge; show which screen failed               |
| `pending`       | Neutral "not yet analysed" state — never imply pass or fail |

## How coverage grows

Coverage expands as new instruments are analysed, so a symbol that's `pending` today may return a full result later. Design for it: cache results you've already fetched, re-check pending symbols on a sensible cadence (for example, the next time a user opens that stock), and always render a clear neutral state in the meantime. Never block a screen or treat `pending` as a hard error.
