europatech 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,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Europa Tech Enterprise S.R.L.
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,133 @@
1
+ Metadata-Version: 2.4
2
+ Name: europatech
3
+ Version: 1.0.0
4
+ Summary: Official Python SDK for the Europa Tech real estate tokenization API
5
+ Project-URL: Homepage, https://europa-tech.org/docs/api
6
+ Project-URL: Repository, https://github.com/europa-tech-srl/europatech-sdk-python
7
+ Project-URL: Documentation, https://europa-tech.org/docs/api
8
+ Author-email: "Europa Tech Enterprise S.R.L." <admin@europa-tech.org>
9
+ License-Expression: MIT
10
+ License-File: LICENSE
11
+ Keywords: api,europa-tech,europatech,mica,real-estate,rwa,sdk,tokenization
12
+ Classifier: Development Status :: 4 - Beta
13
+ Classifier: Intended Audience :: Developers
14
+ Classifier: License :: OSI Approved :: MIT License
15
+ Classifier: Programming Language :: Python :: 3
16
+ Classifier: Programming Language :: Python :: 3.9
17
+ Classifier: Programming Language :: Python :: 3.10
18
+ Classifier: Programming Language :: Python :: 3.11
19
+ Classifier: Programming Language :: Python :: 3.12
20
+ Classifier: Typing :: Typed
21
+ Requires-Python: >=3.9
22
+ Requires-Dist: httpx>=0.27
23
+ Description-Content-Type: text/markdown
24
+
25
+ # europatech
26
+
27
+ Official Python SDK for the [Europa Tech](https://europa-tech.org) real estate tokenization API.
28
+
29
+ ## Installation
30
+
31
+ ```bash
32
+ pip install europatech
33
+ ```
34
+
35
+ ## Quick Start
36
+
37
+ ```python
38
+ from europatech import EuropaTech
39
+
40
+ client = EuropaTech(api_key="your-api-key")
41
+
42
+ # List available properties
43
+ objects = client.list_objects()
44
+ for obj in objects:
45
+ print(f"{obj.name}: {obj.available_shares} shares available")
46
+
47
+ # Get your portfolio
48
+ portfolio = client.get_portfolio()
49
+ print(f"Total value: EUR {portfolio.total_value}")
50
+
51
+ # Get room prices
52
+ rooms = client.list_rooms("obj-001")
53
+ for room in rooms:
54
+ print(f"{room.name}: EUR {room.share_price}/share")
55
+ ```
56
+
57
+ ## API Reference
58
+
59
+ ### Objects
60
+
61
+ ```python
62
+ client.list_objects() # List all properties
63
+ client.get_object("obj-001") # Get property details
64
+ client.list_rooms("obj-001") # Get rooms with share prices
65
+ ```
66
+
67
+ ### Portfolio
68
+
69
+ ```python
70
+ client.get_portfolio() # Your holdings
71
+ client.list_transactions(page=1, limit=20) # Transaction history
72
+ ```
73
+
74
+ ### P2P Marketplace
75
+
76
+ ```python
77
+ client.list_p2p() # Active listings
78
+ client.create_p2p_listing( # Sell shares
79
+ object_id="obj-001",
80
+ room_id="room-101",
81
+ shares=5,
82
+ price_per_share=70.0,
83
+ )
84
+ client.cancel_p2p_listing("listing-id") # Cancel listing
85
+ ```
86
+
87
+ ### Investment
88
+
89
+ ```python
90
+ client.invest( # Buy shares
91
+ object_id="obj-001",
92
+ room_id="room-101",
93
+ shares=10,
94
+ payment_method="CARD",
95
+ )
96
+ ```
97
+
98
+ ### Market & Fund
99
+
100
+ ```python
101
+ client.get_market_rates() # EUR/USD, BTC, ETH rates
102
+ client.get_fund() # AUM, distributions
103
+ ```
104
+
105
+ ### Compliance
106
+
107
+ ```python
108
+ client.get_compliance_status() # KYC/AML status
109
+ ```
110
+
111
+ ## Webhooks
112
+
113
+ ```python
114
+ from europatech.webhooks import verify_webhook, parse_webhook_event
115
+
116
+ # Verify signature
117
+ is_valid = verify_webhook(request.body, request.headers["X-EuropaTech-Signature"], secret)
118
+
119
+ # Parse event
120
+ event = parse_webhook_event(request.body)
121
+ print(event.type) # "investment.completed"
122
+ ```
123
+
124
+ ## Context Manager
125
+
126
+ ```python
127
+ with EuropaTech(api_key="your-key") as client:
128
+ objects = client.list_objects()
129
+ ```
130
+
131
+ ## License
132
+
133
+ MIT — Europa Tech Enterprise S.R.L.
@@ -0,0 +1,109 @@
1
+ # europatech
2
+
3
+ Official Python SDK for the [Europa Tech](https://europa-tech.org) real estate tokenization API.
4
+
5
+ ## Installation
6
+
7
+ ```bash
8
+ pip install europatech
9
+ ```
10
+
11
+ ## Quick Start
12
+
13
+ ```python
14
+ from europatech import EuropaTech
15
+
16
+ client = EuropaTech(api_key="your-api-key")
17
+
18
+ # List available properties
19
+ objects = client.list_objects()
20
+ for obj in objects:
21
+ print(f"{obj.name}: {obj.available_shares} shares available")
22
+
23
+ # Get your portfolio
24
+ portfolio = client.get_portfolio()
25
+ print(f"Total value: EUR {portfolio.total_value}")
26
+
27
+ # Get room prices
28
+ rooms = client.list_rooms("obj-001")
29
+ for room in rooms:
30
+ print(f"{room.name}: EUR {room.share_price}/share")
31
+ ```
32
+
33
+ ## API Reference
34
+
35
+ ### Objects
36
+
37
+ ```python
38
+ client.list_objects() # List all properties
39
+ client.get_object("obj-001") # Get property details
40
+ client.list_rooms("obj-001") # Get rooms with share prices
41
+ ```
42
+
43
+ ### Portfolio
44
+
45
+ ```python
46
+ client.get_portfolio() # Your holdings
47
+ client.list_transactions(page=1, limit=20) # Transaction history
48
+ ```
49
+
50
+ ### P2P Marketplace
51
+
52
+ ```python
53
+ client.list_p2p() # Active listings
54
+ client.create_p2p_listing( # Sell shares
55
+ object_id="obj-001",
56
+ room_id="room-101",
57
+ shares=5,
58
+ price_per_share=70.0,
59
+ )
60
+ client.cancel_p2p_listing("listing-id") # Cancel listing
61
+ ```
62
+
63
+ ### Investment
64
+
65
+ ```python
66
+ client.invest( # Buy shares
67
+ object_id="obj-001",
68
+ room_id="room-101",
69
+ shares=10,
70
+ payment_method="CARD",
71
+ )
72
+ ```
73
+
74
+ ### Market & Fund
75
+
76
+ ```python
77
+ client.get_market_rates() # EUR/USD, BTC, ETH rates
78
+ client.get_fund() # AUM, distributions
79
+ ```
80
+
81
+ ### Compliance
82
+
83
+ ```python
84
+ client.get_compliance_status() # KYC/AML status
85
+ ```
86
+
87
+ ## Webhooks
88
+
89
+ ```python
90
+ from europatech.webhooks import verify_webhook, parse_webhook_event
91
+
92
+ # Verify signature
93
+ is_valid = verify_webhook(request.body, request.headers["X-EuropaTech-Signature"], secret)
94
+
95
+ # Parse event
96
+ event = parse_webhook_event(request.body)
97
+ print(event.type) # "investment.completed"
98
+ ```
99
+
100
+ ## Context Manager
101
+
102
+ ```python
103
+ with EuropaTech(api_key="your-key") as client:
104
+ objects = client.list_objects()
105
+ ```
106
+
107
+ ## License
108
+
109
+ MIT — Europa Tech Enterprise S.R.L.
@@ -0,0 +1,34 @@
1
+ """Official Python SDK for the Europa Tech real estate tokenization API."""
2
+
3
+ from europatech.client import EuropaTech
4
+ from europatech.types import (
5
+ RealEstateObject,
6
+ Room,
7
+ Portfolio,
8
+ Holding,
9
+ Transaction,
10
+ P2PListing,
11
+ MarketRates,
12
+ InvestResult,
13
+ Fund,
14
+ Distribution,
15
+ ComplianceStatus,
16
+ ApiError,
17
+ )
18
+
19
+ __version__ = "1.0.0"
20
+ __all__ = [
21
+ "EuropaTech",
22
+ "RealEstateObject",
23
+ "Room",
24
+ "Portfolio",
25
+ "Holding",
26
+ "Transaction",
27
+ "P2PListing",
28
+ "MarketRates",
29
+ "InvestResult",
30
+ "Fund",
31
+ "Distribution",
32
+ "ComplianceStatus",
33
+ "ApiError",
34
+ ]
@@ -0,0 +1,201 @@
1
+ """Europa Tech API client."""
2
+
3
+ from __future__ import annotations
4
+
5
+ from typing import Any, Optional
6
+
7
+ import httpx
8
+
9
+ from europatech.types import (
10
+ ApiError,
11
+ ComplianceStatus,
12
+ Distribution,
13
+ Fund,
14
+ Holding,
15
+ InvestResult,
16
+ MarketRates,
17
+ P2PListing,
18
+ Portfolio,
19
+ RealEstateObject,
20
+ Room,
21
+ Transaction,
22
+ )
23
+
24
+ DEFAULT_BASE_URL = "https://api.europa-tech.org"
25
+
26
+
27
+ def _to_snake(name: str) -> str:
28
+ """Convert camelCase to snake_case."""
29
+ result: list[str] = []
30
+ for c in name:
31
+ if c.isupper() and result:
32
+ result.append("_")
33
+ result.append(c.lower())
34
+ return "".join(result)
35
+
36
+
37
+ def _snake_keys(data: Any) -> Any:
38
+ """Recursively convert dict keys from camelCase to snake_case."""
39
+ if isinstance(data, dict):
40
+ return {_to_snake(k): _snake_keys(v) for k, v in data.items()}
41
+ if isinstance(data, list):
42
+ return [_snake_keys(item) for item in data]
43
+ return data
44
+
45
+
46
+ class EuropaTech:
47
+ """Official Europa Tech API client.
48
+
49
+ Usage::
50
+
51
+ from europatech import EuropaTech
52
+
53
+ client = EuropaTech(api_key="your-api-key")
54
+ objects = client.list_objects()
55
+ """
56
+
57
+ def __init__(
58
+ self,
59
+ api_key: str,
60
+ base_url: str = DEFAULT_BASE_URL,
61
+ timeout: float = 30.0,
62
+ ) -> None:
63
+ if not api_key:
64
+ raise ValueError("api_key is required")
65
+ self._client = httpx.Client(
66
+ base_url=base_url.rstrip("/"),
67
+ headers={
68
+ "Authorization": f"Bearer {api_key}",
69
+ "Content-Type": "application/json",
70
+ "X-SDK-Version": "python/1.0.0",
71
+ },
72
+ timeout=timeout,
73
+ )
74
+
75
+ def close(self) -> None:
76
+ """Close the HTTP client."""
77
+ self._client.close()
78
+
79
+ def __enter__(self) -> "EuropaTech":
80
+ return self
81
+
82
+ def __exit__(self, *_: Any) -> None:
83
+ self.close()
84
+
85
+ def _request(self, method: str, path: str, json: Any = None) -> Any:
86
+ resp = self._client.request(method, path, json=json)
87
+ if resp.status_code >= 400:
88
+ try:
89
+ body = resp.json()
90
+ msg = body.get("error", resp.reason_phrase)
91
+ code = body.get("code", "UNKNOWN_ERROR")
92
+ except Exception:
93
+ msg = resp.reason_phrase
94
+ code = "UNKNOWN_ERROR"
95
+ raise ApiError(resp.status_code, msg, code)
96
+ return resp.json()
97
+
98
+ # ─── Objects ──────────────────────────────────────────
99
+
100
+ def list_objects(self) -> list[RealEstateObject]:
101
+ """List all real estate objects."""
102
+ data = self._request("GET", "/api/v1/objects")["data"]
103
+ return [RealEstateObject(**_snake_keys(o)) for o in data]
104
+
105
+ def get_object(self, object_id: str) -> RealEstateObject:
106
+ """Get a single object by ID."""
107
+ data = self._request("GET", f"/api/v1/objects/{object_id}")["data"]
108
+ return RealEstateObject(**_snake_keys(data))
109
+
110
+ def list_rooms(self, object_id: str) -> list[Room]:
111
+ """Get rooms for an object."""
112
+ data = self._request("GET", f"/api/v1/objects/{object_id}/rooms")["data"]
113
+ return [Room(**_snake_keys(r)) for r in data]
114
+
115
+ # ─── Portfolio ────────────────────────────────────────
116
+
117
+ def get_portfolio(self) -> Portfolio:
118
+ """Get current user's portfolio."""
119
+ raw = _snake_keys(self._request("GET", "/api/v1/portfolio")["data"])
120
+ raw["holdings"] = [Holding(**h) for h in raw.get("holdings", [])]
121
+ return Portfolio(**raw)
122
+
123
+ def list_transactions(
124
+ self,
125
+ page: int = 1,
126
+ limit: int = 20,
127
+ type: Optional[str] = None,
128
+ ) -> list[Transaction]:
129
+ """List portfolio transactions."""
130
+ params = f"?page={page}&limit={limit}"
131
+ if type:
132
+ params += f"&type={type}"
133
+ data = self._request("GET", f"/api/v1/portfolio/transactions{params}")["data"]
134
+ return [Transaction(**_snake_keys(t)) for t in data]
135
+
136
+ # ─── P2P Marketplace ──────────────────────────────────
137
+
138
+ def list_p2p(self) -> list[P2PListing]:
139
+ """List P2P listings."""
140
+ data = self._request("GET", "/api/v1/p2p")["data"]
141
+ return [P2PListing(**_snake_keys(l)) for l in data]
142
+
143
+ def create_p2p_listing(
144
+ self,
145
+ object_id: str,
146
+ room_id: str,
147
+ shares: int,
148
+ price_per_share: float,
149
+ ) -> P2PListing:
150
+ """Create a P2P sell listing."""
151
+ data = self._request("POST", "/api/v1/p2p", json={
152
+ "objectId": object_id,
153
+ "roomId": room_id,
154
+ "shares": shares,
155
+ "pricePerShare": price_per_share,
156
+ })["data"]
157
+ return P2PListing(**_snake_keys(data))
158
+
159
+ def cancel_p2p_listing(self, listing_id: str) -> None:
160
+ """Cancel a P2P listing."""
161
+ self._request("DELETE", f"/api/v1/p2p/{listing_id}")
162
+
163
+ # ─── Market ───────────────────────────────────────────
164
+
165
+ def get_market_rates(self) -> MarketRates:
166
+ """Get current market rates."""
167
+ data = self._request("GET", "/api/v1/market/rates")["data"]
168
+ return MarketRates(**_snake_keys(data))
169
+
170
+ # ─── Investment ───────────────────────────────────────
171
+
172
+ def invest(
173
+ self,
174
+ object_id: str,
175
+ room_id: str,
176
+ shares: int,
177
+ payment_method: str = "CARD",
178
+ ) -> InvestResult:
179
+ """Execute a share purchase."""
180
+ data = self._request("POST", "/api/v1/invest", json={
181
+ "objectId": object_id,
182
+ "roomId": room_id,
183
+ "shares": shares,
184
+ "paymentMethod": payment_method,
185
+ })["data"]
186
+ return InvestResult(**_snake_keys(data))
187
+
188
+ # ─── Fund ─────────────────────────────────────────────
189
+
190
+ def get_fund(self) -> Fund:
191
+ """Get fund overview."""
192
+ raw = _snake_keys(self._request("GET", "/api/v1/fund")["data"])
193
+ raw["distributions"] = [Distribution(**d) for d in raw.get("distributions", [])]
194
+ return Fund(**raw)
195
+
196
+ # ─── Compliance ───────────────────────────────────────
197
+
198
+ def get_compliance_status(self) -> ComplianceStatus:
199
+ """Get current user's KYC/AML compliance status."""
200
+ data = self._request("GET", "/api/v1/compliance/status")["data"]
201
+ return ComplianceStatus(**_snake_keys(data))
File without changes
@@ -0,0 +1,127 @@
1
+ """Type definitions for Europa Tech API responses."""
2
+
3
+ from __future__ import annotations
4
+
5
+ from dataclasses import dataclass, field
6
+ from typing import Optional
7
+
8
+
9
+ class ApiError(Exception):
10
+ """API error with status code and error code."""
11
+
12
+ def __init__(self, status: int, message: str, code: str = "UNKNOWN_ERROR") -> None:
13
+ super().__init__(message)
14
+ self.status = status
15
+ self.code = code
16
+
17
+
18
+ @dataclass(frozen=True)
19
+ class Room:
20
+ id: str
21
+ name: str
22
+ number: int
23
+ share_price: float
24
+ total_shares: int
25
+ available_shares: int
26
+ status: str
27
+
28
+
29
+ @dataclass(frozen=True)
30
+ class RealEstateObject:
31
+ id: str
32
+ name: str
33
+ location: str
34
+ image_url: str
35
+ status: str
36
+ total_shares: int
37
+ available_shares: int
38
+ rooms: list[Room] = field(default_factory=list)
39
+
40
+
41
+ @dataclass(frozen=True)
42
+ class Holding:
43
+ object_id: str
44
+ object_name: str
45
+ room_id: str
46
+ room_name: str
47
+ shares: int
48
+ share_price: float
49
+ value: float
50
+ purchased_at: str
51
+
52
+
53
+ @dataclass(frozen=True)
54
+ class Portfolio:
55
+ total_value: float
56
+ total_shares: int
57
+ total_invested: float
58
+ holdings: list[Holding] = field(default_factory=list)
59
+
60
+
61
+ @dataclass(frozen=True)
62
+ class Transaction:
63
+ id: str
64
+ type: str
65
+ object_id: str
66
+ room_id: str
67
+ shares: int
68
+ price_per_share: float
69
+ total_amount: float
70
+ status: str
71
+ created_at: str
72
+
73
+
74
+ @dataclass(frozen=True)
75
+ class P2PListing:
76
+ id: str
77
+ object_id: str
78
+ room_id: str
79
+ seller_id: str
80
+ shares: int
81
+ price_per_share: float
82
+ status: str
83
+ created_at: str
84
+
85
+
86
+ @dataclass(frozen=True)
87
+ class MarketRates:
88
+ eur_usd: float
89
+ btc_eur: float
90
+ eth_eur: float
91
+ updated_at: str
92
+
93
+
94
+ @dataclass(frozen=True)
95
+ class InvestResult:
96
+ transaction_id: str
97
+ status: str
98
+ total_amount: float
99
+ currency: str
100
+
101
+
102
+ @dataclass(frozen=True)
103
+ class Distribution:
104
+ month: str
105
+ revenue: float
106
+ expenses: float
107
+ net_profit: float
108
+ distributed_per_share: float
109
+ status: str
110
+
111
+
112
+ @dataclass(frozen=True)
113
+ class Fund:
114
+ total_aum: float
115
+ total_investors: int
116
+ total_properties: int
117
+ total_rooms: int
118
+ distributions: list[Distribution] = field(default_factory=list)
119
+
120
+
121
+ @dataclass(frozen=True)
122
+ class ComplianceStatus:
123
+ kyc_status: str
124
+ kyc_level: int
125
+ aml_status: str
126
+ investment_limit: float
127
+ invested_amount: float
@@ -0,0 +1,77 @@
1
+ """Webhook verification for Europa Tech."""
2
+
3
+ from __future__ import annotations
4
+
5
+ import hashlib
6
+ import hmac
7
+ import json
8
+ from dataclasses import dataclass
9
+ from typing import Any, Literal
10
+
11
+
12
+ def verify_webhook(payload: str | bytes, signature: str, secret: str) -> bool:
13
+ """Verify an incoming Europa Tech webhook signature (HMAC-SHA256).
14
+
15
+ Args:
16
+ payload: Raw request body.
17
+ signature: Value of the X-EuropaTech-Signature header.
18
+ secret: Your webhook secret from the dashboard.
19
+
20
+ Returns:
21
+ True if the signature is valid.
22
+
23
+ Example::
24
+
25
+ from europatech.webhooks import verify_webhook
26
+
27
+ @app.post("/webhook")
28
+ def handle_webhook(request):
29
+ sig = request.headers["X-EuropaTech-Signature"]
30
+ if not verify_webhook(request.body, sig, WEBHOOK_SECRET):
31
+ return {"error": "Invalid signature"}, 401
32
+ event = parse_webhook_event(request.body)
33
+ ...
34
+ """
35
+ if not payload or not signature or not secret:
36
+ return False
37
+
38
+ if isinstance(payload, str):
39
+ payload = payload.encode()
40
+
41
+ expected = hmac.new(secret.encode(), payload, hashlib.sha256).hexdigest()
42
+ sig = signature.removeprefix("sha256=")
43
+
44
+ return hmac.compare_digest(expected, sig)
45
+
46
+
47
+ WebhookEventType = Literal[
48
+ "investment.completed",
49
+ "investment.failed",
50
+ "p2p.listing.created",
51
+ "p2p.listing.sold",
52
+ "p2p.listing.cancelled",
53
+ "distribution.published",
54
+ "kyc.approved",
55
+ "kyc.rejected",
56
+ "transfer.completed",
57
+ ]
58
+
59
+
60
+ @dataclass(frozen=True)
61
+ class WebhookEvent:
62
+ id: str
63
+ type: WebhookEventType
64
+ created_at: str
65
+ data: dict[str, Any]
66
+
67
+
68
+ def parse_webhook_event(payload: str | bytes) -> WebhookEvent:
69
+ """Parse a webhook payload into a typed event object."""
70
+ raw = payload if isinstance(payload, str) else payload.decode()
71
+ d = json.loads(raw)
72
+ return WebhookEvent(
73
+ id=d["id"],
74
+ type=d["type"],
75
+ created_at=d.get("createdAt", ""),
76
+ data=d.get("data", {}),
77
+ )
@@ -0,0 +1,30 @@
1
+ [build-system]
2
+ requires = ["hatchling"]
3
+ build-backend = "hatchling.build"
4
+
5
+ [project]
6
+ name = "europatech"
7
+ version = "1.0.0"
8
+ description = "Official Python SDK for the Europa Tech real estate tokenization API"
9
+ readme = "README.md"
10
+ license = "MIT"
11
+ requires-python = ">=3.9"
12
+ authors = [{ name = "Europa Tech Enterprise S.R.L.", email = "admin@europa-tech.org" }]
13
+ keywords = ["europatech", "europa-tech", "real-estate", "tokenization", "rwa", "api", "sdk", "mica"]
14
+ classifiers = [
15
+ "Development Status :: 4 - Beta",
16
+ "Intended Audience :: Developers",
17
+ "License :: OSI Approved :: MIT License",
18
+ "Programming Language :: Python :: 3",
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
+ "Typing :: Typed",
24
+ ]
25
+ dependencies = ["httpx>=0.27"]
26
+
27
+ [project.urls]
28
+ Homepage = "https://europa-tech.org/docs/api"
29
+ Repository = "https://github.com/europa-tech-srl/europatech-sdk-python"
30
+ Documentation = "https://europa-tech.org/docs/api"