Metadata-Version: 2.4
Name: paspoid
Version: 0.1.3
Summary: Official Python SDK for the paspo.id Server API
Author-email: Daniyar Kalmanbetov <info@pingocean.com>
License-Expression: MIT
Classifier: Development Status :: 3 - Alpha
Classifier: Intended Audience :: Developers
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.10
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Programming Language :: Python :: 3.13
Classifier: Topic :: Software Development :: Libraries :: Python Modules
Requires-Python: >=3.10
Description-Content-Type: text/markdown
License-File: LICENSE
Requires-Dist: requests<3,>=2.31
Provides-Extra: dev
Requires-Dist: build<2,>=1.2; extra == "dev"
Requires-Dist: bump-my-version<1,>=0.27; extra == "dev"
Requires-Dist: pre-commit<5,>=3.7; extra == "dev"
Requires-Dist: ruff<1,>=0.6; extra == "dev"
Requires-Dist: twine<7,>=5; extra == "dev"
Dynamic: license-file

# paspo.id Server API Python SDK

The official Python SDK for integrating a trusted backend with the
**paspo.id Server API**.

It provides a small synchronous API for obtaining a transaction key and
checking that transaction once.

## Installation

```bash
pip install paspoid
```

Python 3.10 or newer is required.

## Quick start

```python
from paspoid import Client

with Client(
    base_url="https://paspo.id",
    api_key="YOUR_API_KEY",
    api_secret="YOUR_API_SECRET",
) as client:
    key_response = client.get_key(
        service_public_id="YOUR_SERVICE_PUBLIC_ID",
        transaction_type="phones",
    )

    print("key:", key_response.key)
    print("validation_window:", key_response.validation_window)

    validation = client.validate(nonce=key_response.key)
    print("status:", validation.status)
    print("data_type:", validation.data_type)
    print("data_value:", validation.data_value)
```

Keep `api_key` and `api_secret` on the backend. Never embed them in browser or
mobile applications.

## API

### `Client`

```python
Client(
    base_url: str,
    api_key: str,
    api_secret: str,
    *,
    timeout: float = 15.0,
    session: requests.Session | None = None,
)
```

The client reuses an HTTP session and can be closed with `close()` or used as a
context manager. A caller-provided session is reused but remains owned by the
caller and is not closed by the SDK.

### `get_key`

```python
client.get_key(
    service_public_id: str,
    transaction_type: str,
) -> GetKeyResponse
```

Supported transaction types:

- `phones`
- `emails`
- `national_id`
- `pasport_id`
- `transaction_verify`
- `second_factor`

The response contains:

| Field | Type | Description |
| --- | --- | --- |
| `key` | `str` | One-time transaction key (nonce). |
| `validation_window` | `str` | Key lifetime, for example `30s`. |

### `validate`

```python
client.validate(nonce: str) -> ValidateResponse
```

This method sends exactly one validation request. The SDK does not poll or
retry automatically.

The response contains:

| Field | Type | Description |
| --- | --- | --- |
| `status` | `str` | Current validation status. |
| `data_type` | `str \| None` | Type of verified data, when available. |
| `data_value` | `str \| None` | Verified value, when available. |
| `phone_data` | `Any \| None` | Extended phone/SIM JSON data. |
| `device_data` | `Any \| None` | Device JSON data. |

Possible `status` values:

- `incomplete` — the transaction has not been completed yet;
- `success` — the transaction completed successfully;
- `failed` — the transaction failed, expired, or was not found.

If an application needs polling, it should schedule subsequent `validate`
calls itself and stop before `validation_window` expires.

## Integration flow

```mermaid
sequenceDiagram
    autonumber
    participant Backend as Integrator Backend
    participant SDK as paspo.id Python SDK
    participant API as paspo.id API

    Backend->>SDK: Client(base_url, api_key, api_secret)
    Backend->>SDK: get_key(service_public_id, transaction_type)
    SDK->>API: POST /v1/ext/get-key
    API-->>SDK: key + validation_window
    SDK-->>Backend: GetKeyResponse

    Backend->>SDK: validate(nonce)
    SDK->>API: POST /v1/ext/validate
    API-->>SDK: status + optional verified data
    SDK-->>Backend: ValidateResponse
```

## Errors

All SDK errors inherit from `PaspoidError`:

- `ConfigurationError` — invalid client settings;
- `RequestValidationError` — invalid method arguments;
- `TransportError` — connection, TLS, or timeout failure;
- `ApiError` — non-2xx API response; exposes `status_code`,
  `response_body`, and `endpoint`;
- `DecodeError` — malformed or unexpected response;
- `ResponseTooLargeError` — response exceeds the 1 MiB safety limit.

```python
from paspoid import ApiError, PaspoidError

try:
    result = client.validate(nonce="...")
except ApiError as error:
    print(error.status_code, error.response_body)
except PaspoidError as error:
    print(error)
```

## Environment variables

The SDK accepts explicit constructor arguments and does not load `.env` files.
Applications may use the variables shown in
[`.env.example`](.env.example):

```env
PASPOID_BASE_URL=https://paspo.id
PASPOID_API_KEY=your_api_key_here
PASPOID_API_SECRET=your_api_secret_here
PASPOID_SERVICE_PUBLIC_ID=your_service_public_id
PASPOID_TRANSACTION_TYPE=phones
```

Run the bundled example after exporting those values:

```bash
python examples/basic.py
```

## Development

```bash
python -m unittest discover -s tests
make lint
make format
make build
```

The package uses a `src` layout and separates its public client, application
contracts/use cases, and REST adapter. See
[`.agent/ARCHITECTURE.md`](.agent/ARCHITECTURE.md) for the contributor
cheat sheet.

## License

Distributed under the MIT License. See [LICENSE](LICENSE).
