cosmic-python-sdk 0.1.1__tar.gz → 0.2.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.
Files changed (42) hide show
  1. cosmic_python_sdk-0.2.0/PKG-INFO +358 -0
  2. cosmic_python_sdk-0.2.0/README.md +328 -0
  3. cosmic_python_sdk-0.2.0/cosmic_python_sdk.egg-info/PKG-INFO +358 -0
  4. cosmic_python_sdk-0.2.0/cosmic_python_sdk.egg-info/SOURCES.txt +31 -0
  5. cosmic_python_sdk-0.2.0/cosmic_python_sdk.egg-info/requires.txt +6 -0
  6. {cosmic_python_sdk-0.1.1 → cosmic_python_sdk-0.2.0}/cosmic_sdk/__init__.py +1 -1
  7. cosmic_python_sdk-0.2.0/cosmic_sdk/client.py +117 -0
  8. cosmic_python_sdk-0.2.0/cosmic_sdk/config.py +41 -0
  9. cosmic_python_sdk-0.2.0/cosmic_sdk/errors.py +52 -0
  10. cosmic_python_sdk-0.2.0/cosmic_sdk/logger.py +51 -0
  11. cosmic_python_sdk-0.2.0/cosmic_sdk/resources/__init__.py +0 -0
  12. cosmic_python_sdk-0.2.0/cosmic_sdk/resources/base.py +76 -0
  13. cosmic_python_sdk-0.2.0/cosmic_sdk/resources/customers.py +24 -0
  14. cosmic_python_sdk-0.2.0/cosmic_sdk/resources/payments.py +36 -0
  15. cosmic_python_sdk-0.2.0/cosmic_sdk/resources/refunds.py +26 -0
  16. cosmic_python_sdk-0.2.0/cosmic_sdk/resources/transactions.py +13 -0
  17. cosmic_python_sdk-0.2.0/cosmic_sdk/types/__init__.py +0 -0
  18. cosmic_python_sdk-0.2.0/cosmic_sdk/types/common.py +47 -0
  19. cosmic_python_sdk-0.2.0/cosmic_sdk/types/customers.py +12 -0
  20. cosmic_python_sdk-0.2.0/cosmic_sdk/types/payments.py +23 -0
  21. cosmic_python_sdk-0.2.0/cosmic_sdk/types/refunds.py +13 -0
  22. cosmic_python_sdk-0.2.0/cosmic_sdk/validation.py +70 -0
  23. cosmic_python_sdk-0.2.0/cosmic_sdk/webhooks.py +31 -0
  24. cosmic_python_sdk-0.2.0/pyproject.toml +44 -0
  25. cosmic_python_sdk-0.2.0/setup.cfg +4 -0
  26. cosmic_python_sdk-0.2.0/tests/test_client.py +80 -0
  27. cosmic_python_sdk-0.2.0/tests/test_config.py +32 -0
  28. cosmic_python_sdk-0.2.0/tests/test_errors.py +39 -0
  29. cosmic_python_sdk-0.2.0/tests/test_logger.py +15 -0
  30. cosmic_python_sdk-0.2.0/tests/test_validation.py +103 -0
  31. cosmic_python_sdk-0.2.0/tests/test_webhooks.py +40 -0
  32. cosmic_python_sdk-0.1.1/PKG-INFO +0 -28
  33. cosmic_python_sdk-0.1.1/README.md +0 -17
  34. cosmic_python_sdk-0.1.1/cosmic_python_sdk.egg-info/PKG-INFO +0 -28
  35. cosmic_python_sdk-0.1.1/cosmic_python_sdk.egg-info/SOURCES.txt +0 -11
  36. cosmic_python_sdk-0.1.1/cosmic_python_sdk.egg-info/requires.txt +0 -1
  37. cosmic_python_sdk-0.1.1/cosmic_sdk/client.py +0 -31
  38. cosmic_python_sdk-0.1.1/pyproject.toml +0 -3
  39. cosmic_python_sdk-0.1.1/setup.cfg +0 -20
  40. cosmic_python_sdk-0.1.1/tests/test_client.py +0 -16
  41. {cosmic_python_sdk-0.1.1 → cosmic_python_sdk-0.2.0}/cosmic_python_sdk.egg-info/dependency_links.txt +0 -0
  42. {cosmic_python_sdk-0.1.1 → cosmic_python_sdk-0.2.0}/cosmic_python_sdk.egg-info/top_level.txt +0 -0
@@ -0,0 +1,358 @@
1
+ Metadata-Version: 2.4
2
+ Name: cosmic-python-sdk
3
+ Version: 0.2.0
4
+ Summary: Official Python SDK for the Cosmic Gateway payment processing API
5
+ Author: Emmanuel Mnanka Samo
6
+ License: MIT
7
+ Project-URL: Homepage, https://github.com/cosmic-payment/cosmic-gateway
8
+ Project-URL: Documentation, https://github.com/cosmic-payment/cosmic-gateway
9
+ Project-URL: Source, https://github.com/cosmic-payment/cosmic-gateway
10
+ Project-URL: Issues, https://github.com/cosmic-payment/cosmic-gateway/issues
11
+ Keywords: payment,gateway,cosmic,api,sdk,payments
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.8
17
+ Classifier: Programming Language :: Python :: 3.9
18
+ Classifier: Programming Language :: Python :: 3.10
19
+ Classifier: Programming Language :: Python :: 3.11
20
+ Classifier: Programming Language :: Python :: 3.12
21
+ Classifier: Topic :: Office/Business :: Financial
22
+ Classifier: Topic :: Software Development :: Libraries :: Python Modules
23
+ Requires-Python: >=3.8
24
+ Description-Content-Type: text/markdown
25
+ Requires-Dist: requests>=2.28
26
+ Provides-Extra: dev
27
+ Requires-Dist: pytest>=7.0; extra == "dev"
28
+ Requires-Dist: pytest-mock>=3.0; extra == "dev"
29
+ Requires-Dist: responses>=0.23; extra == "dev"
30
+
31
+ # Cosmic Python SDK
32
+
33
+ Official Python client SDK for the [Cosmic Gateway](https://cosmicgateway.com) payment processing API.
34
+
35
+ ## Features
36
+
37
+ - **Complete payment lifecycle** — charge, capture, refund, and query payments
38
+ - **Customer management** — create, retrieve, and list customers
39
+ - **Transaction history** — paginated transaction listing with filters
40
+ - **Webhook verification** — HMAC-SHA256 signature verification for incoming webhooks
41
+ - **Idempotency** — automatic idempotency key generation to safely retry requests
42
+ - **Retry with backoff** — automatic retry on 5xx errors and rate limits (429)
43
+ - **Request timeout** — configurable timeout per request
44
+ - **Environment switching** — built-in sandbox and production endpoints
45
+ - **Input validation** — pre-flight validation of amounts, currencies, emails, and more
46
+ - **Typed request/response models** — dataclass-based types for all API objects
47
+ - **Sensitive data masking** — automatic masking of API keys, PAN, and CVC in logs
48
+
49
+ ## Installation
50
+
51
+ ```bash
52
+ pip install cosmic-python-sdk
53
+ ```
54
+
55
+ Requires Python 3.8+.
56
+
57
+ ### Development installation
58
+
59
+ ```bash
60
+ pip install cosmic-python-sdk[dev]
61
+ ```
62
+
63
+ ## Quick Start
64
+
65
+ ```python
66
+ from cosmic_sdk import CosmicGateway
67
+
68
+ client = CosmicGateway(
69
+ api_key="sk_test_...",
70
+ environment="sandbox", # or "production"
71
+ )
72
+
73
+ # Charge a payment
74
+ result = client.payments.charge({
75
+ "amount": 1999, # $19.99 in cents
76
+ "currency": "usd",
77
+ "source": "tok_visa_4242",
78
+ "description": "Test payment",
79
+ })
80
+
81
+ if result["success"]:
82
+ print("Payment ID:", result["transactionId"])
83
+ print("New balance:", result["newBalance"])
84
+ else:
85
+ print("Payment failed:", result["status"])
86
+ ```
87
+
88
+ ## Configuration
89
+
90
+ | Option | Type | Default | Description |
91
+ |--------|------|---------|-------------|
92
+ | `api_key` | `str` | **required** | Your secret API key |
93
+ | `environment` | `str` | `'production'` | API environment: `'sandbox'` or `'production'` |
94
+ | `base_url` | `str` | environment default | Custom API base URL (overrides environment) |
95
+ | `timeout` | `int` | `30000` | Request timeout in milliseconds |
96
+
97
+ ### Environment URLs
98
+
99
+ | Environment | URL |
100
+ |-------------|-----|
101
+ | `sandbox` | `https://api.sandbox.cosmicgateway.com` |
102
+ | `production` | `https://api.cosmicgateway.com` |
103
+
104
+ ### Retry Configuration
105
+
106
+ The SDK retries failed requests with exponential backoff. Configure via `RetryConfig`:
107
+
108
+ ```python
109
+ from cosmic_sdk import CosmicGateway
110
+ from cosmic_sdk.config import RetryConfig
111
+
112
+ client = CosmicGateway(
113
+ api_key="sk_test_...",
114
+ environment="sandbox",
115
+ )
116
+
117
+ client.config.retry = RetryConfig(
118
+ max_retries=5,
119
+ base_delay_ms=200,
120
+ max_delay_ms=10000,
121
+ )
122
+ ```
123
+
124
+ ## API Reference
125
+
126
+ ### Payments
127
+
128
+ #### `client.payments.charge(request)`
129
+
130
+ Process a payment charge.
131
+
132
+ ```python
133
+ result = client.payments.charge({
134
+ "amount": 1999,
135
+ "currency": "usd",
136
+ "source": "tok_abc123",
137
+ "description": "Order #1234",
138
+ "metadata": {"orderId": "ORD-12345"},
139
+ "idempotencyKey": "uuid-v4", # optional — auto-generated if omitted
140
+ })
141
+ ```
142
+
143
+ **Success response:**
144
+ ```python
145
+ {
146
+ "success": True,
147
+ "transactionId": "txn_...",
148
+ "referenceId": "ref_...",
149
+ "processor": "stripe",
150
+ "region": "us",
151
+ "amount": 1999,
152
+ "currency": "usd",
153
+ "settlement": { # present for cross-currency payments
154
+ "from": "usd",
155
+ "to": "kes",
156
+ "originalAmount": 1999,
157
+ "convertedAmount": 289855,
158
+ "rate": 145.0,
159
+ },
160
+ "newBalance": 50000,
161
+ "fraudScore": 0.02,
162
+ "kycVerified": "verified",
163
+ }
164
+ ```
165
+
166
+ **Failed response:**
167
+ ```python
168
+ {
169
+ "success": False,
170
+ "transactionId": "txn_...",
171
+ "referenceId": None,
172
+ "processor": "stripe",
173
+ "region": "us",
174
+ "status": "failed",
175
+ }
176
+ ```
177
+
178
+ #### `client.payments.retrieve(payment_id)`
179
+
180
+ Retrieve payment details by ID.
181
+
182
+ ```python
183
+ payment = client.payments.retrieve("pay_abc123")
184
+ ```
185
+
186
+ #### `client.payments.list(params=None)`
187
+
188
+ List payments with optional filtering.
189
+
190
+ ```python
191
+ result = client.payments.list({
192
+ "page": 1,
193
+ "limit": 20,
194
+ "status": "SUCCESS",
195
+ "startDate": "2026-01-01T00:00:00Z",
196
+ "endDate": "2026-12-31T23:59:59Z",
197
+ })
198
+ ```
199
+
200
+ ### Refunds
201
+
202
+ #### `client.refunds.create(request)`
203
+
204
+ Create a refund for a payment.
205
+
206
+ ```python
207
+ result = client.refunds.create({
208
+ "paymentId": "pay_abc123",
209
+ "amount": 500, # partial refund (optional, defaults to full)
210
+ "reason": "Customer requested refund",
211
+ "metadata": {"ticketId": "TKT-999"},
212
+ })
213
+ ```
214
+
215
+ #### `client.refunds.retrieve(refund_id)`
216
+
217
+ ```python
218
+ refund = client.refunds.retrieve("ref_abc123")
219
+ ```
220
+
221
+ #### `client.refunds.list(params=None)`
222
+
223
+ ### Customers
224
+
225
+ #### `client.customers.create(request)`
226
+
227
+ ```python
228
+ customer = client.customers.create({
229
+ "email": "user@example.com",
230
+ "name": "John Doe",
231
+ "phone": "+254700000000",
232
+ "metadata": {"signupSource": "web"},
233
+ })
234
+ ```
235
+
236
+ #### `client.customers.retrieve(customer_id)`
237
+
238
+ #### `client.customers.list(params=None)`
239
+
240
+ ### Transactions
241
+
242
+ #### `client.transactions.list(params=None)`
243
+
244
+ ```python
245
+ result = client.transactions.list({
246
+ "page": 1,
247
+ "limit": 20,
248
+ })
249
+ ```
250
+
251
+ #### `client.transactions.retrieve(transaction_id)`
252
+
253
+ ### Webhook Verification
254
+
255
+ ```python
256
+ from cosmic_sdk.webhooks import verify_webhook_signature
257
+
258
+ payload = request.body # raw bytes
259
+ signature = request.headers.get("X-Cosmic-Signature") # "sha256=..."
260
+ secret = "whsec_..."
261
+
262
+ event = verify_webhook_signature(payload, signature, secret)
263
+ # {"event": "payment.succeeded", "transactionId": "txn_1", ...}
264
+ ```
265
+
266
+ The SDK verifies the `sha256=` HMAC signature using **timing-safe comparison** (`hmac.compare_digest`).
267
+
268
+ Raises `WebhookVerificationError` if the signature is missing, malformed, or doesn't match.
269
+
270
+ ### Health Check
271
+
272
+ ```python
273
+ health = client.health()
274
+ # {"status": "ok"}
275
+ ```
276
+
277
+ ### Raw HTTP Methods
278
+
279
+ The SDK exposes `get()` and `post()` for direct API access if needed:
280
+
281
+ ```python
282
+ # Raw GET
283
+ resp = client.get("/customers", params={"limit": 10})
284
+
285
+ # Raw POST
286
+ resp = client.post("/customers", json={"email": "user@example.com"})
287
+ ```
288
+
289
+ ## Error Handling
290
+
291
+ The SDK raises typed exceptions for all failure modes:
292
+
293
+ | Exception | HTTP Status | When |
294
+ |-----------|-------------|------|
295
+ | `ValidationError` | 400 | Invalid input |
296
+ | `AuthenticationError` | 401 | Missing or invalid credentials |
297
+ | `PaymentFailedError` | 402 | Payment was declined |
298
+ | `NotFoundError` | 404 | Resource not found |
299
+ | `RateLimitError` | 429 | Too many requests |
300
+ | `ServerError` | 500 | Gateway internal error |
301
+ | `ServiceUnavailableError` | 503 | Service temporarily down |
302
+ | `WebhookVerificationError` | — | Webhook signature invalid |
303
+
304
+ ```python
305
+ from cosmic_sdk.errors import PaymentFailedError, ValidationError
306
+
307
+ try:
308
+ result = client.payments.charge({
309
+ "amount": -1,
310
+ "currency": "usd",
311
+ "source": "tok_abc",
312
+ })
313
+ except ValidationError as e:
314
+ print("Bad input:", e)
315
+ except PaymentFailedError as e:
316
+ print("Payment declined:", e.transaction_id)
317
+ ```
318
+
319
+ ## Retry Behavior
320
+
321
+ - **5xx errors** — retried with exponential backoff (base delay doubles each attempt)
322
+ - **429 rate limits** — respects the `Retry-After` header
323
+ - **Network errors** — retried as transient failures
324
+ - **4xx errors (except 429)** — **not** retried (these are client errors)
325
+ - Configurable via `RetryConfig`
326
+
327
+ ## Idempotency
328
+
329
+ All mutation endpoints (`charge`, `create`, etc.) accept an optional `idempotency_key`. If omitted, a UUID v4 is generated automatically. The gateway uses the `api_key + idempotency_key` pair to detect duplicate requests and return the cached response.
330
+
331
+ ## Sensitive Data Masking
332
+
333
+ The logger automatically masks sensitive fields (API keys, PAN, CVC, auth tokens) in logs. Set the log level to `DEBUG` to inspect request/response shapes without exposing secrets:
334
+
335
+ ```python
336
+ import logging
337
+ client._logger = GatewayLogger(level=logging.DEBUG)
338
+ ```
339
+
340
+ ## Development
341
+
342
+ ```bash
343
+ # Clone and install with dev dependencies
344
+ pip install -e ".[dev]"
345
+
346
+ # Run tests
347
+ python3 -m pytest tests/
348
+
349
+ # Run with coverage
350
+ python3 -m pytest tests/ --cov=cosmic_sdk
351
+
352
+ # Build distribution
353
+ python3 -m build
354
+ ```
355
+
356
+ ## License
357
+
358
+ MIT
@@ -0,0 +1,328 @@
1
+ # Cosmic Python SDK
2
+
3
+ Official Python client SDK for the [Cosmic Gateway](https://cosmicgateway.com) payment processing API.
4
+
5
+ ## Features
6
+
7
+ - **Complete payment lifecycle** — charge, capture, refund, and query payments
8
+ - **Customer management** — create, retrieve, and list customers
9
+ - **Transaction history** — paginated transaction listing with filters
10
+ - **Webhook verification** — HMAC-SHA256 signature verification for incoming webhooks
11
+ - **Idempotency** — automatic idempotency key generation to safely retry requests
12
+ - **Retry with backoff** — automatic retry on 5xx errors and rate limits (429)
13
+ - **Request timeout** — configurable timeout per request
14
+ - **Environment switching** — built-in sandbox and production endpoints
15
+ - **Input validation** — pre-flight validation of amounts, currencies, emails, and more
16
+ - **Typed request/response models** — dataclass-based types for all API objects
17
+ - **Sensitive data masking** — automatic masking of API keys, PAN, and CVC in logs
18
+
19
+ ## Installation
20
+
21
+ ```bash
22
+ pip install cosmic-python-sdk
23
+ ```
24
+
25
+ Requires Python 3.8+.
26
+
27
+ ### Development installation
28
+
29
+ ```bash
30
+ pip install cosmic-python-sdk[dev]
31
+ ```
32
+
33
+ ## Quick Start
34
+
35
+ ```python
36
+ from cosmic_sdk import CosmicGateway
37
+
38
+ client = CosmicGateway(
39
+ api_key="sk_test_...",
40
+ environment="sandbox", # or "production"
41
+ )
42
+
43
+ # Charge a payment
44
+ result = client.payments.charge({
45
+ "amount": 1999, # $19.99 in cents
46
+ "currency": "usd",
47
+ "source": "tok_visa_4242",
48
+ "description": "Test payment",
49
+ })
50
+
51
+ if result["success"]:
52
+ print("Payment ID:", result["transactionId"])
53
+ print("New balance:", result["newBalance"])
54
+ else:
55
+ print("Payment failed:", result["status"])
56
+ ```
57
+
58
+ ## Configuration
59
+
60
+ | Option | Type | Default | Description |
61
+ |--------|------|---------|-------------|
62
+ | `api_key` | `str` | **required** | Your secret API key |
63
+ | `environment` | `str` | `'production'` | API environment: `'sandbox'` or `'production'` |
64
+ | `base_url` | `str` | environment default | Custom API base URL (overrides environment) |
65
+ | `timeout` | `int` | `30000` | Request timeout in milliseconds |
66
+
67
+ ### Environment URLs
68
+
69
+ | Environment | URL |
70
+ |-------------|-----|
71
+ | `sandbox` | `https://api.sandbox.cosmicgateway.com` |
72
+ | `production` | `https://api.cosmicgateway.com` |
73
+
74
+ ### Retry Configuration
75
+
76
+ The SDK retries failed requests with exponential backoff. Configure via `RetryConfig`:
77
+
78
+ ```python
79
+ from cosmic_sdk import CosmicGateway
80
+ from cosmic_sdk.config import RetryConfig
81
+
82
+ client = CosmicGateway(
83
+ api_key="sk_test_...",
84
+ environment="sandbox",
85
+ )
86
+
87
+ client.config.retry = RetryConfig(
88
+ max_retries=5,
89
+ base_delay_ms=200,
90
+ max_delay_ms=10000,
91
+ )
92
+ ```
93
+
94
+ ## API Reference
95
+
96
+ ### Payments
97
+
98
+ #### `client.payments.charge(request)`
99
+
100
+ Process a payment charge.
101
+
102
+ ```python
103
+ result = client.payments.charge({
104
+ "amount": 1999,
105
+ "currency": "usd",
106
+ "source": "tok_abc123",
107
+ "description": "Order #1234",
108
+ "metadata": {"orderId": "ORD-12345"},
109
+ "idempotencyKey": "uuid-v4", # optional — auto-generated if omitted
110
+ })
111
+ ```
112
+
113
+ **Success response:**
114
+ ```python
115
+ {
116
+ "success": True,
117
+ "transactionId": "txn_...",
118
+ "referenceId": "ref_...",
119
+ "processor": "stripe",
120
+ "region": "us",
121
+ "amount": 1999,
122
+ "currency": "usd",
123
+ "settlement": { # present for cross-currency payments
124
+ "from": "usd",
125
+ "to": "kes",
126
+ "originalAmount": 1999,
127
+ "convertedAmount": 289855,
128
+ "rate": 145.0,
129
+ },
130
+ "newBalance": 50000,
131
+ "fraudScore": 0.02,
132
+ "kycVerified": "verified",
133
+ }
134
+ ```
135
+
136
+ **Failed response:**
137
+ ```python
138
+ {
139
+ "success": False,
140
+ "transactionId": "txn_...",
141
+ "referenceId": None,
142
+ "processor": "stripe",
143
+ "region": "us",
144
+ "status": "failed",
145
+ }
146
+ ```
147
+
148
+ #### `client.payments.retrieve(payment_id)`
149
+
150
+ Retrieve payment details by ID.
151
+
152
+ ```python
153
+ payment = client.payments.retrieve("pay_abc123")
154
+ ```
155
+
156
+ #### `client.payments.list(params=None)`
157
+
158
+ List payments with optional filtering.
159
+
160
+ ```python
161
+ result = client.payments.list({
162
+ "page": 1,
163
+ "limit": 20,
164
+ "status": "SUCCESS",
165
+ "startDate": "2026-01-01T00:00:00Z",
166
+ "endDate": "2026-12-31T23:59:59Z",
167
+ })
168
+ ```
169
+
170
+ ### Refunds
171
+
172
+ #### `client.refunds.create(request)`
173
+
174
+ Create a refund for a payment.
175
+
176
+ ```python
177
+ result = client.refunds.create({
178
+ "paymentId": "pay_abc123",
179
+ "amount": 500, # partial refund (optional, defaults to full)
180
+ "reason": "Customer requested refund",
181
+ "metadata": {"ticketId": "TKT-999"},
182
+ })
183
+ ```
184
+
185
+ #### `client.refunds.retrieve(refund_id)`
186
+
187
+ ```python
188
+ refund = client.refunds.retrieve("ref_abc123")
189
+ ```
190
+
191
+ #### `client.refunds.list(params=None)`
192
+
193
+ ### Customers
194
+
195
+ #### `client.customers.create(request)`
196
+
197
+ ```python
198
+ customer = client.customers.create({
199
+ "email": "user@example.com",
200
+ "name": "John Doe",
201
+ "phone": "+254700000000",
202
+ "metadata": {"signupSource": "web"},
203
+ })
204
+ ```
205
+
206
+ #### `client.customers.retrieve(customer_id)`
207
+
208
+ #### `client.customers.list(params=None)`
209
+
210
+ ### Transactions
211
+
212
+ #### `client.transactions.list(params=None)`
213
+
214
+ ```python
215
+ result = client.transactions.list({
216
+ "page": 1,
217
+ "limit": 20,
218
+ })
219
+ ```
220
+
221
+ #### `client.transactions.retrieve(transaction_id)`
222
+
223
+ ### Webhook Verification
224
+
225
+ ```python
226
+ from cosmic_sdk.webhooks import verify_webhook_signature
227
+
228
+ payload = request.body # raw bytes
229
+ signature = request.headers.get("X-Cosmic-Signature") # "sha256=..."
230
+ secret = "whsec_..."
231
+
232
+ event = verify_webhook_signature(payload, signature, secret)
233
+ # {"event": "payment.succeeded", "transactionId": "txn_1", ...}
234
+ ```
235
+
236
+ The SDK verifies the `sha256=` HMAC signature using **timing-safe comparison** (`hmac.compare_digest`).
237
+
238
+ Raises `WebhookVerificationError` if the signature is missing, malformed, or doesn't match.
239
+
240
+ ### Health Check
241
+
242
+ ```python
243
+ health = client.health()
244
+ # {"status": "ok"}
245
+ ```
246
+
247
+ ### Raw HTTP Methods
248
+
249
+ The SDK exposes `get()` and `post()` for direct API access if needed:
250
+
251
+ ```python
252
+ # Raw GET
253
+ resp = client.get("/customers", params={"limit": 10})
254
+
255
+ # Raw POST
256
+ resp = client.post("/customers", json={"email": "user@example.com"})
257
+ ```
258
+
259
+ ## Error Handling
260
+
261
+ The SDK raises typed exceptions for all failure modes:
262
+
263
+ | Exception | HTTP Status | When |
264
+ |-----------|-------------|------|
265
+ | `ValidationError` | 400 | Invalid input |
266
+ | `AuthenticationError` | 401 | Missing or invalid credentials |
267
+ | `PaymentFailedError` | 402 | Payment was declined |
268
+ | `NotFoundError` | 404 | Resource not found |
269
+ | `RateLimitError` | 429 | Too many requests |
270
+ | `ServerError` | 500 | Gateway internal error |
271
+ | `ServiceUnavailableError` | 503 | Service temporarily down |
272
+ | `WebhookVerificationError` | — | Webhook signature invalid |
273
+
274
+ ```python
275
+ from cosmic_sdk.errors import PaymentFailedError, ValidationError
276
+
277
+ try:
278
+ result = client.payments.charge({
279
+ "amount": -1,
280
+ "currency": "usd",
281
+ "source": "tok_abc",
282
+ })
283
+ except ValidationError as e:
284
+ print("Bad input:", e)
285
+ except PaymentFailedError as e:
286
+ print("Payment declined:", e.transaction_id)
287
+ ```
288
+
289
+ ## Retry Behavior
290
+
291
+ - **5xx errors** — retried with exponential backoff (base delay doubles each attempt)
292
+ - **429 rate limits** — respects the `Retry-After` header
293
+ - **Network errors** — retried as transient failures
294
+ - **4xx errors (except 429)** — **not** retried (these are client errors)
295
+ - Configurable via `RetryConfig`
296
+
297
+ ## Idempotency
298
+
299
+ All mutation endpoints (`charge`, `create`, etc.) accept an optional `idempotency_key`. If omitted, a UUID v4 is generated automatically. The gateway uses the `api_key + idempotency_key` pair to detect duplicate requests and return the cached response.
300
+
301
+ ## Sensitive Data Masking
302
+
303
+ The logger automatically masks sensitive fields (API keys, PAN, CVC, auth tokens) in logs. Set the log level to `DEBUG` to inspect request/response shapes without exposing secrets:
304
+
305
+ ```python
306
+ import logging
307
+ client._logger = GatewayLogger(level=logging.DEBUG)
308
+ ```
309
+
310
+ ## Development
311
+
312
+ ```bash
313
+ # Clone and install with dev dependencies
314
+ pip install -e ".[dev]"
315
+
316
+ # Run tests
317
+ python3 -m pytest tests/
318
+
319
+ # Run with coverage
320
+ python3 -m pytest tests/ --cov=cosmic_sdk
321
+
322
+ # Build distribution
323
+ python3 -m build
324
+ ```
325
+
326
+ ## License
327
+
328
+ MIT