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.catalog.list_table_categories()
tables = client.catalog.list_tables(category="equities")
schema = client.catalog.describe_table("financial_ratio", group="valuation")
# Table query — same operators as REST (eq, in, not_in, gte/lte/gt/lt)
rows = client.tables.query(
"stock_price_history",
columns=["symbol", "date", "close"],
filters={"symbol": "VNM", "date": {"gte": "-30d"}},
sort="date.desc",
limit=5,
)
# Document search (semantic)
hits = 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,
)
Async
import asyncio
from investify_data import AsyncDataClient
async def main():
async with AsyncDataClient(api_key="ifyu_...") as client:
rows = await client.tables.query("stock_price_history", filters={"symbol": "VNM"}, limit=5)
print(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). Usinghttp://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": {"items": [{"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
- Source: https://gitlab.com/investify-vn/core/investify-data
- Data API docs: internal
wos-docs/data-api/
License
MIT
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file investify_data-0.1.0a13.tar.gz.
File metadata
- Download URL: investify_data-0.1.0a13.tar.gz
- Upload date:
- Size: 16.6 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: uv/0.9.0
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
20f825304d248fb2543f4b30adb5fa13dd46b404b9e216e3bc6f4cf8dd4e9ce7
|
|
| MD5 |
05b770a765edb2db101b5bd393daa6d1
|
|
| BLAKE2b-256 |
844a790c9088be2f81c9e016e33dea58b72a46818c895af05e391c49d189c77f
|
File details
Details for the file investify_data-0.1.0a13-py3-none-any.whl.
File metadata
- Download URL: investify_data-0.1.0a13-py3-none-any.whl
- Upload date:
- Size: 16.3 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: uv/0.9.0
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
4f6e2dd557aa6568ef6aea8589b68c7899fda88b5ab23de368e05517e01b0789
|
|
| MD5 |
ce25a811ab30f40cfbe43b73c6728392
|
|
| BLAKE2b-256 |
240a8422cb4bdacdf6d1c2cc053735d168bc0de0b8e45e7b3af83199f2d2486f
|