Metadata-Version: 2.4
Name: paymenthub
Version: 0.1.0
Summary: Typed Python client + webhook verification for the PaymentHub API.
Project-URL: Repository, https://github.com/ahmeddmohamed-noon/paymenthub-sdk-python
Author: PaymentHub
License-Expression: MIT
Keywords: paymenthub,payments,paymob,sdk,stripe
Requires-Python: >=3.10
Requires-Dist: httpx>=0.27
Requires-Dist: pydantic[email]>=2.7
Provides-Extra: dev
Requires-Dist: datamodel-code-generator>=0.26; extra == 'dev'
Requires-Dist: mypy>=1.11; extra == 'dev'
Requires-Dist: pytest>=8; extra == 'dev'
Requires-Dist: ruff>=0.7; extra == 'dev'
Description-Content-Type: text/markdown

# paymenthub (Python SDK)

Typed Python client + webhook verification for the [PaymentHub](https://github.com/ahmeddmohamed-noon/paymenthub-be) API. Models are generated from PaymentHub's published OpenAPI spec with `datamodel-code-generator`, so responses are validated pydantic models.

> Sandbox-only portfolio project.

## Install

```bash
pip install paymenthub
```

## Quickstart

```python
from paymenthub import PaymentHubClient, PaymentCreate

with PaymentHubClient(api_key="sk_test_…") as ph:
    # One-call sandbox bootstrap (test-mode keys only):
    demo = ph.seed_sandbox()  # -> SandboxSeedResponse(api_key, merchant_id, sample_payment_ids)

    payment = ph.create_payment(PaymentCreate(
        amount_minor=1500,
        currency="USD",
        success_url="https://example.com/success",
        cancel_url="https://example.com/cancel",
    ))
    print(payment.checkout_url)

    detail = ph.get_payment(payment.id)
```

`PaymentHubClient` defaults to the hosted gateway; pass `base_url=` to point elsewhere, or `http_client=` to inject a custom/mocked `httpx.Client`.

## Webhook verification

Verify the **raw** request body server-side (don't re-serialize):

```python
from paymenthub import verify_webhook

ok = verify_webhook(
    provider="stripe",        # or "paymob"
    payload=raw_body,         # str | bytes
    signature=request.headers["x-paymenthub-signature"],
    secret=WEBHOOK_SECRET,
)
```

- **Stripe-style** (`verify_stripe_signature`): `t=<unix>,v1=<hex>` header; HMAC-SHA256 over `f"{t}.{body}"` with a replay tolerance (default 5 min).
- **Paymob-style** (`verify_paymob_hmac`): raw HMAC-SHA256 hex digest over the body.

All comparisons use `hmac.compare_digest` (constant-time).

## Development

```bash
uv run --extra dev ruff check .
uv run --extra dev mypy src
uv run --extra dev pytest
uv build
```

Models live in `src/paymenthub/_models.py`, generated from the vendored `openapi.json`:

```bash
uv run --with datamodel-code-generator datamodel-codegen \
  --input openapi.json --input-file-type openapi \
  --output src/paymenthub/_models.py \
  --output-model-type pydantic_v2.BaseModel \
  --target-python-version 3.10 --use-standard-collections --use-union-operator
```

Refresh `openapi.json` from the backend and re-run when the API changes.

## Releasing

`release.yml` publishes to PyPI on a `v*` tag (or a `repository_dispatch` from the backend) via **Trusted Publishing (OIDC)** — no token stored. It runs the test suite and **completes a sandbox payment against prod** before publishing. Configure a PyPI trusted publisher for this repo + workflow, and add a `PAYMENTHUB_TEST_KEY` repo secret for the smoke test.
