reconify-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.
- reconify_python-0.1.0/.bumpversion.cfg +14 -0
- reconify_python-0.1.0/.github/workflows/ci.yml +22 -0
- reconify_python-0.1.0/.github/workflows/release.yml +21 -0
- reconify_python-0.1.0/.gitignore +9 -0
- reconify_python-0.1.0/CHANGELOG.md +8 -0
- reconify_python-0.1.0/LICENSE +21 -0
- reconify_python-0.1.0/PKG-INFO +125 -0
- reconify_python-0.1.0/README.md +107 -0
- reconify_python-0.1.0/pyproject.toml +51 -0
- reconify_python-0.1.0/reports/api-error-data-report.md +37 -0
- reconify_python-0.1.0/src/reconify/__init__.py +36 -0
- reconify_python-0.1.0/src/reconify/client.py +264 -0
- reconify_python-0.1.0/src/reconify/errors.py +132 -0
- reconify_python-0.1.0/src/reconify/models.py +1067 -0
- reconify_python-0.1.0/src/reconify/pagination.py +111 -0
- reconify_python-0.1.0/src/reconify/py.typed +0 -0
- reconify_python-0.1.0/src/reconify/resources/__init__.py +124 -0
- reconify_python-0.1.0/src/reconify/resources/alerts.py +58 -0
- reconify_python-0.1.0/src/reconify/resources/base.py +96 -0
- reconify_python-0.1.0/src/reconify/resources/events.py +79 -0
- reconify_python-0.1.0/src/reconify/resources/ingestion.py +94 -0
- reconify_python-0.1.0/src/reconify/resources/issues.py +207 -0
- reconify_python-0.1.0/src/reconify/resources/ledger.py +205 -0
- reconify_python-0.1.0/src/reconify/resources/reconciliations.py +236 -0
- reconify_python-0.1.0/src/reconify/resources/search.py +37 -0
- reconify_python-0.1.0/src/reconify/resources/setup.py +311 -0
- reconify_python-0.1.0/src/reconify/resources/transactions.py +58 -0
- reconify_python-0.1.0/src/reconify/resources/wallets.py +79 -0
- reconify_python-0.1.0/src/reconify/transport.py +299 -0
- reconify_python-0.1.0/tests/test_client.py +204 -0
- reconify_python-0.1.0/tests/test_openapi_coverage.py +88 -0
- reconify_python-0.1.0/tests/test_pagination.py +80 -0
- reconify_python-0.1.0/uv.lock +707 -0
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
[bumpversion]
|
|
2
|
+
current_version = 0.1.0
|
|
3
|
+
commit = True
|
|
4
|
+
tag = True
|
|
5
|
+
tag_name = v{new_version}
|
|
6
|
+
message = release: bump version {current_version} -> {new_version}
|
|
7
|
+
|
|
8
|
+
[bumpversion:file:pyproject.toml]
|
|
9
|
+
search = version = "{current_version}"
|
|
10
|
+
replace = version = "{new_version}"
|
|
11
|
+
|
|
12
|
+
[bumpversion:file:src/reconify/__init__.py]
|
|
13
|
+
search = __version__ = "{current_version}"
|
|
14
|
+
replace = __version__ = "{new_version}"
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
name: CI
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
pull_request:
|
|
6
|
+
|
|
7
|
+
jobs:
|
|
8
|
+
test:
|
|
9
|
+
runs-on: ubuntu-latest
|
|
10
|
+
steps:
|
|
11
|
+
- uses: actions/checkout@v4
|
|
12
|
+
- uses: actions/setup-python@v5
|
|
13
|
+
with:
|
|
14
|
+
python-version: "3.12"
|
|
15
|
+
- run: python -m pip install --upgrade pip
|
|
16
|
+
- run: pip install ".[dev]"
|
|
17
|
+
- run: ruff check .
|
|
18
|
+
- run: mypy src
|
|
19
|
+
- run: pytest -q
|
|
20
|
+
- run: python -m build
|
|
21
|
+
- run: python -m pip install --force-reinstall --no-deps dist/*.whl
|
|
22
|
+
- run: python -c "import reconify; print(reconify.Reconify.__name__)"
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
name: Release
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
release:
|
|
5
|
+
types: [published]
|
|
6
|
+
|
|
7
|
+
jobs:
|
|
8
|
+
publish:
|
|
9
|
+
runs-on: ubuntu-latest
|
|
10
|
+
environment: pypi
|
|
11
|
+
steps:
|
|
12
|
+
- uses: actions/checkout@v4
|
|
13
|
+
- uses: actions/setup-python@v5
|
|
14
|
+
with:
|
|
15
|
+
python-version: "3.12"
|
|
16
|
+
- run: python -m pip install --upgrade pip build
|
|
17
|
+
- run: python -m build
|
|
18
|
+
- name: Publish to PyPI
|
|
19
|
+
uses: pypa/gh-action-pypi-publish@release/v1
|
|
20
|
+
with:
|
|
21
|
+
password: ${{ secrets.PYPI_API_TOKEN }}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Reconify
|
|
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,125 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: reconify-python
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: Typed Python client for the Reconify Public API
|
|
5
|
+
License: MIT
|
|
6
|
+
License-File: LICENSE
|
|
7
|
+
Requires-Python: >=3.10
|
|
8
|
+
Requires-Dist: httpx<1,>=0.27
|
|
9
|
+
Requires-Dist: pydantic<3,>=2.7
|
|
10
|
+
Provides-Extra: dev
|
|
11
|
+
Requires-Dist: build>=1.2; extra == 'dev'
|
|
12
|
+
Requires-Dist: bump2version>=1.0; extra == 'dev'
|
|
13
|
+
Requires-Dist: mypy>=1.10; extra == 'dev'
|
|
14
|
+
Requires-Dist: pytest-asyncio>=0.23; extra == 'dev'
|
|
15
|
+
Requires-Dist: pytest>=8; extra == 'dev'
|
|
16
|
+
Requires-Dist: ruff>=0.5; extra == 'dev'
|
|
17
|
+
Description-Content-Type: text/markdown
|
|
18
|
+
|
|
19
|
+
# Reconify Python SDK
|
|
20
|
+
|
|
21
|
+
Typed synchronous and asynchronous clients for the Reconify Public API.
|
|
22
|
+
|
|
23
|
+
## Installation
|
|
24
|
+
|
|
25
|
+
```bash
|
|
26
|
+
pip install reconify-python
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
## Quickstart
|
|
30
|
+
|
|
31
|
+
```python
|
|
32
|
+
from reconify import Reconify
|
|
33
|
+
|
|
34
|
+
with Reconify(api_key="rk_...") as client:
|
|
35
|
+
sources = client.ledger.list_ledger_sources(limit=25)
|
|
36
|
+
for source in sources.sources or []:
|
|
37
|
+
print(source.id, source.name)
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
The key may also be supplied through `RECONIFY_API_KEY`. The default endpoint is
|
|
41
|
+
`https://api.reconifyhq.com/v1`; pass `base_url="https://staging.example/v1"`
|
|
42
|
+
for staging or self-hosted deployments. `/v1` is added when it is absent.
|
|
43
|
+
|
|
44
|
+
## Async usage and pagination
|
|
45
|
+
|
|
46
|
+
```python
|
|
47
|
+
from reconify import AsyncReconify
|
|
48
|
+
|
|
49
|
+
async with AsyncReconify() as client:
|
|
50
|
+
async for event in client.iter_events(limit=100):
|
|
51
|
+
print(event.id)
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
Cursor and offset iterators preserve opaque cursors and the server's page size.
|
|
55
|
+
When an endpoint accepts both cursor and offset pagination, `after` takes
|
|
56
|
+
precedence.
|
|
57
|
+
|
|
58
|
+
Every list operation also has a natural iterator on the client, for example
|
|
59
|
+
`client.iter_reconciliations(limit=100)` or
|
|
60
|
+
`client.iter_wallet_transactions(after="cursor")`. The async equivalent is
|
|
61
|
+
an async iterator. Iterators forward query parameters using keyword arguments,
|
|
62
|
+
so they never expose transport details.
|
|
63
|
+
|
|
64
|
+
## Errors and retries
|
|
65
|
+
|
|
66
|
+
HTTP failures raise typed `ReconifyError` subclasses. Every HTTP error exposes
|
|
67
|
+
`status_code`, `detail`, `code`, validation details, response headers, and the
|
|
68
|
+
response `request_id` without including credentials or request bodies.
|
|
69
|
+
|
|
70
|
+
429, 503, and transient HTTP transport failures such as timeouts are retried
|
|
71
|
+
for safe methods with bounded exponential backoff and jitter. Mutating methods
|
|
72
|
+
are not retried unless `RetryConfig(retry_unsafe_methods=True)` is supplied.
|
|
73
|
+
Transaction ingestion retries must reuse each row's `idempotencyKey`.
|
|
74
|
+
|
|
75
|
+
The client default timeout is 30 seconds. Individual operations can override
|
|
76
|
+
it with `timeout=...`, including an `httpx.Timeout` object. Async operations
|
|
77
|
+
also support normal `asyncio` cancellation, which is the Python equivalent of
|
|
78
|
+
context cancellation in other SDKs.
|
|
79
|
+
|
|
80
|
+
Use `raw=True` on any operation to receive status, headers, request ID, and raw
|
|
81
|
+
body through `RawResponse`.
|
|
82
|
+
|
|
83
|
+
## Test-session and ingestion headers
|
|
84
|
+
|
|
85
|
+
Integrity ingestion and test-session submission accept
|
|
86
|
+
`integrity_test_session=...`, which is sent as `X-Integrity-Test-Session`.
|
|
87
|
+
Integrity batches support 1–500 events and ledger transaction batches support
|
|
88
|
+
1–5000 transactions; the SDK does not truncate caller input.
|
|
89
|
+
|
|
90
|
+
The SDK intentionally excludes reconciliation adjustment, evidence, lifecycle,
|
|
91
|
+
report-item, and signoff operations. The retained reconciliation surface is
|
|
92
|
+
integrity sources, reconciliation list/create/get, and all schedule operations.
|
|
93
|
+
|
|
94
|
+
## API reference
|
|
95
|
+
|
|
96
|
+
The public operation methods are grouped by API module. Request bodies use the
|
|
97
|
+
typed Pydantic models exported from `reconify.models`; list query parameters use
|
|
98
|
+
the OpenAPI names in snake_case. Every operation accepts `raw=True` and a
|
|
99
|
+
per-request `timeout` override.
|
|
100
|
+
|
|
101
|
+
| Module | Methods |
|
|
102
|
+
| --- | --- |
|
|
103
|
+
| Alerts | `list_alert_rules`, `put_alert_rule` |
|
|
104
|
+
| Events | `list_events`, `get_event`, `reveal_event_field` |
|
|
105
|
+
| Ingestion | `ingest_integrity_events`, `ingest_integrity_test_events` |
|
|
106
|
+
| Issues | `list_issues`, `get_issue_summary`, `get_issue`, `update_issue`, `list_issue_deliveries`, `retry_issue_delivery`, `add_issue_note`, `resolve_issue` |
|
|
107
|
+
| Ledger | `list_ledger_sources`, `create_ledger_source`, `delete_ledger_source`, `get_ledger_source`, `update_ledger_source`, `list_source_periods`, `list_transactions`, `ingest_transactions` |
|
|
108
|
+
| Reconciliations | `list_integrity_sources_for_reconciliation`, `list_reconciliation_schedules`, `create_reconciliation_schedule`, `delete_reconciliation_schedule`, `get_reconciliation_schedule`, `update_reconciliation_schedule`, `list_reconciliations`, `create_reconciliation`, `get_reconciliation` |
|
|
109
|
+
| Search | `search_integrity_resources` |
|
|
110
|
+
| Setup | `list_setup_integrations`, `get_setup_integration`, `list_setup_sources`, `create_setup_source`, `get_setup_source`, `update_setup_source`, `disable_setup_source`, `create_test_session`, `get_test_session`, `get_test_session_result`, `retry_test_session`, `submit_test_session_events` |
|
|
111
|
+
| Transactions | `list_wallet_transactions`, `get_wallet_transaction` |
|
|
112
|
+
| Wallets | `list_wallets`, `get_wallet`, `get_wallet_balance` |
|
|
113
|
+
|
|
114
|
+
## Build and deploy
|
|
115
|
+
|
|
116
|
+
Build the distributable artifacts locally or in CI:
|
|
117
|
+
|
|
118
|
+
```bash
|
|
119
|
+
python -m pip install build
|
|
120
|
+
python -m build
|
|
121
|
+
```
|
|
122
|
+
|
|
123
|
+
The resulting wheel and source archive in `dist/` are ready for publication to
|
|
124
|
+
an internal or public Python package registry. CI builds both artifacts after
|
|
125
|
+
running lint, type checking, and tests.
|
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
# Reconify Python SDK
|
|
2
|
+
|
|
3
|
+
Typed synchronous and asynchronous clients for the Reconify Public API.
|
|
4
|
+
|
|
5
|
+
## Installation
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
pip install reconify-python
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
## Quickstart
|
|
12
|
+
|
|
13
|
+
```python
|
|
14
|
+
from reconify import Reconify
|
|
15
|
+
|
|
16
|
+
with Reconify(api_key="rk_...") as client:
|
|
17
|
+
sources = client.ledger.list_ledger_sources(limit=25)
|
|
18
|
+
for source in sources.sources or []:
|
|
19
|
+
print(source.id, source.name)
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
The key may also be supplied through `RECONIFY_API_KEY`. The default endpoint is
|
|
23
|
+
`https://api.reconifyhq.com/v1`; pass `base_url="https://staging.example/v1"`
|
|
24
|
+
for staging or self-hosted deployments. `/v1` is added when it is absent.
|
|
25
|
+
|
|
26
|
+
## Async usage and pagination
|
|
27
|
+
|
|
28
|
+
```python
|
|
29
|
+
from reconify import AsyncReconify
|
|
30
|
+
|
|
31
|
+
async with AsyncReconify() as client:
|
|
32
|
+
async for event in client.iter_events(limit=100):
|
|
33
|
+
print(event.id)
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
Cursor and offset iterators preserve opaque cursors and the server's page size.
|
|
37
|
+
When an endpoint accepts both cursor and offset pagination, `after` takes
|
|
38
|
+
precedence.
|
|
39
|
+
|
|
40
|
+
Every list operation also has a natural iterator on the client, for example
|
|
41
|
+
`client.iter_reconciliations(limit=100)` or
|
|
42
|
+
`client.iter_wallet_transactions(after="cursor")`. The async equivalent is
|
|
43
|
+
an async iterator. Iterators forward query parameters using keyword arguments,
|
|
44
|
+
so they never expose transport details.
|
|
45
|
+
|
|
46
|
+
## Errors and retries
|
|
47
|
+
|
|
48
|
+
HTTP failures raise typed `ReconifyError` subclasses. Every HTTP error exposes
|
|
49
|
+
`status_code`, `detail`, `code`, validation details, response headers, and the
|
|
50
|
+
response `request_id` without including credentials or request bodies.
|
|
51
|
+
|
|
52
|
+
429, 503, and transient HTTP transport failures such as timeouts are retried
|
|
53
|
+
for safe methods with bounded exponential backoff and jitter. Mutating methods
|
|
54
|
+
are not retried unless `RetryConfig(retry_unsafe_methods=True)` is supplied.
|
|
55
|
+
Transaction ingestion retries must reuse each row's `idempotencyKey`.
|
|
56
|
+
|
|
57
|
+
The client default timeout is 30 seconds. Individual operations can override
|
|
58
|
+
it with `timeout=...`, including an `httpx.Timeout` object. Async operations
|
|
59
|
+
also support normal `asyncio` cancellation, which is the Python equivalent of
|
|
60
|
+
context cancellation in other SDKs.
|
|
61
|
+
|
|
62
|
+
Use `raw=True` on any operation to receive status, headers, request ID, and raw
|
|
63
|
+
body through `RawResponse`.
|
|
64
|
+
|
|
65
|
+
## Test-session and ingestion headers
|
|
66
|
+
|
|
67
|
+
Integrity ingestion and test-session submission accept
|
|
68
|
+
`integrity_test_session=...`, which is sent as `X-Integrity-Test-Session`.
|
|
69
|
+
Integrity batches support 1–500 events and ledger transaction batches support
|
|
70
|
+
1–5000 transactions; the SDK does not truncate caller input.
|
|
71
|
+
|
|
72
|
+
The SDK intentionally excludes reconciliation adjustment, evidence, lifecycle,
|
|
73
|
+
report-item, and signoff operations. The retained reconciliation surface is
|
|
74
|
+
integrity sources, reconciliation list/create/get, and all schedule operations.
|
|
75
|
+
|
|
76
|
+
## API reference
|
|
77
|
+
|
|
78
|
+
The public operation methods are grouped by API module. Request bodies use the
|
|
79
|
+
typed Pydantic models exported from `reconify.models`; list query parameters use
|
|
80
|
+
the OpenAPI names in snake_case. Every operation accepts `raw=True` and a
|
|
81
|
+
per-request `timeout` override.
|
|
82
|
+
|
|
83
|
+
| Module | Methods |
|
|
84
|
+
| --- | --- |
|
|
85
|
+
| Alerts | `list_alert_rules`, `put_alert_rule` |
|
|
86
|
+
| Events | `list_events`, `get_event`, `reveal_event_field` |
|
|
87
|
+
| Ingestion | `ingest_integrity_events`, `ingest_integrity_test_events` |
|
|
88
|
+
| Issues | `list_issues`, `get_issue_summary`, `get_issue`, `update_issue`, `list_issue_deliveries`, `retry_issue_delivery`, `add_issue_note`, `resolve_issue` |
|
|
89
|
+
| Ledger | `list_ledger_sources`, `create_ledger_source`, `delete_ledger_source`, `get_ledger_source`, `update_ledger_source`, `list_source_periods`, `list_transactions`, `ingest_transactions` |
|
|
90
|
+
| Reconciliations | `list_integrity_sources_for_reconciliation`, `list_reconciliation_schedules`, `create_reconciliation_schedule`, `delete_reconciliation_schedule`, `get_reconciliation_schedule`, `update_reconciliation_schedule`, `list_reconciliations`, `create_reconciliation`, `get_reconciliation` |
|
|
91
|
+
| Search | `search_integrity_resources` |
|
|
92
|
+
| Setup | `list_setup_integrations`, `get_setup_integration`, `list_setup_sources`, `create_setup_source`, `get_setup_source`, `update_setup_source`, `disable_setup_source`, `create_test_session`, `get_test_session`, `get_test_session_result`, `retry_test_session`, `submit_test_session_events` |
|
|
93
|
+
| Transactions | `list_wallet_transactions`, `get_wallet_transaction` |
|
|
94
|
+
| Wallets | `list_wallets`, `get_wallet`, `get_wallet_balance` |
|
|
95
|
+
|
|
96
|
+
## Build and deploy
|
|
97
|
+
|
|
98
|
+
Build the distributable artifacts locally or in CI:
|
|
99
|
+
|
|
100
|
+
```bash
|
|
101
|
+
python -m pip install build
|
|
102
|
+
python -m build
|
|
103
|
+
```
|
|
104
|
+
|
|
105
|
+
The resulting wheel and source archive in `dist/` are ready for publication to
|
|
106
|
+
an internal or public Python package registry. CI builds both artifacts after
|
|
107
|
+
running lint, type checking, and tests.
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
[build-system]
|
|
2
|
+
requires = ["hatchling>=1.25"]
|
|
3
|
+
build-backend = "hatchling.build"
|
|
4
|
+
|
|
5
|
+
[project]
|
|
6
|
+
name = "reconify-python"
|
|
7
|
+
version = "0.1.0"
|
|
8
|
+
description = "Typed Python client for the Reconify Public API"
|
|
9
|
+
readme = "README.md"
|
|
10
|
+
requires-python = ">=3.10"
|
|
11
|
+
license = { text = "MIT" }
|
|
12
|
+
dependencies = [
|
|
13
|
+
"httpx>=0.27,<1",
|
|
14
|
+
"pydantic>=2.7,<3",
|
|
15
|
+
]
|
|
16
|
+
|
|
17
|
+
[project.optional-dependencies]
|
|
18
|
+
dev = [
|
|
19
|
+
"build>=1.2",
|
|
20
|
+
"bump2version>=1.0",
|
|
21
|
+
"mypy>=1.10",
|
|
22
|
+
"pytest>=8",
|
|
23
|
+
"pytest-asyncio>=0.23",
|
|
24
|
+
"ruff>=0.5",
|
|
25
|
+
]
|
|
26
|
+
|
|
27
|
+
[tool.hatch.build.targets.wheel]
|
|
28
|
+
packages = ["src/reconify"]
|
|
29
|
+
|
|
30
|
+
[tool.pytest.ini_options]
|
|
31
|
+
asyncio_mode = "auto"
|
|
32
|
+
testpaths = ["tests"]
|
|
33
|
+
pythonpath = ["src"]
|
|
34
|
+
|
|
35
|
+
[tool.ruff]
|
|
36
|
+
line-length = 100
|
|
37
|
+
target-version = "py310"
|
|
38
|
+
|
|
39
|
+
[tool.ruff.lint]
|
|
40
|
+
select = ["E", "F", "I", "UP"]
|
|
41
|
+
|
|
42
|
+
[tool.mypy]
|
|
43
|
+
python_version = "3.10"
|
|
44
|
+
strict = true
|
|
45
|
+
plugins = ["pydantic.mypy"]
|
|
46
|
+
|
|
47
|
+
[tool.pydantic-mypy]
|
|
48
|
+
init_forbid_extra = true
|
|
49
|
+
init_typed = true
|
|
50
|
+
warn_required_dynamic_aliases = true
|
|
51
|
+
warn_untyped_fields = true
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
# Local API Error-Data Report
|
|
2
|
+
|
|
3
|
+
Date: 2026-07-21
|
|
4
|
+
Environment: local Docker stack at `http://localhost:3002/v1`
|
|
5
|
+
Client: Reconify Python SDK
|
|
6
|
+
|
|
7
|
+
## Results
|
|
8
|
+
|
|
9
|
+
- A mixed ledger batch with one valid `status: "failed"` row and one invalid
|
|
10
|
+
date returned HTTP 200 with `ingested: 1` and one per-row error. The failed
|
|
11
|
+
row was persisted and returned by the failed-transaction filter.
|
|
12
|
+
- Replaying the valid row with the same `idempotencyKey` returned
|
|
13
|
+
`duplicates: 1`, confirming idempotent ingestion.
|
|
14
|
+
- An integrity event missing the required `eventType` returned HTTP 422 and
|
|
15
|
+
was surfaced as `ReconifyRequestError` with the server request ID.
|
|
16
|
+
- An alert rule using a valid-but-unknown UUID `controlId` returned HTTP 404
|
|
17
|
+
(`control not found`), as expected.
|
|
18
|
+
|
|
19
|
+
## API issue found
|
|
20
|
+
|
|
21
|
+
An alert rule using a syntactically invalid `controlId` such as
|
|
22
|
+
`missing-control-format` returned HTTP 500 with `internal_error` instead of a
|
|
23
|
+
client validation error. The public OpenAPI schema currently describes
|
|
24
|
+
`controlId` as an unconstrained string, while the database query casts it to a
|
|
25
|
+
UUID.
|
|
26
|
+
|
|
27
|
+
Recommended API fix: validate `controlId` as a UUID before persistence and
|
|
28
|
+
return HTTP 400 for malformed values. Keep HTTP 404 for syntactically valid
|
|
29
|
+
UUIDs that do not identify a control in the organization.
|
|
30
|
+
|
|
31
|
+
## Alert and issue state
|
|
32
|
+
|
|
33
|
+
The clean local tenant had no seeded integrity controls, so no alert rule could
|
|
34
|
+
be created and no alert or issue was generated by this scenario. The failed
|
|
35
|
+
ledger transaction path is independent of integrity-control setup and worked
|
|
36
|
+
as documented.
|
|
37
|
+
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
"""Typed clients for the Reconify Public API."""
|
|
2
|
+
|
|
3
|
+
__version__ = "0.1.0"
|
|
4
|
+
|
|
5
|
+
from .client import AsyncReconify, Reconify
|
|
6
|
+
from .errors import (
|
|
7
|
+
ReconifyAuthenticationError,
|
|
8
|
+
ReconifyConflictError,
|
|
9
|
+
ReconifyError,
|
|
10
|
+
ReconifyNotFoundError,
|
|
11
|
+
ReconifyPermissionError,
|
|
12
|
+
ReconifyRateLimitError,
|
|
13
|
+
ReconifyRequestError,
|
|
14
|
+
ReconifyServerError,
|
|
15
|
+
ReconifyServiceUnavailableError,
|
|
16
|
+
ReconifyValidationError,
|
|
17
|
+
)
|
|
18
|
+
from .transport import RawResponse, RetryConfig
|
|
19
|
+
|
|
20
|
+
__all__ = [
|
|
21
|
+
"AsyncReconify",
|
|
22
|
+
"Reconify",
|
|
23
|
+
"__version__",
|
|
24
|
+
"RawResponse",
|
|
25
|
+
"RetryConfig",
|
|
26
|
+
"ReconifyError",
|
|
27
|
+
"ReconifyValidationError",
|
|
28
|
+
"ReconifyAuthenticationError",
|
|
29
|
+
"ReconifyPermissionError",
|
|
30
|
+
"ReconifyNotFoundError",
|
|
31
|
+
"ReconifyConflictError",
|
|
32
|
+
"ReconifyRequestError",
|
|
33
|
+
"ReconifyRateLimitError",
|
|
34
|
+
"ReconifyServiceUnavailableError",
|
|
35
|
+
"ReconifyServerError",
|
|
36
|
+
]
|