# Setup & Helpers

Use this page before running any script in this section.

### Requirements

Use Python `3.10+`.

Install the required packages first.

{% code title="install.sh" %}

```bash
pip install requests websockets cryptography
```

{% endcode %}

{% hint style="warning" %}
Replace every placeholder API key, secret, event ID, outcome ID, and asset ID before running a script.
{% endhint %}

### Authenticated REST client

Use this client for authenticated REST requests.

Requests are routed to the correct service by path prefix.

{% code title="outpoll\_client.py" %}

```python
import hmac, hashlib, base64, time, json, requests

SERVICE_MAP = {
    "/api/events":      "https://event-service.outpoll.com",
    "/api/categories":  "https://event-service.outpoll.com",
    "/api/tags":        "https://event-service.outpoll.com",
    "/api/coins":       "https://wallet-mutator-view.outpoll.com",
    "/api/user-balances": "https://wallet-mutator-view.outpoll.com",
    "/api/history":     "https://history-service.outpoll.com",
    "/orders":          "https://order-service.outpoll.com",
    "/auth":            "https://auth-service.outpoll.com",
}

class OutpollClient:
    def __init__(self, api_key: str, api_secret: str):
        self.api_key = api_key
        self.api_secret = api_secret

    def _host(self, path: str) -> str:
        for prefix, host in SERVICE_MAP.items():
            if path.startswith(prefix):
                return host
        return "https://event-service.outpoll.com"

    def _sign(self, method: str, path: str, body: str = "") -> dict:
        timestamp = str(int(time.time()))
        message = timestamp + method + path + body
        padded = self.api_secret + "=" * (4 - len(self.api_secret) % 4) if len(self.api_secret) % 4 else self.api_secret
        secret_bytes = base64.urlsafe_b64decode(padded)
        signature = base64.urlsafe_b64encode(
            hmac.new(secret_bytes, message.encode(), hashlib.sha256).digest()
        ).decode().rstrip("=")
        return {
            "OUTPOLL-API-KEY": self.api_key,
            "OUTPOLL-API-SIGNATURE": signature,
            "OUTPOLL-API-TIMESTAMP": timestamp,
            "Content-Type": "application/json",
        }

    def get(self, path: str, params: dict = None):
        headers = self._sign("GET", path)
        return requests.get(self._host(path) + path, headers=headers, params=params)

    def post(self, path: str, data: dict = None):
        body = json.dumps(data) if data else ""
        headers = self._sign("POST", path, body)
        return requests.post(self._host(path) + path, headers=headers, data=body)

    def delete(self, path: str):
        headers = self._sign("DELETE", path)
        return requests.delete(self._host(path) + path, headers=headers)
```

{% endcode %}

### WebSocket auth helper

Use this helper for private WebSocket streams.

{% code title="ws\_auth.py" %}

```python
def ws_auth_message(api_key: str, api_secret: str, path: str) -> dict:
    timestamp = str(int(time.time()))
    message = timestamp + "GET" + path
    secret_padded = api_secret + "=" * (4 - len(api_secret) % 4) if len(api_secret) % 4 else api_secret
    secret_bytes = base64.urlsafe_b64decode(secret_padded)
    signature = base64.urlsafe_b64encode(
        hmac.new(secret_bytes, message.encode(), hashlib.sha256).digest()
    ).decode().rstrip("=")
    return {
        "t": "AUTH",
        "d": {
            "apiKey": api_key,
            "signature": signature,
            "timestamp": timestamp,
        },
    }
```

{% endcode %}

### Related pages

Use these references when adapting the helpers:

* [Public API Overview](https://docs.outpoll.com/api/rest-api/public-endpoints/public-api-overview)
* [WebSocket API Reference](https://docs.outpoll.com/api/rest-api/websockets/websocket-api-reference)
* [Orders](https://docs.outpoll.com/api/rest-api/private-endpoints/orders)
* [Balances](https://docs.outpoll.com/api/rest-api/private-endpoints/balances)
