paravane 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.
paravane-0.2.0/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Paravane Labs
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,697 @@
1
+ Metadata-Version: 2.4
2
+ Name: paravane
3
+ Version: 0.2.0
4
+ Summary: Python SDK for the Paravane API.
5
+ Author-email: Paravane Labs <contact@paravane.io>
6
+ License: MIT License
7
+
8
+ Copyright (c) 2026 Paravane Labs
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://paravane.io
29
+ Project-URL: Documentation, https://paravane.io/pages/docs/index.html
30
+ Project-URL: Changelog, https://github.com/paravaneai/paravane-python/blob/main/CHANGELOG.md
31
+ Project-URL: Source, https://github.com/paravaneai/paravane-python
32
+ Project-URL: Issues, https://github.com/paravaneai/paravane-python/issues
33
+ Keywords: paravane,smtprs,email risk,api,sdk
34
+ Classifier: Development Status :: 3 - Alpha
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 :: Only
40
+ Classifier: Programming Language :: Python :: 3.8
41
+ Classifier: Programming Language :: Python :: 3.9
42
+ Classifier: Programming Language :: Python :: 3.10
43
+ Classifier: Programming Language :: Python :: 3.11
44
+ Classifier: Programming Language :: Python :: 3.12
45
+ Classifier: Programming Language :: Python :: 3.13
46
+ Classifier: Topic :: Software Development :: Libraries :: Python Modules
47
+ Requires-Python: >=3.8
48
+ Description-Content-Type: text/markdown
49
+ License-File: LICENSE
50
+ Requires-Dist: requests>=2.31.0
51
+ Provides-Extra: dev
52
+ Requires-Dist: build>=1.2.1; extra == "dev"
53
+ Requires-Dist: pytest>=8.0.0; extra == "dev"
54
+ Requires-Dist: ruff>=0.6.0; extra == "dev"
55
+ Requires-Dist: setuptools>=61.0; extra == "dev"
56
+ Requires-Dist: tomli>=2.0.0; python_version < "3.11" and extra == "dev"
57
+ Requires-Dist: twine>=5.1.0; extra == "dev"
58
+ Requires-Dist: wheel; extra == "dev"
59
+ Dynamic: license-file
60
+
61
+ <p align="center">
62
+ <picture>
63
+ <source
64
+ media="(prefers-color-scheme: light)"
65
+ srcset="https://raw.githubusercontent.com/paravaneai/paravane-python/main/doc/images/readme/paravane-smtprs-sdk-readme-banner-logo-matched-orange-dark-developer-api-upscaled-3x.png" />
66
+ <img
67
+ src="https://raw.githubusercontent.com/paravaneai/paravane-python/main/doc/images/readme/paravane-smtprs-sdk-readme-banner-logo-matched-orange-dark-developer-api-upscaled-3x.png"
68
+ alt="Paravane" />
69
+ </picture>
70
+ </p>
71
+
72
+ <h1 align="center">
73
+ Paravane Python Library
74
+ </h1>
75
+
76
+ <p align="center">
77
+ The Paravane Python library provides convenient access to the Paravane API from applications written in Python.
78
+ <br /><br />
79
+ The first supported product API is <strong>smtpRS</strong>, Paravane's email risk intelligence API.
80
+ smtpRS helps score email addresses for onboarding, trust, review, abuse-prevention, and operations workflows.
81
+ <br /><br />
82
+ This SDK is intentionally small at the start. It provides a stable client entrypoint,
83
+ request serialization, response helpers, structured errors, examples, tests, and packaging
84
+ conventions that can grow as Paravane adds more APIs.
85
+ </p>
86
+
87
+ <p align="center">
88
+ <a href="https://pypi.org/project/paravane/">
89
+ <img
90
+ src="https://img.shields.io/pypi/v/paravane.svg"
91
+ alt="PyPI" />
92
+ </a>
93
+ <a href="https://pypi.org/project/paravane/">
94
+ <img
95
+ src="https://img.shields.io/pypi/pyversions/paravane.svg"
96
+ alt="Supported Python versions" />
97
+ </a>
98
+ <a href="https://github.com/paravaneai/paravane-python/actions/workflows/tests.yml">
99
+ <img
100
+ src="https://github.com/paravaneai/paravane-python/actions/workflows/tests.yml/badge.svg"
101
+ alt="Tests" />
102
+ </a>
103
+ </p>
104
+
105
+ <h3 align="center">
106
+ <a href="#documentation">Documentation</a>
107
+ <span> · </span>
108
+ <a href="#installation">Installation</a>
109
+ <span> · </span>
110
+ <a href="#quickstart">Quickstart</a>
111
+ <span> · </span>
112
+ <a href="#examples">Examples</a>
113
+ <span> · </span>
114
+ <a href="#development">Development</a>
115
+ </h3>
116
+
117
+ ## Contents
118
+
119
+ - [Documentation](#documentation)
120
+ - [Installation](#installation)
121
+ - [Requirements](#requirements)
122
+ - [Quickstart](#quickstart)
123
+ - [Usage](#usage)
124
+ - [smtpRS](#smtprs)
125
+ - [Configuration](#configuration)
126
+ - [Per-request options](#per-request-options)
127
+ - [Custom HTTP sessions](#custom-http-sessions)
128
+ - [Retries](#retries)
129
+ - [Idempotency](#idempotency)
130
+ - [Errors](#errors)
131
+ - [Responses and raw data](#responses-and-raw-data)
132
+ - [Types](#types)
133
+ - [Logging](#logging)
134
+ - [Examples](#examples)
135
+ - [Development](#development)
136
+ - [Repository layout](#repository-layout)
137
+ - [Versioning](#versioning)
138
+ - [Security](#security)
139
+ - [Support](#support)
140
+
141
+ ## Documentation
142
+
143
+ - Product docs: https://paravane.io/pages/docs/index.html
144
+ - smtpRS docs: https://paravane.io/pages/docs/smtprs/index.html
145
+ - Analyse endpoint: https://paravane.io/pages/docs/smtprs/analyse.html
146
+ - Plans and limits: https://paravane.io/pages/docs/smtprs/plans-limits.html
147
+
148
+ ## Installation
149
+
150
+ Install the latest release from PyPI:
151
+
152
+ ```bash
153
+ python -m pip install --upgrade paravane
154
+ ```
155
+
156
+ To install the current development version directly from GitHub:
157
+
158
+ ```bash
159
+ python -m pip install "git+https://github.com/paravaneai/paravane-python.git"
160
+ ```
161
+
162
+ For local development:
163
+
164
+ ```bash
165
+ git clone git@github.com:paravaneai/paravane-python.git
166
+ cd paravane-python
167
+ python -m pip install -e ".[dev]"
168
+ ```
169
+
170
+ ## Requirements
171
+
172
+ Python 3.8 or newer.
173
+
174
+ Runtime dependency:
175
+
176
+ - `requests>=2.31.0`
177
+
178
+ Development dependencies are installed with:
179
+
180
+ ```bash
181
+ python -m pip install -e ".[dev]"
182
+ ```
183
+
184
+ ## Quickstart
185
+
186
+ Set your API key:
187
+
188
+ ```bash
189
+ export PARAVANE_API_KEY="pvn_live_..."
190
+ ```
191
+
192
+ On Windows PowerShell:
193
+
194
+ ```powershell
195
+ $env:PARAVANE_API_KEY = "pvn_live_..."
196
+ ```
197
+
198
+ Call smtpRS:
199
+
200
+ ```python
201
+ from paravane import ParavaneClient
202
+
203
+ client = ParavaneClient()
204
+
205
+ result = client.smtprs.analyze("alice@example.com")
206
+
207
+ print(result.decision)
208
+ print(result.overall_risk)
209
+ print(result.credits_charged)
210
+ ```
211
+
212
+ The SDK method is named `analyze(...)` for Python readability. The HTTP API endpoint remains:
213
+
214
+ ```text
215
+ POST /v1/analyse
216
+ ```
217
+
218
+ ## Usage
219
+
220
+ Create a client with an API key:
221
+
222
+ ```python
223
+ from paravane import ParavaneClient
224
+
225
+ client = ParavaneClient(api_key="pvn_live_...")
226
+ ```
227
+
228
+ Or use `PARAVANE_API_KEY`:
229
+
230
+ ```python
231
+ from paravane import ParavaneClient
232
+
233
+ client = ParavaneClient()
234
+ ```
235
+
236
+ Run an email risk analysis:
237
+
238
+ ```python
239
+ result = client.smtprs.analyze("person@example.com")
240
+
241
+ if result.decision == "allow":
242
+ print("Continue")
243
+ else:
244
+ print("Review or block")
245
+ ```
246
+
247
+ Inspect the normalized response:
248
+
249
+ ```python
250
+ print(result.email)
251
+ print(result.decision)
252
+ print(result.overall_risk)
253
+ print(result.analysis_profile)
254
+ print(result.credit_cost)
255
+ print(result.usage)
256
+ ```
257
+
258
+ Access the original API response:
259
+
260
+ ```python
261
+ raw = result.to_dict()
262
+ print(raw)
263
+ ```
264
+
265
+ ## smtpRS
266
+
267
+ smtpRS is available through:
268
+
269
+ ```python
270
+ client.smtprs
271
+ ```
272
+
273
+ ### Analysis profiles
274
+
275
+ smtpRS provides named profiles so applications can choose the appropriate balance of
276
+ coverage, latency, and credit usage without configuring individual checks.
277
+
278
+ | Profile | Credits | Availability | Intended use |
279
+ | --- | ---: | --- | --- |
280
+ | `quick` | 1 | All plans | Lightweight screening; this is the default. |
281
+ | `standard` | 3 | Basic and above | Broader passive analysis. |
282
+ | `adaptive` | 5 | Pro and above | Adds checks when the initial result needs more context. |
283
+ | `deep` | 5 | Pro and above | Comprehensive analysis without catch-all probing. |
284
+ | `catch_all` | 20 | Enterprise or entitled accounts | Deep analysis with catch-all probing. |
285
+
286
+ Use the default quick profile:
287
+
288
+ ```python
289
+ result = client.smtprs.analyze("person@example.com")
290
+ ```
291
+
292
+ Or request another profile available to your account:
293
+
294
+ ```python
295
+ result = client.smtprs.analyze(
296
+ "person@example.com",
297
+ profile="standard",
298
+ )
299
+ ```
300
+
301
+ Profile availability is enforced by the API. Requesting a profile that is not included
302
+ with the current plan raises `PermissionDeniedError`.
303
+
304
+ ### Legacy mode flags
305
+
306
+ The older `disposable_only`, `strict_disposable`, `guess`, and `run_catch_all` arguments
307
+ remain available for compatibility. New integrations should use `profile` instead. Do not
308
+ combine `profile` with an enabled legacy mode flag.
309
+
310
+ For example, replace:
311
+
312
+ ```python
313
+ result = client.smtprs.analyze(
314
+ "person@example.com",
315
+ strict_disposable=True,
316
+ )
317
+ ```
318
+
319
+ with:
320
+
321
+ ```python
322
+ result = client.smtprs.analyze(
323
+ "person@example.com",
324
+ profile="deep",
325
+ )
326
+ ```
327
+
328
+ ### Low-latency posture
329
+
330
+ Use the `fast` flag when your workflow favors lower latency:
331
+
332
+ ```python
333
+ result = client.smtprs.analyze(
334
+ "person@example.com",
335
+ fast=True,
336
+ )
337
+ ```
338
+
339
+ ### Company Validity Beta
340
+
341
+ Paid smtpRS callers can explicitly request the optional Company Validity Beta:
342
+
343
+ ```python
344
+ result = client.smtprs.analyze(
345
+ "person@example.com",
346
+ profile="standard",
347
+ company_validity_beta=True,
348
+ )
349
+
350
+ beta = result.company_validity_beta
351
+ if beta is not None:
352
+ print(beta.status) # "beta"
353
+ print(beta.requested) # True
354
+ print(beta.enabled) # True when the feature was active for this request
355
+ print(beta.notes)
356
+
357
+ signal = result.domain_signal
358
+ if signal is not None:
359
+ print(signal.domain_status)
360
+ print(signal.mail_status)
361
+ print(signal.company_valid)
362
+ ```
363
+
364
+ The option is omitted by default, so existing calls retain their current
365
+ behavior. It is available only to paid smtpRS plans and provides additive
366
+ company-domain context rather than an allowlist. It currently adds no credits
367
+ beyond the selected profile. Free-plan requests that explicitly enable it
368
+ receive `PermissionDeniedError`. Because the response contract is beta,
369
+ applications can use `result.to_dict()` to retain access to newly added fields.
370
+
371
+ ## Configuration
372
+
373
+ ```python
374
+ from paravane import ParavaneClient
375
+
376
+ client = ParavaneClient(
377
+ api_key="pvn_live_...",
378
+ base_url="https://api.paravane.io",
379
+ timeout=20.0,
380
+ max_network_retries=1,
381
+ )
382
+ ```
383
+
384
+ Environment variables:
385
+
386
+ | Name | Purpose | Default |
387
+ | --- | --- | --- |
388
+ | `PARAVANE_API_KEY` | API key used for requests. | None |
389
+ | `PARAVANE_BASE_URL` | API base URL. | `https://api.paravane.io` |
390
+
391
+ ## Per-request options
392
+
393
+ You can set a timeout for one request:
394
+
395
+ ```python
396
+ result = client.smtprs.analyze(
397
+ "person@example.com",
398
+ timeout=5.0,
399
+ )
400
+ ```
401
+
402
+ You can pass an idempotency key:
403
+
404
+ ```python
405
+ result = client.smtprs.analyze(
406
+ "person@example.com",
407
+ idempotency_key="signup-check-123",
408
+ )
409
+ ```
410
+
411
+ You can pass future or preview query parameters without waiting for a new SDK release:
412
+
413
+ ```python
414
+ result = client.smtprs.analyze(
415
+ "person@example.com",
416
+ extra_params={"preview_flag": "enabled"},
417
+ )
418
+ ```
419
+
420
+ ## Custom HTTP sessions
421
+
422
+ The SDK uses `requests` by default. If your environment needs custom connection pooling, proxies, certificates, or adapters, pass a configured `requests.Session`:
423
+
424
+ ```python
425
+ import requests
426
+ from paravane import ParavaneClient
427
+
428
+ session = requests.Session()
429
+ session.proxies.update({
430
+ "https": "https://proxy.example.com:8443",
431
+ })
432
+
433
+ client = ParavaneClient(
434
+ api_key="pvn_live_...",
435
+ session=session,
436
+ )
437
+ ```
438
+
439
+ ## Retries
440
+
441
+ By default, the SDK does not retry network calls:
442
+
443
+ ```python
444
+ client = ParavaneClient(max_network_retries=0)
445
+ ```
446
+
447
+ Enable limited retries for transient network failures, `429` rate limits, and `5xx` API responses:
448
+
449
+ ```python
450
+ client = ParavaneClient(max_network_retries=2)
451
+ ```
452
+
453
+ When enabling retries for write-like workflows, pass an idempotency key from your application so repeated attempts can be treated safely by the API:
454
+
455
+ ```python
456
+ result = client.smtprs.analyze(
457
+ "person@example.com",
458
+ idempotency_key="customer-signup-456",
459
+ )
460
+ ```
461
+
462
+ ## Idempotency
463
+
464
+ The SDK accepts an `idempotency_key` and sends it as:
465
+
466
+ ```text
467
+ Idempotency-Key: your-key
468
+ ```
469
+
470
+ Use stable keys for requests that your application may retry after timeouts or transient failures.
471
+
472
+ ## Errors
473
+
474
+ Unsuccessful requests raise structured exceptions from `paravane.errors`.
475
+
476
+ ```python
477
+ from paravane import (
478
+ AuthenticationError,
479
+ ParavaneClient,
480
+ QuotaExceededError,
481
+ RateLimitError,
482
+ ValidationError,
483
+ )
484
+
485
+ client = ParavaneClient()
486
+
487
+ try:
488
+ result = client.smtprs.analyze("person@example.com")
489
+ except AuthenticationError:
490
+ print("Check your API key.")
491
+ except QuotaExceededError:
492
+ print("The workspace has exhausted its available credits.")
493
+ except RateLimitError:
494
+ print("Slow down and retry later.")
495
+ except ValidationError as exc:
496
+ print("Request was invalid:", exc)
497
+ ```
498
+
499
+ Exception classes:
500
+
501
+ | Class | Typical cause |
502
+ | --- | --- |
503
+ | `ConfigurationError` | Missing API key or invalid client setup. |
504
+ | `APIConnectionError` | Network failure, timeout, DNS failure, or connection error. |
505
+ | `APIError` | Generic non-success API response. |
506
+ | `AuthenticationError` | Missing, invalid, or revoked API key. |
507
+ | `PermissionDeniedError` | API key lacks access to the requested resource. |
508
+ | `ValidationError` | Invalid request payload or parameters. |
509
+ | `QuotaExceededError` | Plan or credit quota has been exhausted. |
510
+ | `RateLimitError` | Too many requests. |
511
+
512
+ API errors include useful details when available:
513
+
514
+ ```python
515
+ try:
516
+ client.smtprs.analyze("not-an-email")
517
+ except ValidationError as exc:
518
+ print(exc.status_code)
519
+ print(exc.code)
520
+ print(exc.request_id)
521
+ print(exc.response)
522
+ ```
523
+
524
+ ## Responses and raw data
525
+
526
+ The SDK returns `SmtpRsAnalysis` for smtpRS analysis requests.
527
+
528
+ ```python
529
+ result = client.smtprs.analyze("person@example.com")
530
+ ```
531
+
532
+ Common fields:
533
+
534
+ | Field | Description |
535
+ | --- | --- |
536
+ | `email` | Email address represented by the response, when returned by the API. |
537
+ | `decision` | Customer-facing decision or recommendation, when returned by the API. |
538
+ | `overall_risk` | Overall risk score, when returned by the API. |
539
+ | `tier` | Workspace/API-key tier reflected by the response. |
540
+ | `analysis_profile` | Analysis path used by the API. |
541
+ | `response_profile` | Response shape, such as summary/full. |
542
+ | `credit_cost` | Planned credit cost for the selected profile. |
543
+ | `credits_charged` | Credits recorded for the request, when returned. |
544
+ | `company_validity_beta` | Typed beta status, opt-in state, availability, credit cost, and API notes. |
545
+ | `domain_signal` | Typed domain, mail, and company-context facts when returned. |
546
+ | `reasons` | Human-readable reason strings, when returned. |
547
+ | `usage` | Usage/quota snapshot, when returned. |
548
+ | `raw` | Original API payload. |
549
+
550
+ To avoid losing fields added by the API before the SDK is updated, the full payload is always preserved:
551
+
552
+ ```python
553
+ raw = result.to_dict()
554
+ print(raw["usage"])
555
+ ```
556
+
557
+ ## Types
558
+
559
+ This package includes inline type hints and ships a `py.typed` marker.
560
+
561
+ The response helper is a dataclass:
562
+
563
+ ```python
564
+ from paravane import SmtpRsAnalysis
565
+
566
+ def handle_result(result: SmtpRsAnalysis) -> None:
567
+ print(result.decision)
568
+ signal = result.domain_signal
569
+ if signal is not None:
570
+ print(signal.mail_capable)
571
+ ```
572
+
573
+ Type hints are intended to describe stable SDK behavior. The raw API response may include additional fields that are not represented as first-class dataclass attributes yet.
574
+
575
+ ## Logging
576
+
577
+ The SDK does not install or configure logging handlers. Applications should configure logging at the application boundary.
578
+
579
+ For now, request failures are surfaced through exceptions. If you need detailed HTTP logging during development, configure your own `requests.Session` or enable logging in your HTTP stack.
580
+
581
+ ## Examples
582
+
583
+ This repository includes small examples:
584
+
585
+ ```text
586
+ examples/basic_analyze.py
587
+ examples/strict_analyze.py
588
+ examples/batch_csv.py
589
+ ```
590
+
591
+ Run one with:
592
+
593
+ ```bash
594
+ PARAVANE_API_KEY="pvn_live_..." python examples/basic_analyze.py
595
+ ```
596
+
597
+ Windows PowerShell:
598
+
599
+ ```powershell
600
+ $env:PARAVANE_API_KEY = "pvn_live_..."
601
+ python examples/basic_analyze.py
602
+ ```
603
+
604
+ ## Development
605
+
606
+ Create an environment:
607
+
608
+ ```bash
609
+ python -m venv .venv
610
+ source .venv/bin/activate
611
+ python -m pip install -e ".[dev]"
612
+ ```
613
+
614
+ Windows PowerShell:
615
+
616
+ ```powershell
617
+ python -m venv .venv
618
+ .\.venv\Scripts\Activate.ps1
619
+ python -m pip install -e ".[dev]"
620
+ ```
621
+
622
+ Run tests:
623
+
624
+ ```bash
625
+ pytest
626
+ ```
627
+
628
+ Run lint:
629
+
630
+ ```bash
631
+ ruff check .
632
+ ```
633
+
634
+ Build the package:
635
+
636
+ ```bash
637
+ python -m build
638
+ ```
639
+
640
+ Recommended pre-commit check:
641
+
642
+ ```bash
643
+ pytest && ruff check . && python -m build
644
+ ```
645
+
646
+ ## Repository layout
647
+
648
+ ```text
649
+ paravane-python/
650
+ .github/workflows/ GitHub Actions checks
651
+ examples/ Small runnable examples
652
+ src/paravane/ SDK package source
653
+ tests/ Unit tests
654
+ pyproject.toml Packaging metadata and tool config
655
+ RELEASING.md Maintainer release process
656
+ ```
657
+
658
+ ## Versioning
659
+
660
+ Current package version:
661
+
662
+ ```text
663
+ 0.2.0
664
+ ```
665
+
666
+ The SDK is in an early release phase. Until `1.0.0`, minor versions may refine naming, response helpers, or packaging behavior as the public API settles. Runtime-breaking changes should still be called out clearly in `CHANGELOG.md`.
667
+
668
+ ## Security
669
+
670
+ Do not put API keys in source code, client-side apps, mobile apps, screenshots, or public repositories.
671
+
672
+ Recommended handling:
673
+
674
+ - load API keys from environment variables or a secret manager
675
+ - rotate keys if they are exposed
676
+ - create separate keys for development, staging, and production
677
+ - revoke keys that are no longer needed
678
+
679
+ Report suspected vulnerabilities privately:
680
+
681
+ ```text
682
+ security@paravane.io
683
+ ```
684
+
685
+ ## Support
686
+
687
+ For product or account support:
688
+
689
+ ```text
690
+ contact@paravane.io
691
+ ```
692
+
693
+ For security reports:
694
+
695
+ ```text
696
+ security@paravane.io
697
+ ```