reconify-python 2.0.0__py3-none-any.whl → 2.2.0__py3-none-any.whl

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.
reconify/__init__.py CHANGED
@@ -1,6 +1,6 @@
1
1
  """Typed clients for the Reconify Public API."""
2
2
 
3
- __version__ = "1.0.0"
3
+ __version__ = "2.2.0"
4
4
 
5
5
  from .client import AsyncReconify, Reconify
6
6
  from .errors import (
reconify/client.py CHANGED
@@ -17,11 +17,13 @@ from .resources import (
17
17
  AsyncIngestion,
18
18
  AsyncIssues,
19
19
  AsyncMetadata,
20
+ AsyncOnchain,
20
21
  AsyncOrganization,
21
22
  Events,
22
23
  Ingestion,
23
24
  Issues,
24
25
  Metadata,
26
+ Onchain,
25
27
  Organization,
26
28
  )
27
29
  from .transport import AsyncTransport, RetryConfig, SyncTransport
@@ -51,6 +53,7 @@ class Reconify:
51
53
  ingestion: Ingestion
52
54
  issues: Issues
53
55
  organization: Organization
56
+ onchain: Onchain
54
57
 
55
58
  def __init__(
56
59
  self,
@@ -108,6 +111,7 @@ class AsyncReconify:
108
111
  ingestion: AsyncIngestion
109
112
  issues: AsyncIssues
110
113
  organization: AsyncOrganization
114
+ onchain: AsyncOnchain
111
115
 
112
116
  def __init__(
113
117
  self,
reconify/models.py CHANGED
@@ -36,6 +36,7 @@ class Flow(TolerantStrEnum):
36
36
  PAYMENT_TO_ORDER = "payment_to_order"
37
37
  WALLET_TO_WALLET = "wallet_to_wallet"
38
38
  WALLET_TO_PAYOUT = "wallet_to_payout"
39
+ PROVIDER_TO_SETTLEMENT_ACCOUNT = "provider_to_settlement_account"
39
40
 
40
41
 
41
42
  class EventType(TolerantStrEnum):
@@ -49,6 +50,13 @@ class EventType(TolerantStrEnum):
49
50
  WALLET_CREDITED = "wallet.credited"
50
51
  WALLET_DEBITED = "wallet.debited"
51
52
  WALLET_REFUNDED = "wallet.refunded"
53
+ SETTLEMENT_ALLOCATIONS_RECORDED = "settlement.allocations_recorded"
54
+ SETTLEMENT_CREATED = "settlement.created"
55
+ SETTLEMENT_DISBURSED = "settlement.disbursed"
56
+ SETTLEMENT_FAILED = "settlement.failed"
57
+ SETTLEMENT_FINALIZED = "settlement.finalized"
58
+ SETTLEMENT_RECEIVED = "settlement.received"
59
+ SETTLEMENT_REVISED = "settlement.revised"
52
60
 
53
61
 
54
62
  class EntityType(TolerantStrEnum):
@@ -102,6 +110,44 @@ class MonitoringErrorCode(TolerantStrEnum):
102
110
  MALFORMED_REQUEST = "malformed_request"
103
111
 
104
112
 
113
+ class OnchainSourceKind(TolerantStrEnum):
114
+ PROVIDER_PAYMENT = "provider_payment"
115
+ TRANSACTION = "transaction"
116
+ ADDRESS_REFERENCE = "address_reference"
117
+
118
+
119
+ class OnchainNetwork(TolerantStrEnum):
120
+ ETHEREUM_MAINNET = "ethereum-mainnet"
121
+ ETHEREUM_SEPOLIA = "ethereum-sepolia"
122
+ SOLANA_MAINNET = "solana-mainnet"
123
+ SOLANA_DEVNET = "solana-devnet"
124
+
125
+
126
+ class OnchainSourceStatus(TolerantStrEnum):
127
+ QUEUED = "queued"
128
+
129
+
130
+ class FinancialComponentKind(TolerantStrEnum):
131
+ FEE = "fee"
132
+ COMMISSION = "commission"
133
+ TAX = "tax"
134
+ RESERVE = "reserve"
135
+ ADJUSTMENT = "adjustment"
136
+ OTHER = "other"
137
+
138
+
139
+ class FinancialComponentEffect(TolerantStrEnum):
140
+ ADD = "add"
141
+ DEDUCT = "deduct"
142
+ INCLUDED = "included"
143
+
144
+
145
+ class SettlementAllocationType(TolerantStrEnum):
146
+ PAYMENT = "payment"
147
+ REFUND = "refund"
148
+ CHARGEBACK = "chargeback"
149
+
150
+
105
151
  class APIInfo(ResponseModel):
106
152
  name: str
107
153
  version: str
@@ -113,6 +159,31 @@ class Health(ResponseModel):
113
159
  status: str
114
160
 
115
161
 
162
+ class FinancialComponent(RequestModel):
163
+ amount: str
164
+ kind: FinancialComponentKind
165
+ effect: FinancialComponentEffect
166
+ description: str | None = None
167
+ provider_type: str | None = None
168
+ reference: str | None = None
169
+ metadata: dict[str, str | int | float | bool] | None = None
170
+
171
+
172
+ class FinancialBreakdown(RequestModel):
173
+ gross: str
174
+ net: str
175
+ components: list[FinancialComponent] = Field(max_length=100)
176
+
177
+
178
+ class SettlementAllocation(RequestModel):
179
+ allocation_id: str
180
+ allocation_type: SettlementAllocationType
181
+ flow: str
182
+ reference: str
183
+ amount: str
184
+ event_id: str | None = None
185
+
186
+
116
187
  class MonitoringEventData(RequestModel):
117
188
  provider: str | None = None
118
189
  integration_ref: str | None = None
@@ -121,6 +192,8 @@ class MonitoringEventData(RequestModel):
121
192
  failure_code: str | None = None
122
193
  failure_message: str | None = None
123
194
  retryable: bool | None = None
195
+ revises_event_id: str | None = None
196
+ allocations: list[SettlementAllocation] | None = Field(default=None, max_length=500)
124
197
 
125
198
 
126
199
  class MonitoringEvent(RequestModel):
@@ -131,8 +204,11 @@ class MonitoringEvent(RequestModel):
131
204
  entity_id: str
132
205
  occurred_at: datetime | None = None
133
206
  amount: str | None = None
207
+ correlation_id: str | None = None
208
+ causation_id: str | None = None
134
209
  currency: str | None = None
135
210
  data: MonitoringEventData | None = None
211
+ financial_breakdown: FinancialBreakdown | None = None
136
212
  metadata: dict[str, str | int | float | bool] | None = None
137
213
 
138
214
 
@@ -171,8 +247,17 @@ class Event(ResponseModel):
171
247
  received_at: datetime
172
248
  amount: str | None = None
173
249
  currency: str | None = None
250
+ causation_id: str | None = None
251
+ correlation_id: str | None = None
252
+ revises_event_id: str | None = None
174
253
  provider: str | None = None
175
254
  status: ReceiptStatus
255
+ gross: str | None = None
256
+ net: str | None = None
257
+ component_count: int | None = None
258
+ allocation_count: int | None = None
259
+ financial_breakdown: FinancialBreakdown | None = None
260
+ allocations: list[SettlementAllocation] | None = None
176
261
 
177
262
 
178
263
  class ListEventsResponse(ResponseModel):
@@ -243,5 +328,31 @@ class Error(ResponseModel):
243
328
  detail: str | None = None
244
329
 
245
330
 
331
+ class OnchainSourceLocator(RequestModel):
332
+ integration_ref: str | None = None
333
+ network: OnchainNetwork | None = None
334
+ protocol_reference: str | None = None
335
+ provider_reference: str | None = None
336
+ provider_transaction_id: str | None = None
337
+ receiving_address: str | None = None
338
+ transaction_reference: str | None = None
339
+ window_end: datetime | None = None
340
+ window_start: datetime | None = None
341
+
342
+
343
+ class OnchainSourceRequest(RequestModel):
344
+ flow: str
345
+ operation_reference: str = Field(min_length=1, max_length=256)
346
+ source_event_id: str = Field(min_length=1, max_length=256)
347
+ kind: OnchainSourceKind
348
+ locator: OnchainSourceLocator
349
+
350
+
351
+ class OnchainSourceResponse(ResponseModel):
352
+ id: str
353
+ status: OnchainSourceStatus
354
+ duplicate: bool
355
+
356
+
246
357
  def model_dump(model: BaseModel) -> dict[str, Any]:
247
358
  return model.model_dump(mode="json", by_alias=True, exclude_none=True, exclude_unset=True)
@@ -4,6 +4,7 @@ from .events import AsyncEvents, Events
4
4
  from .ingestion import AsyncIngestion, Ingestion
5
5
  from .issues import AsyncIssues, Issues
6
6
  from .metadata import AsyncMetadata, Metadata
7
+ from .onchain import AsyncOnchain, Onchain
7
8
  from .organization import AsyncOrganization, Organization
8
9
 
9
10
  SYNC_RESOURCE_CLASSES = {
@@ -12,6 +13,7 @@ SYNC_RESOURCE_CLASSES = {
12
13
  "ingestion": Ingestion,
13
14
  "issues": Issues,
14
15
  "organization": Organization,
16
+ "onchain": Onchain,
15
17
  }
16
18
  ASYNC_RESOURCE_CLASSES = {
17
19
  "metadata": AsyncMetadata,
@@ -19,6 +21,7 @@ ASYNC_RESOURCE_CLASSES = {
19
21
  "ingestion": AsyncIngestion,
20
22
  "issues": AsyncIssues,
21
23
  "organization": AsyncOrganization,
24
+ "onchain": AsyncOnchain,
22
25
  }
23
26
 
24
27
  OPERATION_SPECS = {
@@ -35,6 +38,7 @@ OPERATION_SPECS = {
35
38
  "issues_add_note": ("issues", "POST", "/issues/{issue_id}/notes"),
36
39
  "organization_get": ("organization", "GET", "/organization"),
37
40
  "organization_list_members": ("organization", "GET", "/organization/members"),
41
+ "register-onchain-source": ("onchain", "POST", "/onchain-sources"),
38
42
  }
39
43
 
40
44
  OPERATION_METHODS = {
@@ -51,6 +55,7 @@ OPERATION_METHODS = {
51
55
  "issues_add_note": "add_issue_note",
52
56
  "organization_get": "get_organization",
53
57
  "organization_list_members": "list_organization_members",
58
+ "register-onchain-source": "register_onchain_source",
54
59
  }
55
60
 
56
61
  __all__ = [
@@ -59,11 +64,13 @@ __all__ = [
59
64
  "AsyncIssues",
60
65
  "AsyncMetadata",
61
66
  "AsyncOrganization",
67
+ "AsyncOnchain",
62
68
  "Events",
63
69
  "Ingestion",
64
70
  "Issues",
65
71
  "Metadata",
66
72
  "Organization",
73
+ "Onchain",
67
74
  "ASYNC_RESOURCE_CLASSES",
68
75
  "OPERATION_SPECS",
69
76
  "OPERATION_METHODS",
@@ -4,13 +4,16 @@ from __future__ import annotations
4
4
 
5
5
  from typing import Any
6
6
 
7
- from ..models import MonitoringBatchRequest, MonitoringBatchResponse
7
+ from ..models import MonitoringBatchRequest, MonitoringBatchResponse, MonitoringEvent
8
8
  from .base import AsyncResource, SyncResource
9
9
 
10
10
 
11
11
  class Ingestion(SyncResource):
12
12
  def ingest_monitoring_events(
13
- self, body: MonitoringBatchRequest, raw: bool = False, **query: Any
13
+ self,
14
+ body: MonitoringEvent | list[MonitoringEvent] | MonitoringBatchRequest,
15
+ raw: bool = False,
16
+ **query: Any,
14
17
  ) -> Any:
15
18
  return self._request(
16
19
  "POST",
@@ -24,7 +27,10 @@ class Ingestion(SyncResource):
24
27
 
25
28
  class AsyncIngestion(AsyncResource):
26
29
  async def ingest_monitoring_events(
27
- self, body: MonitoringBatchRequest, raw: bool = False, **query: Any
30
+ self,
31
+ body: MonitoringEvent | list[MonitoringEvent] | MonitoringBatchRequest,
32
+ raw: bool = False,
33
+ **query: Any,
28
34
  ) -> Any:
29
35
  return await self._request(
30
36
  "POST",
@@ -0,0 +1,57 @@
1
+ """On-chain evidence source registration resource client."""
2
+
3
+ from __future__ import annotations
4
+
5
+ from typing import Any
6
+
7
+ from ..errors import ReconifyValidationError
8
+ from ..models import OnchainSourceRequest, OnchainSourceResponse
9
+ from .base import AsyncResource, SyncResource
10
+
11
+
12
+ class Onchain(SyncResource):
13
+ def register_onchain_source(
14
+ self,
15
+ body: OnchainSourceRequest,
16
+ *,
17
+ idempotency_key: str,
18
+ raw: bool = False,
19
+ **query: Any,
20
+ ) -> Any:
21
+ if not idempotency_key or len(idempotency_key) > 200:
22
+ raise ReconifyValidationError("idempotency_key must be between 1 and 200 characters")
23
+ return self._request(
24
+ "POST",
25
+ "/onchain-sources",
26
+ params=query,
27
+ body=body,
28
+ response_model=OnchainSourceResponse,
29
+ raw=raw,
30
+ headers={"Idempotency-Key": idempotency_key},
31
+ )
32
+
33
+ register_source = register_onchain_source
34
+
35
+
36
+ class AsyncOnchain(AsyncResource):
37
+ async def register_onchain_source(
38
+ self,
39
+ body: OnchainSourceRequest,
40
+ *,
41
+ idempotency_key: str,
42
+ raw: bool = False,
43
+ **query: Any,
44
+ ) -> Any:
45
+ if not idempotency_key or len(idempotency_key) > 200:
46
+ raise ReconifyValidationError("idempotency_key must be between 1 and 200 characters")
47
+ return await self._request(
48
+ "POST",
49
+ "/onchain-sources",
50
+ params=query,
51
+ body=body,
52
+ response_model=OnchainSourceResponse,
53
+ raw=raw,
54
+ headers={"Idempotency-Key": idempotency_key},
55
+ )
56
+
57
+ register_source = register_onchain_source
reconify/transport.py CHANGED
@@ -88,6 +88,8 @@ def _validate_request_body(body: Any) -> Any:
88
88
  return model_dump(body)
89
89
  except ValidationError as exc:
90
90
  raise ReconifyValidationError(str(exc)) from exc
91
+ if isinstance(body, list):
92
+ return [_validate_request_body(item) for item in body]
91
93
  return body
92
94
 
93
95
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.5
2
2
  Name: reconify-python
3
- Version: 2.0.0
3
+ Version: 2.2.0
4
4
  Summary: Typed Python client for the Reconify Public API
5
5
  License: MIT
6
6
  License-File: LICENSE
@@ -41,8 +41,9 @@ staging or self-hosted endpoint, and URLs with or without `/v2` are accepted.
41
41
 
42
42
  ## Public resources
43
43
 
44
- The client exposes metadata, events, ingestion, issues, and organization. The
45
- current public contract contains exactly 13 operations. Python methods use
44
+ The client exposes metadata, events, ingestion, issues, organization, and
45
+ on-chain evidence registration. The current public contract contains exactly
46
+ 14 operations. Python methods use
46
47
  `snake_case` names and typed Pydantic v2 models from `reconify.models`.
47
48
 
48
49
  Sync and async clients provide cursor iterators:
@@ -81,6 +82,9 @@ Generated operation IDs use stable `resource_action` identifiers while the
81
82
  Python resource methods retain their snake_case names. See
82
83
  [UPGRADING.md](UPGRADING.md).
83
84
 
85
+ Version `2.2.0` adds settlement event fields, flexible ingestion payloads, and
86
+ on-chain evidence source registration. See [UPGRADING.md](UPGRADING.md).
87
+
84
88
  ## Build and release
85
89
 
86
90
  ```sh
@@ -0,0 +1,19 @@
1
+ reconify/__init__.py,sha256=jIlFYfoxffKjIh3p7xQ3yO0NridVpBDGqKuLv9MG1eA,878
2
+ reconify/client.py,sha256=nN9PssyQxQ1NnkDe1HGRouOyctMYYgaOMQjmecWXY_o,4859
3
+ reconify/errors.py,sha256=Dt9UVBSt34jL09AnYWRDKk0UEu70UpmDhQI_MyOzrkM,4185
4
+ reconify/models.py,sha256=vwt476o8S6uMFF1my4K8pyFflUXP4qqoR2ZkBiIlUbk,9281
5
+ reconify/pagination.py,sha256=pub9BQojyGVCfn5jIGJsP2JjCtONZF2LtmWnFg-Tpfw,3487
6
+ reconify/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
7
+ reconify/transport.py,sha256=lfwwXvrxtAkXVAxRyt7qm6bIsXVKJLXuXXI98R5tkzs,10762
8
+ reconify/resources/__init__.py,sha256=TRfdgO7cscWJZ1gl9gRL8DVdIO5ROP-pvcqpZEKJwUI,2585
9
+ reconify/resources/base.py,sha256=qHZm6LuIPJmLTKAjj221QaWuUi0aorIa8GWeWB4qtDs,3279
10
+ reconify/resources/events.py,sha256=Xf-udDFMHF2wPYUkK4HZcq10OTpEb5i831sG5RcP9VY,1858
11
+ reconify/resources/ingestion.py,sha256=5UeRCnXRBkSVBGkxc7y3DUG-NHsKGw85NEEo__tQIxc,1119
12
+ reconify/resources/issues.py,sha256=xljattrDPojWac8MGhk7fF3JAJoitwqAo6-OLABvNBo,3774
13
+ reconify/resources/metadata.py,sha256=lhCcERUaGtCbKc6d9I3U3iClNu9oHEhxnDeqUSkRri4,904
14
+ reconify/resources/onchain.py,sha256=GQZEPmqkBXNCYDF9a_apFK6cNl_tYbOBnSaQD1NTg9Q,1686
15
+ reconify/resources/organization.py,sha256=dQy8Ekd51ldep6IDP1_suz64GE1WX_7dhmQUhsvgsJ0,1295
16
+ reconify_python-2.2.0.dist-info/METADATA,sha256=N8ajFpGzQU9ISrsx45Qni1hzEwO5BXlCaCb9eKJzgWc,3220
17
+ reconify_python-2.2.0.dist-info/WHEEL,sha256=zOwg4jB6zX2kU910N-cMawjivD6tO8NEWvE12je1bVk,87
18
+ reconify_python-2.2.0.dist-info/licenses/LICENSE,sha256=q4Eqlx9sTPEY6DaOMuTjXAtVA7uEjxZkcvaJzcuYaIw,1065
19
+ reconify_python-2.2.0.dist-info/RECORD,,
@@ -1,18 +0,0 @@
1
- reconify/__init__.py,sha256=JN3srG4copTiM5yf6o8npvUSMYSgWysmzAPc75XBloQ,878
2
- reconify/client.py,sha256=HAqFxIbDSWHu5GNOJHENlI-gV28lNjwwOO6lrMzKrFI,4781
3
- reconify/errors.py,sha256=Dt9UVBSt34jL09AnYWRDKk0UEu70UpmDhQI_MyOzrkM,4185
4
- reconify/models.py,sha256=XInYd-wUbdW2eyXnRpqLuEKKeu57ZS_bm3_bphAf9T4,5965
5
- reconify/pagination.py,sha256=pub9BQojyGVCfn5jIGJsP2JjCtONZF2LtmWnFg-Tpfw,3487
6
- reconify/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
7
- reconify/transport.py,sha256=lU0nTvDqBhQw2YS1Y9Zusxxpagfdz87zOfaTrRrxcS4,10668
8
- reconify/resources/__init__.py,sha256=HXq7cpK7z074xpaBq_a63gQpCKN8OYQ8Sy45b2rYK7s,2324
9
- reconify/resources/base.py,sha256=qHZm6LuIPJmLTKAjj221QaWuUi0aorIa8GWeWB4qtDs,3279
10
- reconify/resources/events.py,sha256=Xf-udDFMHF2wPYUkK4HZcq10OTpEb5i831sG5RcP9VY,1858
11
- reconify/resources/ingestion.py,sha256=Azbfhq2yUb_CsCuedDRfs5U_0MSyzfrmrB1n3U2NJ6U,968
12
- reconify/resources/issues.py,sha256=xljattrDPojWac8MGhk7fF3JAJoitwqAo6-OLABvNBo,3774
13
- reconify/resources/metadata.py,sha256=lhCcERUaGtCbKc6d9I3U3iClNu9oHEhxnDeqUSkRri4,904
14
- reconify/resources/organization.py,sha256=dQy8Ekd51ldep6IDP1_suz64GE1WX_7dhmQUhsvgsJ0,1295
15
- reconify_python-2.0.0.dist-info/METADATA,sha256=kNn2bPH4L9esnRKuhXslDQyrBHjwUP2mVDw3ifLmqWw,3035
16
- reconify_python-2.0.0.dist-info/WHEEL,sha256=zOwg4jB6zX2kU910N-cMawjivD6tO8NEWvE12je1bVk,87
17
- reconify_python-2.0.0.dist-info/licenses/LICENSE,sha256=q4Eqlx9sTPEY6DaOMuTjXAtVA7uEjxZkcvaJzcuYaIw,1065
18
- reconify_python-2.0.0.dist-info/RECORD,,