SDKsPython

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

OperationPath
TokenPOST /v1/token
IntentPOST /v1/runtime/platforms/{p}/applications/{a}/intents/submit
Intent SSEPOST /v1/runtime/stream/platforms/{p}/applications/{a}/intents/submit
Entity stateGET /v1/platforms/{p}/applications/{a}/entities/{stream}/{id}/state
QueryPOST /v1/platforms/{p}/applications/{a}/forks/{fork}/queries/{slug}/run

Next steps