Skip to main content

Official Python SDK for the Clous SEC/EDGAR API — entity-resolved filings, insider & institutional ownership, financials, events, and monitors.

Project description

Clous Python SDK

PyPI Python License: MIT

The official Python client for the Clous SEC/EDGAR API — entity-resolved filings, insider & institutional ownership, structured XBRL financials, a typed business-events feed, grounded Q&A, and standing monitors with webhooks.

pip install clous

Requires Python 3.9+. The only runtime dependency is httpx.

Quickstart

from clous import Clous

client = Clous()  # reads CLOUS_API_KEY from the environment

# Search the EDGAR filing index
page = client.filings.search(form_type="8-K", limit=10)
for filing in page:
    print(filing["accession"], filing.get("company_name"))

# Structured XBRL financials for one company
revenue = client.financials.get("0000320193", concept="Revenues")

# Grounded Q&A over filings
answer = client.answer("What was Apple's most recent annual revenue?", ticker="AAPL")
print(answer["answer"])

Authentication

Pass your key explicitly or set the CLOUS_API_KEY environment variable:

client = Clous(api_key="sk_live_...")
# or
import os; os.environ["CLOUS_API_KEY"] = "sk_live_..."; client = Clous()

The key is sent as Authorization: Bearer <CLOUS_API_KEY>. The base URL defaults to https://api.clous.ai and can be overridden with base_url= or the CLOUS_BASE_URL env var. /v1/sources works without a key.

The response envelope

Every endpoint returns a JSON envelope:

{
  "data": [ ... ],
  "page": { "limit": 25, "next_cursor": "…", "has_more": true },
  "as_of": "2026-06-13T00:00:00Z",
  "source": "edgar",
  "query_echo": { ... },
  "warnings": []
}

The SDK wraps this in a Page object. For the common list case a Page behaves like the data list (iterate, index, len()), while the envelope metadata and response headers stay available as attributes:

page = client.events.list(ticker="NVDA", importance="high")

for event in page:            # iterate over page.data
    print(event["event_type"])

first = page[0]               # index into page.data
n = len(page)                 # number of records on this page

page.next_cursor              # cursor for the next page (or None)
page.has_more                 # bool
page.as_of                    # snapshot timestamp
page.source                   # upstream source
page.warnings                 # list of warnings
page.raw                      # the full untouched envelope dict

# Response headers
page.request_id               # X-Request-Id
page.credits_cost             # X-Credits-Cost
page.credits_remaining        # X-Credits-Remaining

Single-object endpoints (e.g. client.account(), client.financials.get(...)) expose the object via page.data; len(page) is then 1.

Pagination

Use ?cursor= / limit= manually, or let the SDK follow page.next_cursor for you with the iterate(...) helper available on every list resource. It yields individual records across all pages and accepts an optional max_items cap:

# Manual
page = client.filings.search(form_type="8-K", limit=100)
while page.has_more:
    page = client.filings.search(form_type="8-K", limit=100, cursor=page.next_cursor)

# Auto — yields every record, stops after max_items
for filing in client.filings.iterate(cik="0000320193", form_type="8-K", max_items=500):
    print(filing["accession"])

limit must be ≤ 100.

Token-efficient projections

Every list/get method accepts fields= (comma-separated dot-paths) or output_schema= (a JSON Schema dict) to project each record server-side:

client.filings.search(form_type="10-K", fields="accession,company_name,filed_date")
client.events.list(ticker="NVDA", output_schema={"type": "object", "properties": {"event_type": {}, "title": {}}})

Resources & methods

The client groups endpoints by resource. Each search/list method also has an iterate(...) auto-paginator.

Resource Methods
client.filings search, iterate, documents, extract(item=…), insiders, events, subsidiaries, crowdfunding, proxy_votes, briefing
client.full_text search(q=…), iterate
client.entities search / resolve, iterate
client.insider search, iterate, form144, iterate_form144
client.ownership search, iterate — 13D/13G
client.holdings search, iterate — 13F holdings
client.managers search, iterate — 13F managers
client.funds holdings, providers, iterate_holdings, iterate_providers — N-PORT / N-CEN
client.advisers search, iterate, get(crd) — Form ADV
client.private_funds / client.private_fund_stats search, iterate
client.broker_dealers / client.form_crs / client.iapd_individuals search, iterate
client.raises search, iterate — Form D
client.financials search, iterate, get(cik, concept=…)
client.financial_statements search, iterate
client.board / client.compensation search, iterate
client.proxy officers, iterate_officers — DEF 14A
client.enforcement / client.litigation / client.nt_late / client.trading_suspensions / client.whistleblower search, iterate
client.cyber_incidents search, iterate — 8-K Item 1.05
client.patents search, iterate — USPTO grants
client.events list, iterate, get(event_id)
client.monitors list, create, get, update, delete
client.webhooks list_endpoints, create_endpoint, list_deliveries
top-level client.account(), client.sources(), client.answer(q, …), client.briefing(accession), client.chat(messages=…)

Method parameters mirror the REST endpoints. Any extra keyword arguments are passed straight through as query params (or body fields for POST/PATCH), so new API params work without an SDK upgrade. There are also raw escape hatches: client.get(path, params=…) and client.post(path, body=…).

Examples

# Insider transactions (Form 4) — purchases over $1M
client.insider.search(ticker="TSLA", trans_code="P", min_value_usd=1_000_000)

# 13F institutional holdings of a security
client.holdings.search(cusip="037833100", min_value=5_000_000)

# Extract Risk Factors from a 10-K
client.filings.extract("0000320193-23-000106", item="1A")

# AI briefing for a filing
brief = client.briefing("0000320193-23-000106")

# Create a monitor that webhooks on high-importance NVDA events
ep = client.webhooks.create_endpoint(url="https://example.com/hook")
mon = client.monitors.create(
    name="NVDA watch", target_type="ticker", target_value="NVDA",
    materiality="high", webhook_endpoint_id=ep.data["id"],
)

# Stream the events feed
for ev in client.events.iterate(ticker="NVDA", importance="high", max_items=100):
    print(ev["event_type"])

OpenAI-compatible endpoint

Clous exposes an OpenAI-compatible chat endpoint. Use the built-in helper:

out = client.chat(messages=[{"role": "user", "content": "Summarize Apple's latest 8-K"}])
print(out["choices"][0]["message"]["content"])

…or point the official openai SDK at Clous directly:

from openai import OpenAI

oai = OpenAI(base_url="https://api.clous.ai/v1", api_key="<CLOUS_API_KEY>")
resp = oai.chat.completions.create(model="clous", messages=[{"role": "user", "content": "…"}])

The Clous SDK also accepts base_url="https://api.clous.ai/v1"; the trailing /v1 is normalized so resource paths still resolve.

Errors, timeouts, retries

Non-2xx responses raise a typed exception carrying status_code, request_id, message, and the parsed body:

from clous import APIError, AuthenticationError, RateLimitError, NotFoundError

try:
    client.filings.search()
except AuthenticationError:
    ...        # 401
except RateLimitError as e:
    ...        # 429
except NotFoundError:
    ...        # 404
except APIError as e:
    print(e.status_code, e.request_id, e.message)

The client times out after 30s (configurable via timeout=) and retries transient failures (429 + 5xx + network errors) up to max_retries (default 3) with exponential backoff that honors Retry-After.

Development

pip install -e ".[dev]"
pytest -q

License

MIT

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

clous-0.1.0.tar.gz (18.3 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

clous-0.1.0-py3-none-any.whl (18.1 kB view details)

Uploaded Python 3

File details

Details for the file clous-0.1.0.tar.gz.

File metadata

  • Download URL: clous-0.1.0.tar.gz
  • Upload date:
  • Size: 18.3 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.14.2

File hashes

Hashes for clous-0.1.0.tar.gz
Algorithm Hash digest
SHA256 0ac3334a0894ac09510e23cfc8f1c72bd1d20f648afbee4c0ca79190aaf726b3
MD5 ae35fddf357be401efc6aa680da7d963
BLAKE2b-256 e942807b8c7d10b169c46778252ec51eaa72219d26f9577559e01e007690e628

See more details on using hashes here.

File details

Details for the file clous-0.1.0-py3-none-any.whl.

File metadata

  • Download URL: clous-0.1.0-py3-none-any.whl
  • Upload date:
  • Size: 18.1 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.14.2

File hashes

Hashes for clous-0.1.0-py3-none-any.whl
Algorithm Hash digest
SHA256 b0425e719cc822225469a932fcd63616c0f12fc2dd6ce114c5efe6081346a782
MD5 47dfef3fd94dedb495809a8fd5ae0387
BLAKE2b-256 de6ade3c7ba6d620dddd11181c7e89e8fc71fc2d4632575d54332fa1b44f1783

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page