trodo-python 1.0.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,227 @@
1
+ Metadata-Version: 2.4
2
+ Name: trodo-python
3
+ Version: 1.0.0
4
+ Summary: Trodo Analytics SDK for Python — server-side event tracking
5
+ License: ISC
6
+ Keywords: analytics,tracking,trodo,server-side
7
+ Classifier: Programming Language :: Python :: 3
8
+ Classifier: Programming Language :: Python :: 3.8
9
+ Classifier: Programming Language :: Python :: 3.9
10
+ Classifier: Programming Language :: Python :: 3.10
11
+ Classifier: Programming Language :: Python :: 3.11
12
+ Classifier: Programming Language :: Python :: 3.12
13
+ Classifier: License :: OSI Approved :: ISC License (ISCL)
14
+ Classifier: Operating System :: OS Independent
15
+ Classifier: Intended Audience :: Developers
16
+ Classifier: Topic :: Software Development :: Libraries :: Python Modules
17
+ Requires-Python: >=3.8
18
+ Description-Content-Type: text/markdown
19
+ Requires-Dist: requests>=2.28.0
20
+ Provides-Extra: async
21
+ Requires-Dist: httpx>=0.27.0; extra == "async"
22
+ Provides-Extra: dev
23
+ Requires-Dist: pytest>=7.0; extra == "dev"
24
+ Requires-Dist: pytest-cov; extra == "dev"
25
+ Requires-Dist: responses>=0.25.0; extra == "dev"
26
+ Requires-Dist: httpx>=0.27.0; extra == "dev"
27
+
28
+ # trodo-python
29
+
30
+ Server-side Python SDK for [Trodo Analytics](https://trodo.ai). Track backend events, identify users, and manage people/groups — all merging seamlessly with your frontend Trodo data under the same `site_id`.
31
+
32
+ ## Installation
33
+
34
+ ```bash
35
+ pip install trodo-python
36
+ ```
37
+
38
+ For async support (optional):
39
+
40
+ ```bash
41
+ pip install trodo-python[async]
42
+ ```
43
+
44
+ Requires Python 3.8+.
45
+
46
+ ## Quick Start
47
+
48
+ ```python
49
+ import trodo
50
+
51
+ # Initialize once at app startup
52
+ trodo.init(
53
+ site_id='your-site-id',
54
+ debug=False, # optional: log API calls
55
+ auto_events=True, # optional: hook sys.excepthook
56
+ )
57
+
58
+ # Get a user context
59
+ user = trodo.for_user('user-123')
60
+
61
+ # Track a custom event
62
+ user.track('purchase_completed', {'amount': 99.99, 'plan': 'pro'})
63
+
64
+ # Identify the user (merges with frontend events under the same identity)
65
+ user.identify('user@example.com') # distinct_id becomes id_user@example.com
66
+
67
+ # Update people profile
68
+ user.people.set({'plan': 'pro', 'company': 'Acme'})
69
+
70
+ # Track a server-side error
71
+ user.capture_error(Exception('payment failed'))
72
+
73
+ # Flush queued events before process exit
74
+ trodo.shutdown()
75
+ ```
76
+
77
+ ## Flask / FastAPI Example
78
+
79
+ ```python
80
+ # Flask
81
+ from flask import Flask, request
82
+ import trodo
83
+
84
+ app = Flask(__name__)
85
+ trodo.init(site_id='your-site-id')
86
+
87
+ @app.route('/purchase', methods=['POST'])
88
+ def purchase():
89
+ user_id = request.json['user_id']
90
+ user = trodo.for_user(user_id)
91
+ user.track('purchase_completed', {'amount': request.json['amount']})
92
+ return {'ok': True}
93
+ ```
94
+
95
+ ## Cross-SDK Identity Merging
96
+
97
+ Frontend and backend events merge when both sides call `identify()` with the same value:
98
+
99
+ ```python
100
+ # Python SDK
101
+ user.identify('user@example.com') # → id_user@example.com
102
+
103
+ # Browser SDK (same value)
104
+ # Trodo.identify('user@example.com') → id_user@example.com
105
+
106
+ # Both event streams now appear together in the Trodo dashboard
107
+ ```
108
+
109
+ ## API Reference
110
+
111
+ ### `trodo.init(config)`
112
+
113
+ | Parameter | Type | Default | Description |
114
+ |-----------|------|---------|-------------|
115
+ | `site_id` | `str` | required | Your Trodo site ID |
116
+ | `api_base` | `str` | `https://sdkapi.trodo.ai` | API base URL |
117
+ | `debug` | `bool` | `False` | Log API requests/responses |
118
+ | `auto_events` | `bool` | `False` | Hook `sys.excepthook` + `threading.excepthook` |
119
+ | `retries` | `int` | `3` | HTTP retry attempts on 5xx errors |
120
+ | `timeout` | `int` | `10` | HTTP timeout in seconds |
121
+ | `batch_enabled` | `bool` | `False` | Queue events and flush in bulk |
122
+ | `batch_size` | `int` | `50` | Max events per batch flush |
123
+ | `batch_flush_interval` | `float` | `5.0` | Flush interval in seconds |
124
+ | `on_error` | `callable` | `None` | Callback for SDK errors |
125
+
126
+ ### `trodo.for_user(distinct_id, session_id=None)`
127
+
128
+ Returns a user-bound context. All subsequent calls use this user's session.
129
+
130
+ ```python
131
+ user = trodo.for_user(
132
+ 'user-123',
133
+ session_id=request.cookies.get('trodo_session'), # optional: correlate with browser session
134
+ )
135
+ ```
136
+
137
+ ### User Context Methods
138
+
139
+ ```python
140
+ user.track(event_name, properties=None) # Track custom event
141
+ user.track_event(event_name, properties=None) # Alias for track()
142
+ user.identify(identify_id) # Merge identity
143
+ user.wallet_address(address) # Set crypto wallet address
144
+ user.reset() # Clear session context
145
+ user.capture_error(exception) # Track server_error event
146
+
147
+ # People profile
148
+ user.people.set(properties)
149
+ user.people.set_once(properties)
150
+ user.people.unset(keys)
151
+ user.people.increment(properties)
152
+ user.people.append(properties)
153
+ user.people.union(properties)
154
+ user.people.remove(properties)
155
+ user.people.track_charge(amount, properties=None)
156
+ user.people.clear_charges()
157
+ user.people.delete_user()
158
+
159
+ # Groups
160
+ user.set_group(group_key, group_id)
161
+ user.add_group(group_key, group_id)
162
+ user.remove_group(group_key, group_id)
163
+ group = user.get_group(group_key, group_id)
164
+ group.set(properties)
165
+ group.set_once(properties)
166
+ group.union(properties)
167
+ group.remove(properties)
168
+ group.unset(keys)
169
+ group.increment(properties)
170
+ group.append(properties)
171
+ group.delete()
172
+ ```
173
+
174
+ ### Direct Call Pattern (for pipelines/scripts)
175
+
176
+ ```python
177
+ trodo.track('user-123', 'event_name', {'key': 'value'})
178
+ trodo.identify('user-123', 'identify_id')
179
+ trodo.people_set('user-123', {'plan': 'pro'})
180
+ trodo.set_group('user-123', 'company', 'acme')
181
+ ```
182
+
183
+ ### Global Methods
184
+
185
+ ```python
186
+ trodo.enable_auto_events() # Enable sys.excepthook hooks
187
+ trodo.disable_auto_events() # Disable hooks
188
+ trodo.flush() # Flush pending batch queue
189
+ trodo.shutdown() # Flush + stop background timers
190
+ ```
191
+
192
+ ## Auto Events
193
+
194
+ When `auto_events=True`, the SDK wraps Python's exception hooks and sends `server_error` events to Trodo:
195
+
196
+ - `sys.excepthook` — unhandled exceptions in the main thread
197
+ - `threading.excepthook` — unhandled exceptions in threads
198
+
199
+ These events use `distinct_id: 'server_global'` in the dashboard.
200
+
201
+ Per-user error capture: `user.capture_error(e)` uses the user's own `distinct_id`.
202
+
203
+ ## Batching
204
+
205
+ ```python
206
+ trodo.init(
207
+ site_id='your-site-id',
208
+ batch_enabled=True,
209
+ batch_size=100,
210
+ batch_flush_interval=3.0,
211
+ )
212
+
213
+ # Events are queued and flushed every 3s or when 100 events accumulate
214
+ user.track('page_view')
215
+
216
+ # Always flush before process exit
217
+ import atexit
218
+ atexit.register(trodo.shutdown)
219
+ ```
220
+
221
+ ## Thread Safety
222
+
223
+ The SDK is thread-safe. `SessionManager`, `EventQueue`, and `BatchFlusher` all use `threading.Lock` internally. Safe to use in multi-threaded Flask/Django/FastAPI applications.
224
+
225
+ ## License
226
+
227
+ ISC
@@ -0,0 +1,200 @@
1
+ # trodo-python
2
+
3
+ Server-side Python SDK for [Trodo Analytics](https://trodo.ai). Track backend events, identify users, and manage people/groups — all merging seamlessly with your frontend Trodo data under the same `site_id`.
4
+
5
+ ## Installation
6
+
7
+ ```bash
8
+ pip install trodo-python
9
+ ```
10
+
11
+ For async support (optional):
12
+
13
+ ```bash
14
+ pip install trodo-python[async]
15
+ ```
16
+
17
+ Requires Python 3.8+.
18
+
19
+ ## Quick Start
20
+
21
+ ```python
22
+ import trodo
23
+
24
+ # Initialize once at app startup
25
+ trodo.init(
26
+ site_id='your-site-id',
27
+ debug=False, # optional: log API calls
28
+ auto_events=True, # optional: hook sys.excepthook
29
+ )
30
+
31
+ # Get a user context
32
+ user = trodo.for_user('user-123')
33
+
34
+ # Track a custom event
35
+ user.track('purchase_completed', {'amount': 99.99, 'plan': 'pro'})
36
+
37
+ # Identify the user (merges with frontend events under the same identity)
38
+ user.identify('user@example.com') # distinct_id becomes id_user@example.com
39
+
40
+ # Update people profile
41
+ user.people.set({'plan': 'pro', 'company': 'Acme'})
42
+
43
+ # Track a server-side error
44
+ user.capture_error(Exception('payment failed'))
45
+
46
+ # Flush queued events before process exit
47
+ trodo.shutdown()
48
+ ```
49
+
50
+ ## Flask / FastAPI Example
51
+
52
+ ```python
53
+ # Flask
54
+ from flask import Flask, request
55
+ import trodo
56
+
57
+ app = Flask(__name__)
58
+ trodo.init(site_id='your-site-id')
59
+
60
+ @app.route('/purchase', methods=['POST'])
61
+ def purchase():
62
+ user_id = request.json['user_id']
63
+ user = trodo.for_user(user_id)
64
+ user.track('purchase_completed', {'amount': request.json['amount']})
65
+ return {'ok': True}
66
+ ```
67
+
68
+ ## Cross-SDK Identity Merging
69
+
70
+ Frontend and backend events merge when both sides call `identify()` with the same value:
71
+
72
+ ```python
73
+ # Python SDK
74
+ user.identify('user@example.com') # → id_user@example.com
75
+
76
+ # Browser SDK (same value)
77
+ # Trodo.identify('user@example.com') → id_user@example.com
78
+
79
+ # Both event streams now appear together in the Trodo dashboard
80
+ ```
81
+
82
+ ## API Reference
83
+
84
+ ### `trodo.init(config)`
85
+
86
+ | Parameter | Type | Default | Description |
87
+ |-----------|------|---------|-------------|
88
+ | `site_id` | `str` | required | Your Trodo site ID |
89
+ | `api_base` | `str` | `https://sdkapi.trodo.ai` | API base URL |
90
+ | `debug` | `bool` | `False` | Log API requests/responses |
91
+ | `auto_events` | `bool` | `False` | Hook `sys.excepthook` + `threading.excepthook` |
92
+ | `retries` | `int` | `3` | HTTP retry attempts on 5xx errors |
93
+ | `timeout` | `int` | `10` | HTTP timeout in seconds |
94
+ | `batch_enabled` | `bool` | `False` | Queue events and flush in bulk |
95
+ | `batch_size` | `int` | `50` | Max events per batch flush |
96
+ | `batch_flush_interval` | `float` | `5.0` | Flush interval in seconds |
97
+ | `on_error` | `callable` | `None` | Callback for SDK errors |
98
+
99
+ ### `trodo.for_user(distinct_id, session_id=None)`
100
+
101
+ Returns a user-bound context. All subsequent calls use this user's session.
102
+
103
+ ```python
104
+ user = trodo.for_user(
105
+ 'user-123',
106
+ session_id=request.cookies.get('trodo_session'), # optional: correlate with browser session
107
+ )
108
+ ```
109
+
110
+ ### User Context Methods
111
+
112
+ ```python
113
+ user.track(event_name, properties=None) # Track custom event
114
+ user.track_event(event_name, properties=None) # Alias for track()
115
+ user.identify(identify_id) # Merge identity
116
+ user.wallet_address(address) # Set crypto wallet address
117
+ user.reset() # Clear session context
118
+ user.capture_error(exception) # Track server_error event
119
+
120
+ # People profile
121
+ user.people.set(properties)
122
+ user.people.set_once(properties)
123
+ user.people.unset(keys)
124
+ user.people.increment(properties)
125
+ user.people.append(properties)
126
+ user.people.union(properties)
127
+ user.people.remove(properties)
128
+ user.people.track_charge(amount, properties=None)
129
+ user.people.clear_charges()
130
+ user.people.delete_user()
131
+
132
+ # Groups
133
+ user.set_group(group_key, group_id)
134
+ user.add_group(group_key, group_id)
135
+ user.remove_group(group_key, group_id)
136
+ group = user.get_group(group_key, group_id)
137
+ group.set(properties)
138
+ group.set_once(properties)
139
+ group.union(properties)
140
+ group.remove(properties)
141
+ group.unset(keys)
142
+ group.increment(properties)
143
+ group.append(properties)
144
+ group.delete()
145
+ ```
146
+
147
+ ### Direct Call Pattern (for pipelines/scripts)
148
+
149
+ ```python
150
+ trodo.track('user-123', 'event_name', {'key': 'value'})
151
+ trodo.identify('user-123', 'identify_id')
152
+ trodo.people_set('user-123', {'plan': 'pro'})
153
+ trodo.set_group('user-123', 'company', 'acme')
154
+ ```
155
+
156
+ ### Global Methods
157
+
158
+ ```python
159
+ trodo.enable_auto_events() # Enable sys.excepthook hooks
160
+ trodo.disable_auto_events() # Disable hooks
161
+ trodo.flush() # Flush pending batch queue
162
+ trodo.shutdown() # Flush + stop background timers
163
+ ```
164
+
165
+ ## Auto Events
166
+
167
+ When `auto_events=True`, the SDK wraps Python's exception hooks and sends `server_error` events to Trodo:
168
+
169
+ - `sys.excepthook` — unhandled exceptions in the main thread
170
+ - `threading.excepthook` — unhandled exceptions in threads
171
+
172
+ These events use `distinct_id: 'server_global'` in the dashboard.
173
+
174
+ Per-user error capture: `user.capture_error(e)` uses the user's own `distinct_id`.
175
+
176
+ ## Batching
177
+
178
+ ```python
179
+ trodo.init(
180
+ site_id='your-site-id',
181
+ batch_enabled=True,
182
+ batch_size=100,
183
+ batch_flush_interval=3.0,
184
+ )
185
+
186
+ # Events are queued and flushed every 3s or when 100 events accumulate
187
+ user.track('page_view')
188
+
189
+ # Always flush before process exit
190
+ import atexit
191
+ atexit.register(trodo.shutdown)
192
+ ```
193
+
194
+ ## Thread Safety
195
+
196
+ The SDK is thread-safe. `SessionManager`, `EventQueue`, and `BatchFlusher` all use `threading.Lock` internally. Safe to use in multi-threaded Flask/Django/FastAPI applications.
197
+
198
+ ## License
199
+
200
+ ISC
@@ -0,0 +1,43 @@
1
+ [build-system]
2
+ requires = ["setuptools>=68", "wheel"]
3
+ build-backend = "setuptools.build_meta"
4
+
5
+ [project]
6
+ name = "trodo-python"
7
+ version = "1.0.0"
8
+ description = "Trodo Analytics SDK for Python — server-side event tracking"
9
+ readme = "README.md"
10
+ license = { text = "ISC" }
11
+ requires-python = ">=3.8"
12
+ dependencies = [
13
+ "requests>=2.28.0",
14
+ ]
15
+ keywords = ["analytics", "tracking", "trodo", "server-side"]
16
+ classifiers = [
17
+ "Programming Language :: Python :: 3",
18
+ "Programming Language :: Python :: 3.8",
19
+ "Programming Language :: Python :: 3.9",
20
+ "Programming Language :: Python :: 3.10",
21
+ "Programming Language :: Python :: 3.11",
22
+ "Programming Language :: Python :: 3.12",
23
+ "License :: OSI Approved :: ISC License (ISCL)",
24
+ "Operating System :: OS Independent",
25
+ "Intended Audience :: Developers",
26
+ "Topic :: Software Development :: Libraries :: Python Modules",
27
+ ]
28
+
29
+ [project.optional-dependencies]
30
+ async = ["httpx>=0.27.0"]
31
+ dev = [
32
+ "pytest>=7.0",
33
+ "pytest-cov",
34
+ "responses>=0.25.0",
35
+ "httpx>=0.27.0",
36
+ ]
37
+
38
+ [tool.setuptools.packages.find]
39
+ where = ["."]
40
+ include = ["trodo*"]
41
+
42
+ [tool.pytest.ini_options]
43
+ testpaths = ["tests"]
@@ -0,0 +1,4 @@
1
+ [egg_info]
2
+ tag_build =
3
+ tag_date = 0
4
+
@@ -0,0 +1,134 @@
1
+ """
2
+ trodo-python — Trodo Analytics SDK for Python
3
+
4
+ Usage (module-level singleton):
5
+ import trodo
6
+ trodo.init(site_id='your-site-id')
7
+ user = trodo.for_user('user-123')
8
+ user.track('purchase_completed', {'amount': 99.99})
9
+
10
+ Usage (class):
11
+ from trodo import TrodoClient
12
+ client = TrodoClient(site_id='your-site-id')
13
+ user = client.for_user('user-123')
14
+ user.track('purchase_completed', {'amount': 99.99})
15
+ """
16
+
17
+ from __future__ import annotations
18
+
19
+ from typing import Any, Dict, List, Optional, Union
20
+
21
+ from .client import TrodoClient
22
+ from .user_context import UserContext
23
+ from .managers.group_manager import GroupProfile
24
+ from .types import ApiResult, IdentifyResult, ResetResult, WalletAddressResult
25
+
26
+ __all__ = [
27
+ "TrodoClient",
28
+ "UserContext",
29
+ "GroupProfile",
30
+ "init",
31
+ "for_user",
32
+ "track",
33
+ "identify",
34
+ "wallet_address",
35
+ "reset",
36
+ "enable_auto_events",
37
+ "disable_auto_events",
38
+ "flush",
39
+ "shutdown",
40
+ ]
41
+
42
+ # ============================================================================
43
+ # Singleton convenience API
44
+ # ============================================================================
45
+
46
+ _client: Optional[TrodoClient] = None
47
+
48
+
49
+ def _get_client() -> TrodoClient:
50
+ if _client is None:
51
+ raise RuntimeError(
52
+ "trodo-python: Call trodo.init(site_id=...) before using the SDK."
53
+ )
54
+ return _client
55
+
56
+
57
+ def init(
58
+ site_id: str,
59
+ api_base: str = "https://sdkapi.trodo.ai",
60
+ timeout: int = 10,
61
+ retries: int = 2,
62
+ batch_enabled: bool = False,
63
+ batch_size: int = 50,
64
+ batch_flush_interval: float = 5.0,
65
+ auto_events: bool = False,
66
+ on_error: Optional[Any] = None,
67
+ debug: bool = False,
68
+ ) -> TrodoClient:
69
+ """Initialise the singleton SDK instance."""
70
+ global _client
71
+ _client = TrodoClient(
72
+ site_id=site_id,
73
+ api_base=api_base,
74
+ timeout=timeout,
75
+ retries=retries,
76
+ batch_enabled=batch_enabled,
77
+ batch_size=batch_size,
78
+ batch_flush_interval=batch_flush_interval,
79
+ auto_events=auto_events,
80
+ on_error=on_error,
81
+ debug=debug,
82
+ )
83
+ return _client
84
+
85
+
86
+ def for_user(
87
+ distinct_id: str,
88
+ session_id: Optional[str] = None,
89
+ ) -> UserContext:
90
+ """Return a UserContext bound to the given distinctId."""
91
+ return _get_client().for_user(distinct_id, session_id)
92
+
93
+
94
+ def track(
95
+ distinct_id: str,
96
+ event_name: str,
97
+ properties: Optional[Dict[str, Any]] = None,
98
+ category: str = "custom",
99
+ ) -> None:
100
+ """Track an event for a user (direct-call pattern)."""
101
+ _get_client().track(distinct_id, event_name, properties, category)
102
+
103
+
104
+ def identify(distinct_id: str, identify_id: str) -> IdentifyResult:
105
+ """Alias a user's distinctId to an external identifier."""
106
+ return _get_client().identify(distinct_id, identify_id)
107
+
108
+
109
+ def wallet_address(distinct_id: str, wallet_addr: str) -> WalletAddressResult:
110
+ """Associate a wallet address with a user."""
111
+ return _get_client().wallet_address(distinct_id, wallet_addr)
112
+
113
+
114
+ def reset(distinct_id: str) -> ResetResult:
115
+ """Reset a user's session."""
116
+ return _get_client().reset(distinct_id)
117
+
118
+
119
+ def enable_auto_events() -> None:
120
+ _get_client().enable_auto_events()
121
+
122
+
123
+ def disable_auto_events() -> None:
124
+ _get_client().disable_auto_events()
125
+
126
+
127
+ def flush() -> None:
128
+ """Flush any queued batch events."""
129
+ _get_client().flush()
130
+
131
+
132
+ def shutdown() -> None:
133
+ """Flush, stop timers, and disable auto events."""
134
+ _get_client().shutdown()
File without changes
@@ -0,0 +1,96 @@
1
+ """Async HTTP client using httpx (optional dependency)."""
2
+
3
+ from __future__ import annotations
4
+
5
+ import sys
6
+ import asyncio
7
+ from typing import Any, Callable, Dict, Optional
8
+
9
+ from ..types import ApiResult, EventPayload
10
+
11
+
12
+ class AsyncHttpClient:
13
+ def __init__(
14
+ self,
15
+ api_base: str,
16
+ site_id: str,
17
+ timeout: int = 10,
18
+ retries: int = 2,
19
+ on_error: Optional[Callable[[Exception], None]] = None,
20
+ debug: bool = False,
21
+ ) -> None:
22
+ try:
23
+ import httpx # noqa: F401
24
+ except ImportError:
25
+ raise ImportError(
26
+ "trodo-python async support requires httpx: pip install trodo-python[async]"
27
+ )
28
+
29
+ self.api_base = api_base.rstrip("/")
30
+ self.site_id = site_id
31
+ self.timeout = timeout
32
+ self.retries = retries
33
+ self.on_error = on_error
34
+ self.debug = debug
35
+
36
+ def _log(self, *args: Any) -> None:
37
+ if self.debug:
38
+ sys.stderr.write(f"[trodo-python-async] {' '.join(str(a) for a in args)}\n")
39
+
40
+ async def _request(
41
+ self, path: str, body: Dict[str, Any], attempt: int = 0
42
+ ) -> ApiResult:
43
+ import httpx
44
+
45
+ url = f"{self.api_base}{path}"
46
+ self._log(f"POST {url}")
47
+ headers = {
48
+ "Content-Type": "application/json",
49
+ "X-Trodo-Site-Id": self.site_id,
50
+ }
51
+ try:
52
+ async with httpx.AsyncClient(timeout=self.timeout) as client:
53
+ resp = await client.post(url, json=body, headers=headers)
54
+ if resp.status_code >= 500 and attempt < self.retries:
55
+ delay = 2 ** attempt
56
+ self._log(f"Retry {attempt + 1} after {delay}s")
57
+ await asyncio.sleep(delay)
58
+ return await self._request(path, body, attempt + 1)
59
+ try:
60
+ return resp.json()
61
+ except Exception:
62
+ return {}
63
+ except Exception as exc:
64
+ if attempt < self.retries:
65
+ await asyncio.sleep(2 ** attempt)
66
+ return await self._request(path, body, attempt + 1)
67
+ self._log(f"Error: {exc}")
68
+ if self.on_error:
69
+ self.on_error(exc)
70
+ return {}
71
+
72
+ async def post_track(self, session_data: Dict[str, Any]) -> ApiResult:
73
+ return await self._request("/api/sdk/track", {"sessionData": session_data})
74
+
75
+ async def post_event(self, event: EventPayload) -> ApiResult:
76
+ return await self._request("/api/events", event.to_dict())
77
+
78
+ async def post_bulk_events(self, events: list) -> ApiResult:
79
+ return await self._request(
80
+ "/api/events/bulk", {"events": [e.to_dict() for e in events]}
81
+ )
82
+
83
+ async def post_identify(self, payload: Dict[str, Any]) -> ApiResult:
84
+ return await self._request("/api/sdk/identify", payload)
85
+
86
+ async def post_wallet_address(self, payload: Dict[str, Any]) -> ApiResult:
87
+ return await self._request("/api/sdk/wallet-address", payload)
88
+
89
+ async def post_reset(self, payload: Dict[str, Any]) -> ApiResult:
90
+ return await self._request("/api/sdk/reset", payload)
91
+
92
+ async def post_people(self, path: str, payload: Dict[str, Any]) -> ApiResult:
93
+ return await self._request(path, payload)
94
+
95
+ async def post_group(self, path: str, payload: Dict[str, Any]) -> ApiResult:
96
+ return await self._request(path, payload)