settld-api-sdk-python 0.1.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.
- settld_api_sdk_python-0.1.0/PKG-INFO +14 -0
- settld_api_sdk_python-0.1.0/README.md +5 -0
- settld_api_sdk_python-0.1.0/pyproject.toml +20 -0
- settld_api_sdk_python-0.1.0/settld_api_sdk/__init__.py +3 -0
- settld_api_sdk_python-0.1.0/settld_api_sdk/client.py +346 -0
- settld_api_sdk_python-0.1.0/settld_api_sdk_python.egg-info/PKG-INFO +14 -0
- settld_api_sdk_python-0.1.0/settld_api_sdk_python.egg-info/SOURCES.txt +8 -0
- settld_api_sdk_python-0.1.0/settld_api_sdk_python.egg-info/dependency_links.txt +1 -0
- settld_api_sdk_python-0.1.0/settld_api_sdk_python.egg-info/top_level.txt +1 -0
- settld_api_sdk_python-0.1.0/setup.cfg +4 -0
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: settld-api-sdk-python
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: Settld API SDK (Python)
|
|
5
|
+
Author: Settld
|
|
6
|
+
License: UNLICENSED
|
|
7
|
+
Requires-Python: >=3.9
|
|
8
|
+
Description-Content-Type: text/markdown
|
|
9
|
+
|
|
10
|
+
# Settld API SDK (Python)
|
|
11
|
+
|
|
12
|
+
Python client for Settld API endpoints, including a high-level `first_verified_run` helper.
|
|
13
|
+
|
|
14
|
+
Quickstart docs live in `docs/QUICKSTART_SDK_PYTHON.md` at repo root.
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
[build-system]
|
|
2
|
+
requires = ["setuptools>=68"]
|
|
3
|
+
build-backend = "setuptools.build_meta"
|
|
4
|
+
|
|
5
|
+
[project]
|
|
6
|
+
name = "settld-api-sdk-python"
|
|
7
|
+
version = "0.1.0"
|
|
8
|
+
description = "Settld API SDK (Python)"
|
|
9
|
+
readme = "README.md"
|
|
10
|
+
requires-python = ">=3.9"
|
|
11
|
+
license = { text = "UNLICENSED" }
|
|
12
|
+
authors = [{ name = "Settld" }]
|
|
13
|
+
dependencies = []
|
|
14
|
+
|
|
15
|
+
[tool.setuptools]
|
|
16
|
+
include-package-data = true
|
|
17
|
+
|
|
18
|
+
[tool.setuptools.packages.find]
|
|
19
|
+
where = ["."]
|
|
20
|
+
include = ["settld_api_sdk*"]
|
|
@@ -0,0 +1,346 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
import json
|
|
4
|
+
import random
|
|
5
|
+
import time
|
|
6
|
+
import uuid
|
|
7
|
+
from typing import Any, Dict, Optional
|
|
8
|
+
from urllib import error, parse, request
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
def _assert_non_empty_string(value: Any, name: str) -> str:
|
|
12
|
+
if not isinstance(value, str) or value.strip() == "":
|
|
13
|
+
raise ValueError(f"{name} must be a non-empty string")
|
|
14
|
+
return value
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
def _random_request_id() -> str:
|
|
18
|
+
return f"req_{uuid.uuid4().hex}"
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
def _normalize_prefix(value: Optional[str], fallback: str) -> str:
|
|
22
|
+
if isinstance(value, str) and value.strip():
|
|
23
|
+
return value.strip()
|
|
24
|
+
return fallback
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
class SettldApiError(Exception):
|
|
28
|
+
def __init__(
|
|
29
|
+
self,
|
|
30
|
+
*,
|
|
31
|
+
status: int,
|
|
32
|
+
message: str,
|
|
33
|
+
code: Optional[str] = None,
|
|
34
|
+
details: Any = None,
|
|
35
|
+
request_id: Optional[str] = None,
|
|
36
|
+
) -> None:
|
|
37
|
+
super().__init__(message)
|
|
38
|
+
self.status = status
|
|
39
|
+
self.code = code
|
|
40
|
+
self.details = details
|
|
41
|
+
self.request_id = request_id
|
|
42
|
+
|
|
43
|
+
def to_dict(self) -> Dict[str, Any]:
|
|
44
|
+
return {
|
|
45
|
+
"status": self.status,
|
|
46
|
+
"code": self.code,
|
|
47
|
+
"message": str(self),
|
|
48
|
+
"details": self.details,
|
|
49
|
+
"requestId": self.request_id,
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
|
|
53
|
+
class SettldClient:
|
|
54
|
+
def __init__(
|
|
55
|
+
self,
|
|
56
|
+
*,
|
|
57
|
+
base_url: str,
|
|
58
|
+
tenant_id: str,
|
|
59
|
+
protocol: str = "1.0",
|
|
60
|
+
api_key: Optional[str] = None,
|
|
61
|
+
user_agent: Optional[str] = None,
|
|
62
|
+
timeout_seconds: float = 30.0,
|
|
63
|
+
) -> None:
|
|
64
|
+
self.base_url = _assert_non_empty_string(base_url, "base_url").rstrip("/")
|
|
65
|
+
self.tenant_id = _assert_non_empty_string(tenant_id, "tenant_id")
|
|
66
|
+
self.protocol = protocol
|
|
67
|
+
self.api_key = api_key
|
|
68
|
+
self.user_agent = user_agent
|
|
69
|
+
self.timeout_seconds = timeout_seconds
|
|
70
|
+
|
|
71
|
+
def _request(
|
|
72
|
+
self,
|
|
73
|
+
method: str,
|
|
74
|
+
path: str,
|
|
75
|
+
*,
|
|
76
|
+
body: Optional[Dict[str, Any]] = None,
|
|
77
|
+
request_id: Optional[str] = None,
|
|
78
|
+
idempotency_key: Optional[str] = None,
|
|
79
|
+
expected_prev_chain_hash: Optional[str] = None,
|
|
80
|
+
timeout_seconds: Optional[float] = None,
|
|
81
|
+
) -> Dict[str, Any]:
|
|
82
|
+
rid = request_id if request_id else _random_request_id()
|
|
83
|
+
headers = {
|
|
84
|
+
"content-type": "application/json",
|
|
85
|
+
"x-proxy-tenant-id": self.tenant_id,
|
|
86
|
+
"x-settld-protocol": self.protocol,
|
|
87
|
+
"x-request-id": rid,
|
|
88
|
+
}
|
|
89
|
+
if self.user_agent:
|
|
90
|
+
headers["user-agent"] = self.user_agent
|
|
91
|
+
if self.api_key:
|
|
92
|
+
headers["authorization"] = f"Bearer {self.api_key}"
|
|
93
|
+
if idempotency_key:
|
|
94
|
+
headers["x-idempotency-key"] = str(idempotency_key)
|
|
95
|
+
if expected_prev_chain_hash:
|
|
96
|
+
headers["x-proxy-expected-prev-chain-hash"] = str(expected_prev_chain_hash)
|
|
97
|
+
|
|
98
|
+
url = parse.urljoin(f"{self.base_url}/", path.lstrip("/"))
|
|
99
|
+
payload = None if body is None else json.dumps(body).encode("utf-8")
|
|
100
|
+
req = request.Request(url=url, data=payload, method=method, headers=headers)
|
|
101
|
+
timeout = self.timeout_seconds if timeout_seconds is None else timeout_seconds
|
|
102
|
+
try:
|
|
103
|
+
with request.urlopen(req, timeout=timeout) as response:
|
|
104
|
+
raw = response.read().decode("utf-8")
|
|
105
|
+
parsed = None
|
|
106
|
+
if raw:
|
|
107
|
+
try:
|
|
108
|
+
parsed = json.loads(raw)
|
|
109
|
+
except json.JSONDecodeError:
|
|
110
|
+
parsed = {"raw": raw}
|
|
111
|
+
response_headers = {str(k).lower(): str(v) for k, v in response.headers.items()}
|
|
112
|
+
return {
|
|
113
|
+
"ok": True,
|
|
114
|
+
"status": int(response.status),
|
|
115
|
+
"requestId": response_headers.get("x-request-id"),
|
|
116
|
+
"body": parsed,
|
|
117
|
+
"headers": response_headers,
|
|
118
|
+
}
|
|
119
|
+
except error.HTTPError as http_error:
|
|
120
|
+
raw = http_error.read().decode("utf-8")
|
|
121
|
+
parsed: Any = {}
|
|
122
|
+
if raw:
|
|
123
|
+
try:
|
|
124
|
+
parsed = json.loads(raw)
|
|
125
|
+
except json.JSONDecodeError:
|
|
126
|
+
parsed = {"raw": raw}
|
|
127
|
+
response_headers = {str(k).lower(): str(v) for k, v in http_error.headers.items()}
|
|
128
|
+
raise SettldApiError(
|
|
129
|
+
status=int(http_error.code),
|
|
130
|
+
code=parsed.get("code") if isinstance(parsed, dict) else None,
|
|
131
|
+
message=parsed.get("error", f"request failed ({http_error.code})") if isinstance(parsed, dict) else f"request failed ({http_error.code})",
|
|
132
|
+
details=parsed.get("details") if isinstance(parsed, dict) else None,
|
|
133
|
+
request_id=response_headers.get("x-request-id"),
|
|
134
|
+
) from http_error
|
|
135
|
+
|
|
136
|
+
def register_agent(self, body: Dict[str, Any], **opts: Any) -> Dict[str, Any]:
|
|
137
|
+
if not isinstance(body, dict):
|
|
138
|
+
raise ValueError("body is required")
|
|
139
|
+
_assert_non_empty_string(body.get("publicKeyPem"), "body.publicKeyPem")
|
|
140
|
+
return self._request("POST", "/agents/register", body=body, **opts)
|
|
141
|
+
|
|
142
|
+
def credit_agent_wallet(self, agent_id: str, body: Dict[str, Any], **opts: Any) -> Dict[str, Any]:
|
|
143
|
+
_assert_non_empty_string(agent_id, "agent_id")
|
|
144
|
+
if not isinstance(body, dict):
|
|
145
|
+
raise ValueError("body is required")
|
|
146
|
+
return self._request("POST", f"/agents/{parse.quote(agent_id, safe='')}/wallet/credit", body=body, **opts)
|
|
147
|
+
|
|
148
|
+
def get_agent_wallet(self, agent_id: str, **opts: Any) -> Dict[str, Any]:
|
|
149
|
+
_assert_non_empty_string(agent_id, "agent_id")
|
|
150
|
+
return self._request("GET", f"/agents/{parse.quote(agent_id, safe='')}/wallet", **opts)
|
|
151
|
+
|
|
152
|
+
def create_agent_run(self, agent_id: str, body: Optional[Dict[str, Any]] = None, **opts: Any) -> Dict[str, Any]:
|
|
153
|
+
_assert_non_empty_string(agent_id, "agent_id")
|
|
154
|
+
run_body = {} if body is None else body
|
|
155
|
+
if not isinstance(run_body, dict):
|
|
156
|
+
raise ValueError("body must be an object")
|
|
157
|
+
return self._request("POST", f"/agents/{parse.quote(agent_id, safe='')}/runs", body=run_body, **opts)
|
|
158
|
+
|
|
159
|
+
def append_agent_run_event(
|
|
160
|
+
self,
|
|
161
|
+
agent_id: str,
|
|
162
|
+
run_id: str,
|
|
163
|
+
body: Dict[str, Any],
|
|
164
|
+
*,
|
|
165
|
+
expected_prev_chain_hash: str,
|
|
166
|
+
**opts: Any,
|
|
167
|
+
) -> Dict[str, Any]:
|
|
168
|
+
_assert_non_empty_string(agent_id, "agent_id")
|
|
169
|
+
_assert_non_empty_string(run_id, "run_id")
|
|
170
|
+
_assert_non_empty_string(expected_prev_chain_hash, "expected_prev_chain_hash")
|
|
171
|
+
if not isinstance(body, dict):
|
|
172
|
+
raise ValueError("body is required")
|
|
173
|
+
_assert_non_empty_string(body.get("type"), "body.type")
|
|
174
|
+
return self._request(
|
|
175
|
+
"POST",
|
|
176
|
+
f"/agents/{parse.quote(agent_id, safe='')}/runs/{parse.quote(run_id, safe='')}/events",
|
|
177
|
+
body=body,
|
|
178
|
+
expected_prev_chain_hash=expected_prev_chain_hash,
|
|
179
|
+
**opts,
|
|
180
|
+
)
|
|
181
|
+
|
|
182
|
+
def get_agent_run(self, agent_id: str, run_id: str, **opts: Any) -> Dict[str, Any]:
|
|
183
|
+
_assert_non_empty_string(agent_id, "agent_id")
|
|
184
|
+
_assert_non_empty_string(run_id, "run_id")
|
|
185
|
+
return self._request("GET", f"/agents/{parse.quote(agent_id, safe='')}/runs/{parse.quote(run_id, safe='')}", **opts)
|
|
186
|
+
|
|
187
|
+
def list_agent_run_events(self, agent_id: str, run_id: str, **opts: Any) -> Dict[str, Any]:
|
|
188
|
+
_assert_non_empty_string(agent_id, "agent_id")
|
|
189
|
+
_assert_non_empty_string(run_id, "run_id")
|
|
190
|
+
return self._request("GET", f"/agents/{parse.quote(agent_id, safe='')}/runs/{parse.quote(run_id, safe='')}/events", **opts)
|
|
191
|
+
|
|
192
|
+
def get_run_verification(self, run_id: str, **opts: Any) -> Dict[str, Any]:
|
|
193
|
+
_assert_non_empty_string(run_id, "run_id")
|
|
194
|
+
return self._request("GET", f"/runs/{parse.quote(run_id, safe='')}/verification", **opts)
|
|
195
|
+
|
|
196
|
+
def get_run_settlement(self, run_id: str, **opts: Any) -> Dict[str, Any]:
|
|
197
|
+
_assert_non_empty_string(run_id, "run_id")
|
|
198
|
+
return self._request("GET", f"/runs/{parse.quote(run_id, safe='')}/settlement", **opts)
|
|
199
|
+
|
|
200
|
+
def first_verified_run(
|
|
201
|
+
self,
|
|
202
|
+
params: Dict[str, Any],
|
|
203
|
+
*,
|
|
204
|
+
idempotency_prefix: Optional[str] = None,
|
|
205
|
+
request_id_prefix: Optional[str] = None,
|
|
206
|
+
timeout_seconds: Optional[float] = None,
|
|
207
|
+
) -> Dict[str, Any]:
|
|
208
|
+
if not isinstance(params, dict):
|
|
209
|
+
raise ValueError("params must be an object")
|
|
210
|
+
payee_agent = params.get("payee_agent")
|
|
211
|
+
if not isinstance(payee_agent, dict):
|
|
212
|
+
raise ValueError("params.payee_agent is required")
|
|
213
|
+
_assert_non_empty_string(payee_agent.get("publicKeyPem"), "params.payee_agent.publicKeyPem")
|
|
214
|
+
|
|
215
|
+
step_prefix = _normalize_prefix(
|
|
216
|
+
idempotency_prefix,
|
|
217
|
+
f"sdk_first_verified_run_{int(time.time() * 1000):x}_{random.randint(0, 0xFFFFFF):06x}",
|
|
218
|
+
)
|
|
219
|
+
request_prefix = _normalize_prefix(request_id_prefix, _random_request_id())
|
|
220
|
+
|
|
221
|
+
def make_step_opts(step: str, **extra: Any) -> Dict[str, Any]:
|
|
222
|
+
out = {
|
|
223
|
+
"request_id": f"{request_prefix}_{step}",
|
|
224
|
+
"idempotency_key": f"{step_prefix}_{step}",
|
|
225
|
+
"timeout_seconds": timeout_seconds,
|
|
226
|
+
}
|
|
227
|
+
out.update(extra)
|
|
228
|
+
return out
|
|
229
|
+
|
|
230
|
+
payee_registration = self.register_agent(payee_agent, **make_step_opts("register_payee"))
|
|
231
|
+
payee_agent_id = payee_registration.get("body", {}).get("agentIdentity", {}).get("agentId")
|
|
232
|
+
_assert_non_empty_string(payee_agent_id, "payee_agent_id")
|
|
233
|
+
|
|
234
|
+
payer_registration = None
|
|
235
|
+
payer_credit = None
|
|
236
|
+
payer_agent_id = None
|
|
237
|
+
payer_agent = params.get("payer_agent")
|
|
238
|
+
if payer_agent is not None:
|
|
239
|
+
if not isinstance(payer_agent, dict):
|
|
240
|
+
raise ValueError("params.payer_agent must be an object")
|
|
241
|
+
_assert_non_empty_string(payer_agent.get("publicKeyPem"), "params.payer_agent.publicKeyPem")
|
|
242
|
+
payer_registration = self.register_agent(payer_agent, **make_step_opts("register_payer"))
|
|
243
|
+
payer_agent_id = payer_registration.get("body", {}).get("agentIdentity", {}).get("agentId")
|
|
244
|
+
_assert_non_empty_string(payer_agent_id, "payer_agent_id")
|
|
245
|
+
|
|
246
|
+
settlement = params.get("settlement") if isinstance(params.get("settlement"), dict) else None
|
|
247
|
+
settlement_amount_cents = settlement.get("amountCents") if settlement else None
|
|
248
|
+
settlement_currency = settlement.get("currency", "USD") if settlement else "USD"
|
|
249
|
+
settlement_payer_agent_id = (
|
|
250
|
+
settlement.get("payerAgentId")
|
|
251
|
+
if settlement and isinstance(settlement.get("payerAgentId"), str)
|
|
252
|
+
else payer_agent_id
|
|
253
|
+
)
|
|
254
|
+
if settlement_amount_cents is not None and settlement_payer_agent_id is None:
|
|
255
|
+
raise ValueError("params.payer_agent or params.settlement.payerAgentId is required when settlement is requested")
|
|
256
|
+
|
|
257
|
+
payer_credit_input = params.get("payer_credit")
|
|
258
|
+
if payer_credit_input is not None:
|
|
259
|
+
if not isinstance(payer_credit_input, dict):
|
|
260
|
+
raise ValueError("params.payer_credit must be an object")
|
|
261
|
+
payer_credit_amount = payer_credit_input.get("amountCents")
|
|
262
|
+
if not isinstance(payer_credit_amount, (int, float)) or payer_credit_amount <= 0:
|
|
263
|
+
raise ValueError("params.payer_credit.amountCents must be a positive number")
|
|
264
|
+
if not payer_agent_id:
|
|
265
|
+
raise ValueError("params.payer_agent is required when params.payer_credit is provided")
|
|
266
|
+
payer_credit = self.credit_agent_wallet(
|
|
267
|
+
payer_agent_id,
|
|
268
|
+
{
|
|
269
|
+
"amountCents": int(payer_credit_amount),
|
|
270
|
+
"currency": payer_credit_input.get("currency", settlement_currency),
|
|
271
|
+
},
|
|
272
|
+
**make_step_opts("credit_payer_wallet"),
|
|
273
|
+
)
|
|
274
|
+
|
|
275
|
+
run_body = dict(params.get("run") or {})
|
|
276
|
+
if settlement_amount_cents is not None:
|
|
277
|
+
if not isinstance(settlement_amount_cents, (int, float)) or settlement_amount_cents <= 0:
|
|
278
|
+
raise ValueError("params.settlement.amountCents must be a positive number")
|
|
279
|
+
run_body["settlement"] = {
|
|
280
|
+
"payerAgentId": settlement_payer_agent_id,
|
|
281
|
+
"amountCents": int(settlement_amount_cents),
|
|
282
|
+
"currency": settlement_currency,
|
|
283
|
+
}
|
|
284
|
+
|
|
285
|
+
run_created = self.create_agent_run(payee_agent_id, run_body, **make_step_opts("create_run"))
|
|
286
|
+
run_id = run_created.get("body", {}).get("run", {}).get("runId")
|
|
287
|
+
_assert_non_empty_string(run_id, "run_id")
|
|
288
|
+
prev_chain_hash = run_created.get("body", {}).get("run", {}).get("lastChainHash")
|
|
289
|
+
_assert_non_empty_string(prev_chain_hash, "run_created.body.run.lastChainHash")
|
|
290
|
+
|
|
291
|
+
actor = params.get("actor") or {"type": "agent", "id": payee_agent_id}
|
|
292
|
+
started_payload = params.get("started_payload") or {"startedBy": "sdk.first_verified_run"}
|
|
293
|
+
run_started = self.append_agent_run_event(
|
|
294
|
+
payee_agent_id,
|
|
295
|
+
run_id,
|
|
296
|
+
{"type": "RUN_STARTED", "actor": actor, "payload": started_payload},
|
|
297
|
+
expected_prev_chain_hash=prev_chain_hash,
|
|
298
|
+
**make_step_opts("run_started"),
|
|
299
|
+
)
|
|
300
|
+
prev_chain_hash = run_started.get("body", {}).get("run", {}).get("lastChainHash")
|
|
301
|
+
_assert_non_empty_string(prev_chain_hash, "run_started.body.run.lastChainHash")
|
|
302
|
+
|
|
303
|
+
evidence_ref = params.get("evidence_ref") if isinstance(params.get("evidence_ref"), str) and params.get("evidence_ref").strip() else f"evidence://{run_id}/output.json"
|
|
304
|
+
evidence_payload = params.get("evidence_payload") if isinstance(params.get("evidence_payload"), dict) else {"evidenceRef": evidence_ref}
|
|
305
|
+
run_evidence_added = self.append_agent_run_event(
|
|
306
|
+
payee_agent_id,
|
|
307
|
+
run_id,
|
|
308
|
+
{"type": "EVIDENCE_ADDED", "actor": actor, "payload": evidence_payload},
|
|
309
|
+
expected_prev_chain_hash=prev_chain_hash,
|
|
310
|
+
**make_step_opts("evidence_added"),
|
|
311
|
+
)
|
|
312
|
+
prev_chain_hash = run_evidence_added.get("body", {}).get("run", {}).get("lastChainHash")
|
|
313
|
+
_assert_non_empty_string(prev_chain_hash, "run_evidence_added.body.run.lastChainHash")
|
|
314
|
+
|
|
315
|
+
completed_payload = dict(params.get("completed_payload") or {})
|
|
316
|
+
output_ref = params.get("output_ref") if isinstance(params.get("output_ref"), str) and params.get("output_ref").strip() else evidence_ref
|
|
317
|
+
completed_payload["outputRef"] = output_ref
|
|
318
|
+
if isinstance(params.get("completed_metrics"), dict):
|
|
319
|
+
completed_payload["metrics"] = params.get("completed_metrics")
|
|
320
|
+
run_completed = self.append_agent_run_event(
|
|
321
|
+
payee_agent_id,
|
|
322
|
+
run_id,
|
|
323
|
+
{"type": "RUN_COMPLETED", "actor": actor, "payload": completed_payload},
|
|
324
|
+
expected_prev_chain_hash=prev_chain_hash,
|
|
325
|
+
**make_step_opts("run_completed"),
|
|
326
|
+
)
|
|
327
|
+
|
|
328
|
+
run = self.get_agent_run(payee_agent_id, run_id, **make_step_opts("get_run"))
|
|
329
|
+
verification = self.get_run_verification(run_id, **make_step_opts("get_verification"))
|
|
330
|
+
settlement_out = None
|
|
331
|
+
if run_body.get("settlement") or run_created.get("body", {}).get("settlement") or run_completed.get("body", {}).get("settlement"):
|
|
332
|
+
settlement_out = self.get_run_settlement(run_id, **make_step_opts("get_settlement"))
|
|
333
|
+
|
|
334
|
+
return {
|
|
335
|
+
"ids": {"run_id": run_id, "payee_agent_id": payee_agent_id, "payer_agent_id": payer_agent_id},
|
|
336
|
+
"payee_registration": payee_registration,
|
|
337
|
+
"payer_registration": payer_registration,
|
|
338
|
+
"payer_credit": payer_credit,
|
|
339
|
+
"run_created": run_created,
|
|
340
|
+
"run_started": run_started,
|
|
341
|
+
"run_evidence_added": run_evidence_added,
|
|
342
|
+
"run_completed": run_completed,
|
|
343
|
+
"run": run,
|
|
344
|
+
"verification": verification,
|
|
345
|
+
"settlement": settlement_out,
|
|
346
|
+
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: settld-api-sdk-python
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: Settld API SDK (Python)
|
|
5
|
+
Author: Settld
|
|
6
|
+
License: UNLICENSED
|
|
7
|
+
Requires-Python: >=3.9
|
|
8
|
+
Description-Content-Type: text/markdown
|
|
9
|
+
|
|
10
|
+
# Settld API SDK (Python)
|
|
11
|
+
|
|
12
|
+
Python client for Settld API endpoints, including a high-level `first_verified_run` helper.
|
|
13
|
+
|
|
14
|
+
Quickstart docs live in `docs/QUICKSTART_SDK_PYTHON.md` at repo root.
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
README.md
|
|
2
|
+
pyproject.toml
|
|
3
|
+
settld_api_sdk/__init__.py
|
|
4
|
+
settld_api_sdk/client.py
|
|
5
|
+
settld_api_sdk_python.egg-info/PKG-INFO
|
|
6
|
+
settld_api_sdk_python.egg-info/SOURCES.txt
|
|
7
|
+
settld_api_sdk_python.egg-info/dependency_links.txt
|
|
8
|
+
settld_api_sdk_python.egg-info/top_level.txt
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
settld_api_sdk
|