Metadata-Version: 2.5
Name: filingstudio
Version: 0.4.0
Summary: Client for the Filing Studio API: search SEC filings, resolve traces, verify claims. One call per door, typed results, your key never in a URL.
Project-URL: Homepage, https://filingstudio.com
Project-URL: Documentation, https://filingstudio.com/docs#sdk
Author-email: Filing Studio <support@filingstudio.com>
License: MIT
License-File: LICENSE
Keywords: 10-K,10-Q,api-client,citations,edgar,filings,finance,provenance,sec
Classifier: Development Status :: 4 - Beta
Classifier: Intended Audience :: Developers
Classifier: Intended Audience :: Financial and Insurance Industry
Classifier: License :: OSI Approved :: MIT License
Classifier: Operating System :: OS Independent
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3 :: Only
Classifier: Programming Language :: Python :: 3.9
Classifier: Programming Language :: Python :: 3.10
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Programming Language :: Python :: 3.13
Classifier: Topic :: Office/Business :: Financial
Classifier: Topic :: Software Development :: Libraries
Classifier: Typing :: Typed
Requires-Python: >=3.9
Requires-Dist: httpx>=0.24
Requires-Dist: pydantic>=2.0
Provides-Extra: test
Requires-Dist: anyio>=3; extra == 'test'
Requires-Dist: pytest>=7; extra == 'test'
Description-Content-Type: text/markdown

# filingstudio

Python client for the [Filing Studio](https://filingstudio.com) API. Search
SEC filings exactly as printed, resolve any number back to the line that
printed it, and verify claims deterministically. One call per door, typed
results, and your key never in a URL.

```bash
pip install filingstudio
```

```python
import os
from filingstudio import FilingStudio

fs = FilingStudio(api_key=os.environ["FILING_STUDIO_API_KEY"])

hits = fs.search("NVDA", "purchase commitments", type="prose")
for p in hits.passages:
    print(p.text, p.trace_id)

v = fs.verify("NVDA", metric="Revenue", value=130497, period="FY2025")
print(v.verdict)                       # supported | unsupported | ambiguous | unavailable
print(v.receipts[0].printed_text)      # "130,497"
print(v.receipts[0].links.highlight)   # opens the filing with that cell marked

t = fs.trace(v.receipts[0].trace_id)   # the printed line plus its neighbours
for row in t.context:
    print(row.label, row.printed_text, "<- source" if row.is_source else "")
```

Async is the same API:

```python
from filingstudio import AsyncFilingStudio

async with AsyncFilingStudio(api_key=key) as fs:
    cov = await fs.coverage("NVDA")
```

## The six doors

| method | what it answers |
|---|---|
| `search(ticker, q, type=, period=, forms=, limit=, offset=)` | printed rows, tables, and prose matching plain words |
| `verify(ticker, metric=, value=, period=, claim=)` | is this claim what the filing prints? |
| `trace(trace_id, include_context=True)` | the exact printed line behind a traceId, with neighbours |
| `filings(ticker, form=, year=, limit=)` | a company's indexed filings |
| `coverage(ticker)` | is anything indexed, and how fresh |
| `table(ticker, accession, table_id, format="records")` | one printed table, as filed |

Pass `value` to `verify` as the raw figure you hold (130497 or 130497000000
alike). The API tries every printed scale a filer could use. Do not pre-scale.

## Honest answers

Every result carries `index_state`. `coverage` is one of:

- `indexed`: a populated index answered, with results
- `empty`: a populated index answered and had nothing. The only real negative.
- `incomplete`: the index could not fully answer. Says nothing about the filing.
- `unavailable`: the service or your quota could not answer. Same.

`RateLimitError` (HTTP 429) carries `index_state.note`, a sentence safe to
show a user. Other non-2xx answers raise `FilingStudioError` with `status`,
`code`, and the API's `message`. 5xx and network failures are retried with
backoff; 4xx are not. No error ever contains your key.

## Research with receipts (experimental)

```python
from filingstudio.research import answer

def llm(system: str, user: str, json_mode: bool) -> str:
    ...  # any chat model; return the assistant text

res = answer("How is Data Center revenue trending?", "NVDA", llm=llm, client=fs,
             on_step=lambda label, detail: print(label, detail))
res.answer, res.sources, res.hard_stop
```

Plan, search, assess, write, with hard stops. Every `[n]` in the answer is a
search hit you can trace; citations to nothing are stripped; with no evidence
the answer says so. `llm=None` runs one search and returns the evidence only.

## Options

`FilingStudio(api_key, base_url=None, timeout=30.0, max_retries=2, transport=None)`

`transport` accepts an `httpx` transport, for tests (`httpx.MockTransport`).

## Develop

```bash
pip install -e .[test]
pytest
```

MIT
