> For the complete documentation index, see [llms.txt](https://sm-fund.gitbook.io/sm-fund-docs/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://sm-fund.gitbook.io/sm-fund-docs/examples/python.md).

# Python

This example uses Python 3.11 or later and [`websockets` 16](https://websockets.readthedocs.io/en/16.0/reference/sync/client.html). It requests a fresh Ticket, receives three messages, and closes. It does not automatically reconnect.

## Install and configure

In a new local directory, create a virtual environment:

```bash
python3 -m venv .venv
source .venv/bin/activate
python -m pip install 'websockets==16.0'
```

Set `SMFUND_API_KEY` through your secret manager or environment. If it is absent, the example securely prompts for the key in your terminal. Set `SMFUND_FEED=raw` for raw notifications; the default is `polymarket`.

This example opens a connection for your account, replacing any other active client.

## Receive messages

Save as `smfund.py`:

```python
import getpass
import json
import os
import sys
import time
from urllib.error import HTTPError, URLError
from urllib.request import Request, urlopen

from websockets.exceptions import ConnectionClosed, InvalidHandshake
from websockets.sync.client import connect


def main():
    api_key = os.environ.get("SMFUND_API_KEY") or getpass.getpass("SM FUND API Key: ")
    requested_feed = os.environ.get("SMFUND_FEED", "polymarket")
    if not api_key or requested_feed not in {"polymarket", "raw"}:
        print("Set an API Key and choose polymarket or raw.", file=sys.stderr)
        return 1

    request = Request(
        "https://sm.fund/v1/wss/tickets",
        data=json.dumps({"feed": requested_feed}).encode(),
        headers={"X-API-Key": api_key, "Content-Type": "application/json"},
        method="POST",
    )
    try:
        with urlopen(request, timeout=15) as response:
            issued = json.load(response)
    except HTTPError as error:
        print(f"Ticket request failed: HTTP {error.code}", file=sys.stderr)
        if error.headers.get("Retry-After"):
            print(f"Retry after {error.headers['Retry-After']} seconds.", file=sys.stderr)
        return 1
    except (URLError, TimeoutError):
        print("Ticket request failed; check your network.", file=sys.stderr)
        return 1

    issued_feed = issued["feed"]
    if issued_feed not in {"polymarket", "raw"} or issued_feed != requested_feed:
        print("Ticket response selected an unexpected feed.", file=sys.stderr)
        return 1

    try:
        with connect(
            issued["wss_url"],
            subprotocols=[issued["subprotocol"]],
            additional_headers={"Authorization": f"Bearer {issued['ticket']}"},
            open_timeout=15,
            max_size=16 * 1024 * 1024,
        ) as socket:
            print(f"Connected: {issued_feed}")
            deadline = time.monotonic() + 60
            for received in range(1, 4):
                text = socket.recv(timeout=max(0, deadline - time.monotonic()))
                if issued_feed == "raw":
                    # 原始通知保持文本；本示例只打印大小。
                    print(f"Raw message {received}: {len(text.encode('utf-8'))} bytes")
                else:
                    batch = json.loads(text)
                    print(batch["tx_hash"], f"{len(batch['fills'])} fills")
            socket.close(1000, "sample complete")
            print("Closed: 1000")
    except ConnectionClosed as error:
        code = error.rcvd.code if error.rcvd else 1006
        print(f"Closed: {code}", file=sys.stderr)
        if code == 4001:
            print("Replaced by another client; stop reconnecting.", file=sys.stderr)
        elif code == 4003:
            print("Access changed; check access and request a fresh Ticket.", file=sys.stderr)
        return 1
    except TimeoutError:
        print("Connection or three-message sample timed out.", file=sys.stderr)
        return 1
    except (InvalidHandshake, OSError):
        print("WebSocket connection failed; check the handshake and network.", file=sys.stderr)
        return 1
    return 0


if __name__ == "__main__":
    raise SystemExit(main())
```

Run:

```bash
python smfund.py
```

Expected output starts with `Connected: polymarket`, followed by transaction hashes and fill counts, then `Closed: 1000`. Raw mode prints byte lengths while leaving the notification text intact. A sample timeout does not by itself prove that the service is unavailable.

The library handles protocol ping/pong. The example uses a 16 MiB incoming-message limit; that is a client setting, not a promised maximum frame size for the service. Adapt it to your workload, and follow the [connection lifecycle guide](/sm-fund-docs/guides/connection-lifecycle.md) for a continuous consumer.
