Skip to main content

Python client for the Investify Data API (wos-data-api)

Project description

investify-data

Python client for the Investify Data API (wos-data-api) — an AI-agent-first financial-data platform covering Vietnamese market data, company profiles, financial ratios, and searchable document collections.

Installation

pip install investify-data

Python 3.10+ required.

Quickstart — Sync

from investify_data import DataClient

with DataClient(api_key="ifyu_...") as client:
    # Discovery
    categories = client.tables.categories()                  # TableCategoryList
    tables = client.tables.list(category="equities")         # TableList
    schema = client.tables.describe("financial_ratio", group="valuation")  # TableDetail

    # Table query — same operators as REST (eq, in, not_in, gte/lte/gt/lt)
    page = client.tables.query(
        "stock_price_history",
        columns=["symbol", "date", "close"],
        filters={"symbol": "VNM", "date": {"gte": "-30d"}},
        sort="date.desc",
        limit=5,
    )                                                        # RecordPage
    page.rows                                                # list[dict] — raw records

    # Document search (semantic) — 3-tier hierarchy ranked by document
    res = client.collections.search(
        "market_news",
        q="lãi suất ngân hàng tác động đến cổ phiếu",
        metadata_filters={"topic": {"in": ["banking", "macro"]}},
        limit=5,                                             # counts DOCUMENTS
    )                                                        # PassageResult
    doc = res.results[0]                                     # DocumentGroup (best-ranked)
    doc.document.document_id, doc.document.citable, doc.score
    doc.passages[0].content, doc.passages[0].score          # PassageHit (the body)

Responses are typed pydantic models (investify_data.models) mirroring the server's response schema — attribute access + autocomplete; .model_dump() for a plain dict. Unknown future fields are kept, not rejected.

Async

import asyncio
from investify_data import AsyncDataClient

async def main():
    async with AsyncDataClient(api_key="ifyu_...") as client:
        page = await client.tables.query("stock_price_history", filters={"symbol": "VNM"}, limit=5)
        print(page.rows)

asyncio.run(main())

Authentication

Three credential types, picked up from the api_key prefix:

Prefix Role Use
ifyu_ User Direct queries scoped to the user's permission
ifys_ Tenant Use on_behalf_of(user_id=...) for data; admin ops without
ifym_ Super admin Use on_behalf_of(tenant_id=..., user_id=...) for data
# Tenant key querying on behalf of an end-user
tenant_client = DataClient(api_key="ifys_...")
user_client = tenant_client.on_behalf_of(user_id="550e8400-e29b-41d4-a716-446655440000")

Error handling

from investify_data import DataClient, NotFound, InvalidRequest, Unauthorized

try:
    client.tables.query("nonexistent")
except NotFound:
    ...
except InvalidRequest as err:
    print(err.code, err.detail)
except Unauthorized:
    ...

All exceptions inherit from InvestifyDataError. APIError subclasses (Unauthorized, Forbidden, NotFound, InvalidRequest, RateLimited, ServerError) carry status_code, code, and detail. TransportError wraps network/TLS/timeout failures.

Security

  • Never commit your API key. Read it from an env var or secret store.
  • The SDK redacts keys in repr(), logs, and error messages — only the 5-char prefix is shown (e.g., ifyu_***).
  • HTTPS is the default (https://data.investify.vn). Using http:// with a production key triggers a runtime warning; local/LAN hosts (localhost, 127.0.0.1, investify.k8s) are exempt.
  • If you pin a custom base_url, keep it behind TLS.

Configuration

DataClient(
    api_key="ifyu_...",
    base_url="https://data.investify.vn",  # override for dev (e.g. http://investify.k8s:30702)
    timeout=30.0,                           # seconds
    user_agent="my-app/1.0",                # optional
)

Glossary (entity normalization)

Match free-text mentions to canonical terms (trigram, per tenant) — one noun endpoint:

out = client.glossary.match(["vietcombank", "ngân hàng ngoại thương"], kinds=["stock"])
# out.matches -> {"vietcombank": PhraseHits(items=[MatchHit(canonical="...", score=1.0, ...)], total=1)}
# out.unresolved -> phrases with no match

candidates = client.glossary.match(["VCB"], top_k_per_phrase=5)   # ranked candidates (disambiguation)

top_k_per_phrase=1 (default) = normalization; >1 = disambiguation. Same engine.

Pagination

Tables and collection list mode paginate with limit/offset:

offset = 0
while True:
    page = client.tables.query("stock_price_history", filters={"symbol": "VNM"}, limit=1000, offset=offset)
    if not page.rows:
        break
    process(page.rows)
    offset += len(page.rows)

Semantic search does not paginate — it returns the global top-limit by score; there is no offset/cursor. Raise limit (max 100) or narrow with metadata_filters instead.

Troubleshooting

Symptom Likely cause
Unauthorized (401) malformed/revoked key — check the ify[usm]_ prefix and key status
Forbidden (403) service key without user context — use client.on_behalf_of(user_id=...); or ifyu_ key combined with X-User-Id
NotFound (404) on a table/collection id not in catalog or no permission grant — both look identical by design
Empty rows/hits, no error permission row-scope ∩ your filters is empty — check tables.describe() and your grant
InvalidRequest (400) UNKNOWN_COLUMN column not in the catalog, not visible to you, or used in sort without being selected
InvalidRequest (400) on date range in semantic search date/relative ranges work in list mode only — drop q or move the range filter

Links

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

investify_data-0.1.0a19.tar.gz (21.3 kB view details)

Uploaded Source

Built Distribution

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

investify_data-0.1.0a19-py3-none-any.whl (19.9 kB view details)

Uploaded Python 3

File details

Details for the file investify_data-0.1.0a19.tar.gz.

File metadata

  • Download URL: investify_data-0.1.0a19.tar.gz
  • Upload date:
  • Size: 21.3 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: uv/0.9.0

File hashes

Hashes for investify_data-0.1.0a19.tar.gz
Algorithm Hash digest
SHA256 d9b00bd933bf48da50fc0f8f792dacaf2a6e0dd9e3e9c8f566045bc2327dabd5
MD5 dc3eda1d9d2bc65ea0d05d317f14472f
BLAKE2b-256 bbc7fece72991fe416b063f7c465764481874f0b90651ef484b99f52f1a40fb5

See more details on using hashes here.

File details

Details for the file investify_data-0.1.0a19-py3-none-any.whl.

File metadata

File hashes

Hashes for investify_data-0.1.0a19-py3-none-any.whl
Algorithm Hash digest
SHA256 539e4c6e8086eb9005eda5e54705924489332555f0a815990cb4292073d1264d
MD5 c26ec5e9132ecb1a9b187fbb45f084bb
BLAKE2b-256 4a423f33272aad2be3bab7e9b27ec14e3ee834a98a30b5a5a2d82dae1f27db56

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