Metadata-Version: 2.4
Name: paynotify
Version: 1.0.1
Summary: Official Python SDK for the PayNotify Webhook Engine
Home-page: https://github.com/paynotify/paynotify-python
Author: PayNotify
Author-email: ayyappanallamothu4@gmail.com
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.7
Classifier: Programming Language :: Python :: 3.8
Classifier: Programming Language :: Python :: 3.9
Classifier: Programming Language :: Python :: 3.10
Classifier: Programming Language :: Python :: 3.11
Classifier: License :: OSI Approved :: MIT License
Classifier: Operating System :: OS Independent
Classifier: Intended Audience :: Developers
Classifier: Topic :: Software Development :: Libraries :: Python Modules
Requires-Python: >=3.7
Description-Content-Type: text/markdown
License-File: LICENSE
Requires-Dist: requests>=2.25.0
Dynamic: author
Dynamic: author-email
Dynamic: classifier
Dynamic: description
Dynamic: description-content-type
Dynamic: home-page
Dynamic: license-file
Dynamic: requires-dist
Dynamic: requires-python
Dynamic: summary

# PayNotify Python SDK

The official Python Server SDK for **PayNotify** — the zero-MDR, automated, lifetime-free UPI payment gateway engine.

Designed for enterprise reliability, this SDK provides seamless integration with the PayNotify architecture, enabling **Dynamic Cent Masking** for payment concurrency management and **Cryptographic HMAC-SHA256 Webhook Verification** using stable string formatting to guarantee bank-grade security against replay and JSON mutation attacks.

---

## ✨ Features

### Dynamic Cent Masking (Penny Drop)

Automatically resolves payment concurrency (for example, multiple users checking out with ₹49 simultaneously) by generating unique fractional amounts through an atomic database lock.

### Cryptographic Webhook Security (Stable String)

Built-in logic validates the `X-PayNotify-Signature` using **HMAC-SHA256**. It securely signs a fixed string template:

```text
orderId:amount:status:timestamp
```

This completely prevents JSON parsing drift vulnerabilities and replay attacks (via a strict 5-minute expiry window).

### Client-Side Idempotency

Prevents duplicate orders and double-charging. The SDK requires you to pass a stable, unique string (like a cart ID or session UUID) during order creation.

---

# Installation

Using pip:

```bash
pip install paynotify
```

---

# Quick Start

## Initialization

Initialize the PayNotify client using your secret API key.

> **Security Warning:** Never expose your API key in frontend or client-side code.

```python
from paynotify import PayNotify

paynotify = PayNotify(api_key="your-secure-api-key")
```

---

## Creating a Payment Order

When a user initiates checkout, create an order on your backend. The SDK communicates with the PayNotify Engine to lock in a concurrency-safe amount.

```python
try {
    order_data = paynotify.create_order(
        base_amount=49.00,
        customer_name="Surya",
        idempotency_key="unique-cart-id-123" # STRICTLY REQUIRED
    )

    # Returns: {'success': True, 'orderId': '...', 'amount': 49.01, 'status': 'PENDING'}
    return jsonify(order_data)

except ValueError as e:
    return jsonify({"error": str(e)}), 400
except Exception as e:
    return jsonify({"error": "Payment Gateway is warming up. Please try again."}), 503
```

---

## Securing Webhooks

PayNotify sends real-time webhooks whenever a payment is verified. Every incoming request must be authenticated before processing.

```python
from flask import Flask, request, jsonify
from paynotify.exceptions import SignatureVerificationError

app = Flask(__name__)

@app.route('/api/webhook', methods=['POST'])
def webhook():
    signature_header = request.headers.get('X-PayNotify-Signature')
    payload = request.json

    try:
        # Automatically verifies signature and prevents replay attacks
        paynotify.verify_webhook(signature_header, payload)
        
        if payload.get('status') == 'VERIFIED':
            # Unlock user content, update database, etc.
            print(f"Payment of {payload.get('amount')} received!")
            return jsonify({'success': True}), 200
            
    except SignatureVerificationError as e:
        return jsonify({'error': str(e)}), 401

    return jsonify({'message': 'Ignored'}), 200
```

---

# API Reference

## `PayNotify(api_key: str, gateway_url: str = "https://paypager.vercel.app")`

Creates a new PayNotify client instance.

---

## `create_order(base_amount: float, customer_name: str, idempotency_key: str) -> Dict[str, Any]`

Creates a new payment order atomically.

### Parameters

| Parameter         | Type     | Required | Description                                                                               |
| ----------------- | -------- | -------- | ----------------------------------------------------------------------------------------- |
| `base_amount`     | `float`  | ✅        | Original payment amount                                                                   |
| `customer_name`   | `str`    | ✅        | Customer name shown in dashboards                                                         |
| `idempotency_key` | `str`    | ✅        | Prevents duplicate orders during retries. Must be a unique string per transaction.        |

---

## `verify_webhook(signature_header: str, payload: Dict[str, Any], tolerance_seconds: int = 300) -> bool`

Validates webhook signatures using the stable string format: `orderId:amount:status:timestamp`

* Verifies `X-PayNotify-Signature` using HMAC-SHA256
* Prevents replay attacks using `tolerance_seconds` (defaults to 5 minutes)
* Throws `SignatureVerificationError` on failure

---

# Security Best Practices

* Never expose API keys in frontend applications.
* Always verify webhook signatures using the SDK.
* Store `orderId` and assigned payment amounts in your database.
* Process only payments with status `VERIFIED`.
* Use HTTPS in all production environments.

---

# License

MIT License.

```text
Copyright (c) PayNotify.
```
