validpay 0.1.0__tar.gz → 1.0.1__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,46 @@
1
+ # Changelog
2
+
3
+ All notable changes to the ValidPay Python SDK will be documented in this file.
4
+
5
+ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
6
+ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
7
+
8
+ ## [1.0.1] - 2026-06-08
9
+
10
+ ### Changed
11
+
12
+ - `DEFAULT_BASE_URL` is now `https://api.validpay.com` (Prompt 086B —
13
+ primary domain migrated from validpay.io). The legacy host keeps
14
+ working via Cloudflare 301 redirects, so 1.0.0 installs are
15
+ unaffected; new installs default to `.com`. The `base_url` constructor
16
+ argument continues to override.
17
+ - README + `pyproject.toml` URLs (Homepage, Documentation) now point at
18
+ `validpay.com`.
19
+
20
+ ## [1.0.0] - 2026-05-03
21
+
22
+ ### Added
23
+
24
+ - **Core client** (`ValidPayClient`) — create, verify, revoke, and reinstate
25
+ document intents via the ValidPay API.
26
+ - **AES-256-GCM encryption** — client-side encryption/decryption with
27
+ commitment hash verification (Patent B).
28
+ - **Split-key verification** (Patent C) — XOR key splitting into Share A
29
+ (document) and Share B (server). Neither alone decrypts.
30
+ - **Time-locked verification** (Patent D) — optional `valid_from` /
31
+ `valid_until` windows with client-side enforcement.
32
+ - **Selective field disclosure** (Patent E) — per-field encryption with
33
+ role-based disclosure policies.
34
+ - **Physical medium binding** (Patent F) — perceptual hashing and binding
35
+ zone comparison for document-to-physical matching.
36
+ Requires optional `binding` extra (`pip install validpay[binding]`).
37
+ - **Chain-of-custody tracking** (Patent G) — verification event audit log
38
+ via the API.
39
+ - **Blind revocation** (Patent H) — revoke/reinstate intents without
40
+ decrypting the payload.
41
+ - **Offline verification** (`OfflineCache`) — encrypted local cache for
42
+ offline verification with staleness tracking and revocation sync.
43
+ - **Batch intent creation** — create up to 100 intents in a single API call.
44
+ - **115 automated tests** across 4 test modules.
45
+
46
+ [1.0.0]: https://github.com/ValidPay-io/validpay-python-sdk/releases/tag/v1.0.0
@@ -1,6 +1,6 @@
1
1
  MIT License
2
2
 
3
- Copyright (c) 2026 MiLu Technologies LLC
3
+ Copyright (c) 2026 ValidPay
4
4
 
5
5
  Permission is hereby granted, free of charge, to any person obtaining a copy
6
6
  of this software and associated documentation files (the "Software"), to deal
@@ -0,0 +1,7 @@
1
+ include LICENSE
2
+ include README.md
3
+ include CHANGELOG.md
4
+ recursive-include validpay *.py
5
+ prune tests
6
+ prune check21
7
+ prune .github
@@ -0,0 +1,260 @@
1
+ Metadata-Version: 2.4
2
+ Name: validpay
3
+ Version: 1.0.1
4
+ Summary: Official ValidPay Python SDK — client-side AES-256-GCM encryption + ValidPay API client
5
+ Author-email: ValidPay <dev@validpay.com>
6
+ License: MIT License
7
+
8
+ Copyright (c) 2026 ValidPay
9
+
10
+ Permission is hereby granted, free of charge, to any person obtaining a copy
11
+ of this software and associated documentation files (the "Software"), to deal
12
+ in the Software without restriction, including without limitation the rights
13
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
14
+ copies of the Software, and to permit persons to whom the Software is
15
+ furnished to do so, subject to the following conditions:
16
+
17
+ The above copyright notice and this permission notice shall be included in all
18
+ copies or substantial portions of the Software.
19
+
20
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
21
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
22
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
23
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
24
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
25
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
26
+ SOFTWARE.
27
+
28
+ Project-URL: Homepage, https://validpay.com
29
+ Project-URL: Documentation, https://validpay.com/docs/api
30
+ Project-URL: Repository, https://github.com/ValidPay-io/validpay-python-sdk
31
+ Project-URL: Issues, https://github.com/ValidPay-io/validpay-python-sdk/issues
32
+ Project-URL: Changelog, https://github.com/ValidPay-io/validpay-python-sdk/blob/main/CHANGELOG.md
33
+ Keywords: validpay,encryption,aes-256-gcm,document-verification,blind-escrow
34
+ Classifier: Development Status :: 5 - Production/Stable
35
+ Classifier: Intended Audience :: Developers
36
+ Classifier: License :: OSI Approved :: MIT License
37
+ Classifier: Operating System :: OS Independent
38
+ Classifier: Programming Language :: Python :: 3
39
+ Classifier: Programming Language :: Python :: 3.9
40
+ Classifier: Programming Language :: Python :: 3.10
41
+ Classifier: Programming Language :: Python :: 3.11
42
+ Classifier: Programming Language :: Python :: 3.12
43
+ Classifier: Topic :: Security :: Cryptography
44
+ Requires-Python: >=3.9
45
+ Description-Content-Type: text/markdown
46
+ License-File: LICENSE
47
+ Requires-Dist: cryptography>=41.0
48
+ Requires-Dist: requests>=2.28
49
+ Provides-Extra: dev
50
+ Requires-Dist: pytest>=7.0; extra == "dev"
51
+ Provides-Extra: binding
52
+ Requires-Dist: Pillow>=10.0; extra == "binding"
53
+ Requires-Dist: numpy>=1.24; extra == "binding"
54
+ Requires-Dist: scipy>=1.10; extra == "binding"
55
+ Dynamic: license-file
56
+
57
+ # ValidPay Python SDK
58
+
59
+ Official Python SDK for the [ValidPay](https://validpay.com) document
60
+ verification API. Provides client-side AES-256-GCM encryption and a thin
61
+ client around the ValidPay HTTP API.
62
+
63
+ The encryption format is wire-compatible with the
64
+ [Node.js SDK](https://github.com/ValidPay-io/validpay-node-sdk): a payload
65
+ encrypted by the Python SDK can be decrypted by the Node SDK and vice
66
+ versa.
67
+
68
+ ## Install
69
+
70
+ ```bash
71
+ pip install validpay
72
+ ```
73
+
74
+ For physical-binding support (Patent F — image-based binding zones), install
75
+ the optional extras:
76
+
77
+ ```bash
78
+ pip install validpay[binding]
79
+ ```
80
+
81
+ Requires Python 3.9+.
82
+
83
+ ## Quick start
84
+
85
+ ```python
86
+ from validpay import ValidPayClient
87
+
88
+ client = ValidPayClient(api_key="vp_live_xxx")
89
+
90
+ # Create a single intent — the payload is encrypted locally before
91
+ # anything leaves your process. Only the ciphertext is sent to ValidPay.
92
+ result = client.create_intent(
93
+ document_type="check",
94
+ payload={"payee": "John Doe", "amount": 1500.00, "check_number": "10042"},
95
+ )
96
+ print(result.retrieval_id) # vp_abc123def456
97
+ print(result.key) # base64 AES-256 key — deliver out-of-band
98
+
99
+ # Create up to 100 intents in one round trip.
100
+ results = client.create_intent_batch([
101
+ {"document_type": "check", "payload": {"payee": "Alice", "amount": 500}},
102
+ {"document_type": "check", "payload": {"payee": "Bob", "amount": 750}},
103
+ ])
104
+ for r in results:
105
+ print(r.retrieval_id, r.key)
106
+
107
+ # Verify (retrieve + decrypt). No API key required for this endpoint.
108
+ verification = client.verify_intent(
109
+ retrieval_id="vp_abc123def456",
110
+ key=result.key,
111
+ )
112
+ print(verification.payload) # decrypted dict
113
+ print(verification.issuer) # "Acme Corp"
114
+ print(verification.issuer_verified) # True
115
+ print(verification.status) # "active"
116
+ ```
117
+
118
+ ### Time-Locked Verification (Patent D)
119
+
120
+ Restrict when a document can be verified by specifying a validity window:
121
+
122
+ ```python
123
+ from datetime import datetime, timezone, timedelta
124
+
125
+ result = client.create_intent(
126
+ document_type="check",
127
+ payload={"payee": "Jane Doe", "amount": 1500.00},
128
+ valid_from=(datetime.now(timezone.utc) + timedelta(hours=1)).isoformat(),
129
+ valid_until=(datetime.now(timezone.utc) + timedelta(days=30)).isoformat(),
130
+ )
131
+
132
+ # Later, when verifying:
133
+ verified = client.verify_intent(result.retrieval_id, result.key)
134
+ print(verified.time_lock_status) # "valid", "not_yet_valid", or "expired"
135
+ print(verified.valid_from) # ISO-8601 timestamp or None
136
+ print(verified.valid_until) # ISO-8601 timestamp or None
137
+ ```
138
+
139
+ Time-lock status is informational — the SDK always returns the decrypted
140
+ payload regardless of the time window. Your application decides how to
141
+ handle `not_yet_valid` or `expired` results. The server stores the
142
+ timestamps but never enforces them; this preserves the blind intermediary
143
+ model (the server never decides whether a document is "still good").
144
+
145
+ The same `valid_from` / `valid_until` keyword arguments are accepted by
146
+ `create_intent_batch` (per-item), `create_split_key_intent`, and
147
+ `create_selective_intent`.
148
+
149
+ ### Split-key intents (Patent C)
150
+
151
+ Splits the AES key into two XOR shares: Share A is returned to the caller
152
+ (typically embedded in the QR code), Share B is stored server-side. Neither
153
+ share alone can decrypt the payload.
154
+
155
+ ```python
156
+ result = client.create_split_key_intent(
157
+ document_type="ssn_card",
158
+ payload={"ssn": "123-45-6789"},
159
+ )
160
+ # result.key is Share A — pair it with Share B at verification time.
161
+
162
+ verified = client.verify_split_key_intent(result.retrieval_id, result.key)
163
+ print(verified.payload)
164
+ ```
165
+
166
+ ### Selective disclosure (Patent E)
167
+
168
+ Each field is encrypted with its own per-field key. A disclosure policy maps
169
+ role names to the fields that role may decrypt. A `full` role with access to
170
+ every field is added automatically.
171
+
172
+ ```python
173
+ result = client.create_selective_intent(
174
+ document_type="check",
175
+ payload={"payee": "Alice", "amount": 1500.00, "memo": "rent"},
176
+ disclosure_policy={"bank": ["amount"], "auditor": ["amount", "payee"]},
177
+ )
178
+
179
+ # Bank sees only 'amount'; other fields come back as REDACTED markers.
180
+ verified = client.verify_selective_intent(result.retrieval_id, result.key, role="bank")
181
+ print(verified.payload)
182
+ ```
183
+
184
+ `create_selective_intent` accepts `split_key=True` to combine Patents C + E.
185
+
186
+ ### Revocation (Patent H — Blind Revocation)
187
+
188
+ Issuers can revoke or reinstate an intent without decrypting it. Verifiers
189
+ of a revoked intent receive `status="revoked"` and no encrypted payload.
190
+
191
+ ```python
192
+ client.revoke_intent("vp_abc123def456", reason="Stop payment")
193
+ client.reinstate_intent("vp_abc123def456", reason="False alarm")
194
+
195
+ history = client.get_revocation_history("vp_abc123def456")
196
+ for event in history:
197
+ print(event["action"], event["reason"], event["performed_at"])
198
+ ```
199
+
200
+ ## API
201
+
202
+ ### `ValidPayClient(api_key, *, base_url=..., timeout=30.0, session=None)`
203
+
204
+ - `api_key` — your ValidPay API key (required for create endpoints).
205
+ - `base_url` — defaults to `https://api.validpay.com`.
206
+ - `timeout` — per-request timeout in seconds.
207
+ - `session` — optionally provide a `requests.Session` for connection
208
+ pooling, custom adapters, or mocking in tests.
209
+
210
+ ### `client.create_intent(document_type, payload) -> CreateIntentResult`
211
+
212
+ Encrypts `payload` (any JSON-serializable value) under a freshly
213
+ generated AES-256 key and registers it with ValidPay. Returns the
214
+ retrieval id and the key. **The key is never sent to ValidPay** — you
215
+ must hand it off out-of-band to whoever needs to verify the intent.
216
+
217
+ ### `client.create_intent_batch(intents) -> list[CreateIntentResult]`
218
+
219
+ Bulk version. `intents` is an iterable of mappings shaped
220
+ `{"document_type": str, "payload": Any}`, with 1–100 items. Each intent
221
+ gets its own unique key. Result order matches input order.
222
+
223
+ ### `client.verify_intent(retrieval_id, key) -> VerifyIntentResult`
224
+
225
+ Fetches the intent (public endpoint, no API key required), decrypts the
226
+ payload locally, and returns issuer metadata + the decrypted payload.
227
+
228
+ ### Errors
229
+
230
+ All SDK and API errors are raised as `ValidPayError`, which exposes:
231
+
232
+ - `code` — machine-readable code (e.g. `"unauthorized"`, `"not_found"`,
233
+ `"decryption_failed"`, `"invalid_key"`, `"network_error"`).
234
+ - `status` — HTTP status when the error came from the API.
235
+ - `details` — raw error body / extra context when available.
236
+
237
+ ### Low-level crypto
238
+
239
+ For advanced use cases the encryption primitives are exported directly:
240
+
241
+ ```python
242
+ from validpay import generate_key, encrypt, decrypt
243
+
244
+ key = generate_key()
245
+ blob = encrypt('{"hello": "world"}', key)
246
+ assert decrypt(blob, key) == '{"hello": "world"}'
247
+ ```
248
+
249
+ Wire format: `base64(iv[12] || authTag[16] || ciphertext)`.
250
+
251
+ ## Development
252
+
253
+ ```bash
254
+ pip install -e ".[dev]"
255
+ pytest
256
+ ```
257
+
258
+ ## License
259
+
260
+ MIT — see `LICENSE`.
@@ -0,0 +1,204 @@
1
+ # ValidPay Python SDK
2
+
3
+ Official Python SDK for the [ValidPay](https://validpay.com) document
4
+ verification API. Provides client-side AES-256-GCM encryption and a thin
5
+ client around the ValidPay HTTP API.
6
+
7
+ The encryption format is wire-compatible with the
8
+ [Node.js SDK](https://github.com/ValidPay-io/validpay-node-sdk): a payload
9
+ encrypted by the Python SDK can be decrypted by the Node SDK and vice
10
+ versa.
11
+
12
+ ## Install
13
+
14
+ ```bash
15
+ pip install validpay
16
+ ```
17
+
18
+ For physical-binding support (Patent F — image-based binding zones), install
19
+ the optional extras:
20
+
21
+ ```bash
22
+ pip install validpay[binding]
23
+ ```
24
+
25
+ Requires Python 3.9+.
26
+
27
+ ## Quick start
28
+
29
+ ```python
30
+ from validpay import ValidPayClient
31
+
32
+ client = ValidPayClient(api_key="vp_live_xxx")
33
+
34
+ # Create a single intent — the payload is encrypted locally before
35
+ # anything leaves your process. Only the ciphertext is sent to ValidPay.
36
+ result = client.create_intent(
37
+ document_type="check",
38
+ payload={"payee": "John Doe", "amount": 1500.00, "check_number": "10042"},
39
+ )
40
+ print(result.retrieval_id) # vp_abc123def456
41
+ print(result.key) # base64 AES-256 key — deliver out-of-band
42
+
43
+ # Create up to 100 intents in one round trip.
44
+ results = client.create_intent_batch([
45
+ {"document_type": "check", "payload": {"payee": "Alice", "amount": 500}},
46
+ {"document_type": "check", "payload": {"payee": "Bob", "amount": 750}},
47
+ ])
48
+ for r in results:
49
+ print(r.retrieval_id, r.key)
50
+
51
+ # Verify (retrieve + decrypt). No API key required for this endpoint.
52
+ verification = client.verify_intent(
53
+ retrieval_id="vp_abc123def456",
54
+ key=result.key,
55
+ )
56
+ print(verification.payload) # decrypted dict
57
+ print(verification.issuer) # "Acme Corp"
58
+ print(verification.issuer_verified) # True
59
+ print(verification.status) # "active"
60
+ ```
61
+
62
+ ### Time-Locked Verification (Patent D)
63
+
64
+ Restrict when a document can be verified by specifying a validity window:
65
+
66
+ ```python
67
+ from datetime import datetime, timezone, timedelta
68
+
69
+ result = client.create_intent(
70
+ document_type="check",
71
+ payload={"payee": "Jane Doe", "amount": 1500.00},
72
+ valid_from=(datetime.now(timezone.utc) + timedelta(hours=1)).isoformat(),
73
+ valid_until=(datetime.now(timezone.utc) + timedelta(days=30)).isoformat(),
74
+ )
75
+
76
+ # Later, when verifying:
77
+ verified = client.verify_intent(result.retrieval_id, result.key)
78
+ print(verified.time_lock_status) # "valid", "not_yet_valid", or "expired"
79
+ print(verified.valid_from) # ISO-8601 timestamp or None
80
+ print(verified.valid_until) # ISO-8601 timestamp or None
81
+ ```
82
+
83
+ Time-lock status is informational — the SDK always returns the decrypted
84
+ payload regardless of the time window. Your application decides how to
85
+ handle `not_yet_valid` or `expired` results. The server stores the
86
+ timestamps but never enforces them; this preserves the blind intermediary
87
+ model (the server never decides whether a document is "still good").
88
+
89
+ The same `valid_from` / `valid_until` keyword arguments are accepted by
90
+ `create_intent_batch` (per-item), `create_split_key_intent`, and
91
+ `create_selective_intent`.
92
+
93
+ ### Split-key intents (Patent C)
94
+
95
+ Splits the AES key into two XOR shares: Share A is returned to the caller
96
+ (typically embedded in the QR code), Share B is stored server-side. Neither
97
+ share alone can decrypt the payload.
98
+
99
+ ```python
100
+ result = client.create_split_key_intent(
101
+ document_type="ssn_card",
102
+ payload={"ssn": "123-45-6789"},
103
+ )
104
+ # result.key is Share A — pair it with Share B at verification time.
105
+
106
+ verified = client.verify_split_key_intent(result.retrieval_id, result.key)
107
+ print(verified.payload)
108
+ ```
109
+
110
+ ### Selective disclosure (Patent E)
111
+
112
+ Each field is encrypted with its own per-field key. A disclosure policy maps
113
+ role names to the fields that role may decrypt. A `full` role with access to
114
+ every field is added automatically.
115
+
116
+ ```python
117
+ result = client.create_selective_intent(
118
+ document_type="check",
119
+ payload={"payee": "Alice", "amount": 1500.00, "memo": "rent"},
120
+ disclosure_policy={"bank": ["amount"], "auditor": ["amount", "payee"]},
121
+ )
122
+
123
+ # Bank sees only 'amount'; other fields come back as REDACTED markers.
124
+ verified = client.verify_selective_intent(result.retrieval_id, result.key, role="bank")
125
+ print(verified.payload)
126
+ ```
127
+
128
+ `create_selective_intent` accepts `split_key=True` to combine Patents C + E.
129
+
130
+ ### Revocation (Patent H — Blind Revocation)
131
+
132
+ Issuers can revoke or reinstate an intent without decrypting it. Verifiers
133
+ of a revoked intent receive `status="revoked"` and no encrypted payload.
134
+
135
+ ```python
136
+ client.revoke_intent("vp_abc123def456", reason="Stop payment")
137
+ client.reinstate_intent("vp_abc123def456", reason="False alarm")
138
+
139
+ history = client.get_revocation_history("vp_abc123def456")
140
+ for event in history:
141
+ print(event["action"], event["reason"], event["performed_at"])
142
+ ```
143
+
144
+ ## API
145
+
146
+ ### `ValidPayClient(api_key, *, base_url=..., timeout=30.0, session=None)`
147
+
148
+ - `api_key` — your ValidPay API key (required for create endpoints).
149
+ - `base_url` — defaults to `https://api.validpay.com`.
150
+ - `timeout` — per-request timeout in seconds.
151
+ - `session` — optionally provide a `requests.Session` for connection
152
+ pooling, custom adapters, or mocking in tests.
153
+
154
+ ### `client.create_intent(document_type, payload) -> CreateIntentResult`
155
+
156
+ Encrypts `payload` (any JSON-serializable value) under a freshly
157
+ generated AES-256 key and registers it with ValidPay. Returns the
158
+ retrieval id and the key. **The key is never sent to ValidPay** — you
159
+ must hand it off out-of-band to whoever needs to verify the intent.
160
+
161
+ ### `client.create_intent_batch(intents) -> list[CreateIntentResult]`
162
+
163
+ Bulk version. `intents` is an iterable of mappings shaped
164
+ `{"document_type": str, "payload": Any}`, with 1–100 items. Each intent
165
+ gets its own unique key. Result order matches input order.
166
+
167
+ ### `client.verify_intent(retrieval_id, key) -> VerifyIntentResult`
168
+
169
+ Fetches the intent (public endpoint, no API key required), decrypts the
170
+ payload locally, and returns issuer metadata + the decrypted payload.
171
+
172
+ ### Errors
173
+
174
+ All SDK and API errors are raised as `ValidPayError`, which exposes:
175
+
176
+ - `code` — machine-readable code (e.g. `"unauthorized"`, `"not_found"`,
177
+ `"decryption_failed"`, `"invalid_key"`, `"network_error"`).
178
+ - `status` — HTTP status when the error came from the API.
179
+ - `details` — raw error body / extra context when available.
180
+
181
+ ### Low-level crypto
182
+
183
+ For advanced use cases the encryption primitives are exported directly:
184
+
185
+ ```python
186
+ from validpay import generate_key, encrypt, decrypt
187
+
188
+ key = generate_key()
189
+ blob = encrypt('{"hello": "world"}', key)
190
+ assert decrypt(blob, key) == '{"hello": "world"}'
191
+ ```
192
+
193
+ Wire format: `base64(iv[12] || authTag[16] || ciphertext)`.
194
+
195
+ ## Development
196
+
197
+ ```bash
198
+ pip install -e ".[dev]"
199
+ pytest
200
+ ```
201
+
202
+ ## License
203
+
204
+ MIT — see `LICENSE`.
@@ -0,0 +1,58 @@
1
+ [build-system]
2
+ requires = ["setuptools>=68", "wheel"]
3
+ build-backend = "setuptools.build_meta"
4
+
5
+ [project]
6
+ name = "validpay"
7
+ version = "1.0.1"
8
+ description = "Official ValidPay Python SDK — client-side AES-256-GCM encryption + ValidPay API client"
9
+ readme = "README.md"
10
+ license = { file = "LICENSE" }
11
+ authors = [{ name = "ValidPay", email = "dev@validpay.com" }]
12
+ requires-python = ">=3.9"
13
+ keywords = [
14
+ "validpay",
15
+ "encryption",
16
+ "aes-256-gcm",
17
+ "document-verification",
18
+ "blind-escrow",
19
+ ]
20
+ classifiers = [
21
+ "Development Status :: 5 - Production/Stable",
22
+ "Intended Audience :: Developers",
23
+ "License :: OSI Approved :: MIT License",
24
+ "Operating System :: OS Independent",
25
+ "Programming Language :: Python :: 3",
26
+ "Programming Language :: Python :: 3.9",
27
+ "Programming Language :: Python :: 3.10",
28
+ "Programming Language :: Python :: 3.11",
29
+ "Programming Language :: Python :: 3.12",
30
+ "Topic :: Security :: Cryptography",
31
+ ]
32
+ dependencies = [
33
+ "cryptography>=41.0",
34
+ "requests>=2.28",
35
+ ]
36
+
37
+ [project.optional-dependencies]
38
+ dev = [
39
+ "pytest>=7.0",
40
+ ]
41
+ binding = ["Pillow>=10.0", "numpy>=1.24", "scipy>=1.10"]
42
+
43
+ [project.urls]
44
+ Homepage = "https://validpay.com"
45
+ Documentation = "https://validpay.com/docs/api"
46
+ Repository = "https://github.com/ValidPay-io/validpay-python-sdk"
47
+ Issues = "https://github.com/ValidPay-io/validpay-python-sdk/issues"
48
+ Changelog = "https://github.com/ValidPay-io/validpay-python-sdk/blob/main/CHANGELOG.md"
49
+
50
+ [tool.setuptools.packages.find]
51
+ include = ["validpay*"]
52
+ exclude = ["tests*", "check21*"]
53
+
54
+ [tool.setuptools.package-data]
55
+ validpay = ["py.typed"]
56
+
57
+ [tool.pytest.ini_options]
58
+ testpaths = ["tests"]
@@ -0,0 +1,4 @@
1
+ [egg_info]
2
+ tag_build =
3
+ tag_date = 0
4
+
@@ -0,0 +1,52 @@
1
+ """ValidPay Python SDK.
2
+
3
+ Public API:
4
+ ValidPayClient — thin client for the ValidPay HTTP API
5
+ ValidPayError — exception type raised for all SDK / API errors
6
+ CreateIntentResult, VerifyIntentResult — result dataclasses
7
+ generate_key, encrypt, decrypt — low-level crypto helpers
8
+ """
9
+
10
+ from .binding import (
11
+ BindingComparisonResult,
12
+ compare_binding_hashes,
13
+ compute_binding_hash,
14
+ )
15
+ from .client import ValidPayClient
16
+ from .crypto import (
17
+ build_key_map,
18
+ combine_key_shares,
19
+ compute_commitment_hash,
20
+ decrypt,
21
+ decrypt_fields,
22
+ encrypt,
23
+ encrypt_fields,
24
+ generate_key,
25
+ split_key,
26
+ )
27
+ from .errors import ValidPayError
28
+ from .offline import OfflineCache, OfflineVerifyResult
29
+ from .types import CreateIntentResult, VerifyIntentResult
30
+
31
+ __all__ = [
32
+ "ValidPayClient",
33
+ "ValidPayError",
34
+ "CreateIntentResult",
35
+ "VerifyIntentResult",
36
+ "generate_key",
37
+ "encrypt",
38
+ "decrypt",
39
+ "compute_commitment_hash",
40
+ "split_key",
41
+ "combine_key_shares",
42
+ "encrypt_fields",
43
+ "build_key_map",
44
+ "decrypt_fields",
45
+ "compute_binding_hash",
46
+ "compare_binding_hashes",
47
+ "BindingComparisonResult",
48
+ "OfflineCache",
49
+ "OfflineVerifyResult",
50
+ ]
51
+
52
+ __version__ = "1.0.1"