Python SDK
causet-sdk provides both an async client (CausetClient) and a sync client (CausetClientSync, which wraps every async method with asyncio.run()) for scripts, CLI tools, or synchronous frameworks.
The Python SDK is Early access. Source: github.com/Causet-Inc/causet-sdks (packages/python); PyPI publish in progress. See What runs today? for maturity and production-support details.
Requirements
- Python 3.10+
- Dependencies:
httpx,websockets
Installation
PyPI is not published yet. Install from source:
git clone https://github.com/Causet-Inc/causet-sdks.git
cd causet-sdks/packages/python && pip install -e ".[dev]"For team contributors with an existing checkout:
Quick start
Async
import asyncio
from causet_sdk import CausetClient
async def main():
client = CausetClient(
api_url="https://api.causet.cloud",
platform_slug="my-platform",
app_slug="my-app",
api_key="ck_live_xxx.secret",
)
await client.init()
# Subscribe and read entity state
await client.subscribe("ticket_stream", "tkt_1")
print(client.get_state("ticket_stream", "tkt_1"))
# Submit intent
result = await client.submitIntent(
"ticket_stream", "tkt_1", "CREATE_TICKET",
{"customer_id": "cust_1", "subject": "Help", "body": "..."},
)
print("Accepted:", result["accepted"], "Execution:", result.get("execution_id"))
# Run query
rows = await client.run_query("urgent_tickets", {"status": "open"}, limit=20)
print(f"{len(rows['items'])} tickets")
# SSE intent progress
await client.submit_intent_stream(
"ticket_stream", "tkt_1", "PROCESS_REFUND", {"amount_cents": 5000},
on_event=lambda ev: print(ev.get("event"), ev.get("data")),
)
# WebSocket streaming
client.on("state", lambda e: print("State:", e))
await client.connect_stream("ticket_stream")
client.destroy()
asyncio.run(main())Sync
from causet_sdk import CausetClientSync
client = CausetClientSync(
api_url="https://api.causet.cloud",
platform_slug="my-platform",
app_slug="my-app",
bearer_token="eyJ...",
)
client.init()
client.subscribe("orders", "ord_1")
print(client.get_state("orders", "ord_1"))
client.destroy()Configuration
CausetClient(
api_url: str, # required — e.g. "https://api.causet.cloud"
platform_slug: str, # required
app_slug: str, # required
fork_id: str = "main", # optional
ws_url: str | None = None, # optional — derived from api_url
bearer_token: str = "", # static JWT
api_key: str = "", # cloud API key (preferred for servers)
)Provide either api_key or bearer_token.
API keys (ck_live_...) are exchanged via POST /v1/token. The SDK caches the JWT until ~30 seconds before expiry, coalesces concurrent token requests, retries transient network errors (up to 4 attempts), and force-refreshes on HTTP 401.
Entity state
await client.subscribe("stream", "entity")
client.get_state("stream", "entity") # deep clone or None
client.unsubscribe("stream", "entity")
await client.fetch_state("stream", "entity") # one-shot, no cache
await client.fetch_state_at_cursor("s", "e", 42)
await client.diff_state("s", "e", cursor_a=10, cursor_b=20)
await client.list_entities(stream_name="orders", limit=50)Intents
result = await client.submitIntent(
"stream", "entity", "INTENT_TYPE",
{"key": "value"},
intent_id="optional-idempotency-key",
)
# {"accepted": bool, "execution_id": str|None, "error": str|None, "state_patch": ...}
await client.submit_intent_stream(
"stream", "entity", "INTENT_TYPE", payload,
on_event=lambda ev: print(ev),
)Queries and projections
await client.run_query(
"query_slug",
{"param": "value"},
limit=30, # page size
offset=0, # skipped when cursor is set
cursor="abc",
include_total=True,
)
await client.list_queries()
await client.get_query_definition("query_slug")
await client.list_projections()
await client.get_projection_schema("projection_slug")Query input stringification: values are coerced to strings before send — booleans → "true"/"false", lists/dicts → JSON, numbers → decimal strings.
Row flattening: dotted keys like artist_directory.artist_id become artist_id in result rows (see causet_sdk.flatten_projection_row).
Real-time (WebSocket & SSE)
conn_id = await client.connect_stream(
"stream_id",
from_cursor=0,
channels=[{"channel": "ledger"}, {"channel": "state"}],
)
client.on("stream_event", handler)
client.on("stream_connected", lambda ev: print(ev["conn_id"], ev["transport"]))
await client.connect_stream(
"stream_id:entity-1",
transport="sse",
from_cursor=100,
)
client.disconnect_stream()Live events come from causet-realtime (*.realtime.causet.cloud). See SSE / WebSocket for URLs, sample JSON responses, and SSE wire format.
Selectors
unsub = client.select(
"stream", "entity",
lambda state: state["cart"]["total"],
lambda total: print(f"Total: {total}"),
)
unsub()Error handling
from causet_sdk import CausetError, CausetAuthError, CausetApiError
try:
await client.submitIntent("ticket_stream", "tkt_1", "CREATE_TICKET", {})
except CausetApiError as e:
print(e.status_code, e.body)
except CausetAuthError as e:
print("Auth failed:", e)HTTP endpoints
| Operation | Path |
|---|---|
| Token | POST /v1/token |
| Intent | POST /v1/runtime/platforms/{p}/applications/{a}/intents/submit |
| Intent SSE | POST /v1/runtime/stream/platforms/{p}/applications/{a}/intents/submit |
| Entity state | GET /v1/platforms/{p}/applications/{a}/entities/{stream}/{id}/state |
| Query | POST /v1/platforms/{p}/applications/{a}/forks/{fork}/queries/{slug}/run |
Next steps
- TypeScript / JavaScript — equivalent client for JS/Node
- Testing — integration-testing patterns
- Roadmap — publishing status