diff --git a/README.md b/README.md index ffb8428..deed525 100644 --- a/README.md +++ b/README.md @@ -42,6 +42,8 @@ pip install django-nepali-payment ## Highlights +

Why you'll love it.

+ - **One shape for every gateway**: every call returns a `PaymentResult`. - **Signatures that just work**: reproduced from each provider's reference: - eSewa: HMAC-SHA256 (base64) @@ -57,6 +59,8 @@ pip install django-nepali-payment ## Architecture +

Simple by design. Three layers, total.

+ Three small layers, all usable directly: - **`PaymentManager`**: the entry point. Pick gateway, mode, secret once; call @@ -69,6 +73,8 @@ Three small layers, all usable directly: ## Quick start +

Your first payment in seconds.

+ ```python from nepali_payment import PaymentManager, PaymentMethod, PaymentMode, PaymentResult @@ -122,6 +128,8 @@ connections on shutdown. ## Initiate a payment +

Same call, every gateway.

+ ```python manager.initiate_payment(PaymentResult, request) ``` @@ -183,6 +191,8 @@ The dynamic QR bakes the amount in; settlement is async, so pair it with the ## Fonepay Static QR +

Set it once, scan forever.

+ One fixed merchant QR; the customer types the amount at scan. Fetch once per station: @@ -204,6 +214,8 @@ if result.success: ## ConnectIPS +

Bank-grade signing, dead-simple form.

+ A **form POST** gateway signed with **SHA256withRSA** using a merchant certificate (`.pfx`, `.p12` or `.pem`). Instead of a secret key it takes a config object: @@ -267,6 +279,8 @@ if result.success: ## Verify a payment +

One call to confirm it's real.

+ Same call everywhere, only the argument differs: ```python @@ -289,6 +303,8 @@ result = manager.verify_payment(PaymentResult, base64_response) ## Errors +

Failures are data. Bugs are loud.

+ Two kinds, kept separate: **1. Gateway failures return a failed `PaymentResult`**: no exception, so @@ -327,6 +343,8 @@ comes back as a `PaymentResult`; if it's a bug in your call, it raises. ## Handling callbacks safely +

Never trust the query string. Always verify.

+ - **Verify server-side, don't trust the query string.** The `pidx` (Khalti) or `data` (eSewa) is only an identifier; always round-trip through `manager.verify_payment`. For ConnectIPS, pass the params _and_ the expected @@ -342,6 +360,8 @@ comes back as a `PaymentResult`; if it's a bug in your call, it raises. ## Fonepay QR status monitoring +

Know the moment it settles.

+ Settlement is async, so poll for it with plain **HTTP polling**, shared-hosting safe: @@ -391,12 +411,16 @@ monitor.dispose() # stop all, release session ### Why polling, not WebSockets? +Shared hosting said no. We said fine. + Shared hosting forbids persistent connections, daemons and async loops. The monitoring thread needs none of these; it is plain HTTPS on the shared `requests.Session`. Dependency-light, synchronous, deploys cleanly. ## See it in action +

Wired up, ready to run.

+ A runnable Django app in [`examples/`](examples/) wires every gateway into real views, an `Order` model, provider callbacks and a Fonepay background monitor: @@ -415,6 +439,8 @@ Defaults to sandbox; credentials come from env vars. See ## Development +

One command to get going.

+ Tooling via [uv](https://docs.astral.sh/uv/): ```bash @@ -427,6 +453,8 @@ NEPALI_PAYMENT_ESEWA_SECRET=... ... uv run pytest tests/test_live_api.py -v ## Contributing +

PRs welcome, big or small.

+ Contributions are welcome. Open an issue or submit a PR. 1. Fork the repo