bitsopay 0.1.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.
Files changed (55) hide show
  1. bitsopay-0.1.0/CHANGELOG.md +33 -0
  2. bitsopay-0.1.0/CODE_OF_CONDUCT.md +103 -0
  3. bitsopay-0.1.0/CONTRIBUTING.md +47 -0
  4. bitsopay-0.1.0/LICENSE +21 -0
  5. bitsopay-0.1.0/MANIFEST.in +8 -0
  6. bitsopay-0.1.0/PKG-INFO +234 -0
  7. bitsopay-0.1.0/README.md +193 -0
  8. bitsopay-0.1.0/SECURITY.md +44 -0
  9. bitsopay-0.1.0/deploy/.env.example +9 -0
  10. bitsopay-0.1.0/deploy/bitsopay.service +21 -0
  11. bitsopay-0.1.0/deploy/gunicorn.conf.py +16 -0
  12. bitsopay-0.1.0/deploy/nginx.conf +31 -0
  13. bitsopay-0.1.0/docs/api.md +52 -0
  14. bitsopay-0.1.0/docs/architecture.md +37 -0
  15. bitsopay-0.1.0/docs/cli.md +20 -0
  16. bitsopay-0.1.0/docs/deployment.md +39 -0
  17. bitsopay-0.1.0/docs/releasing.md +31 -0
  18. bitsopay-0.1.0/docs/security-model.md +34 -0
  19. bitsopay-0.1.0/docs/usage.md +70 -0
  20. bitsopay-0.1.0/examples/basic_qr.py +13 -0
  21. bitsopay-0.1.0/examples/embed_in_wsgi.py +13 -0
  22. bitsopay-0.1.0/examples/short_links.py +14 -0
  23. bitsopay-0.1.0/pyproject.toml +101 -0
  24. bitsopay-0.1.0/setup.cfg +4 -0
  25. bitsopay-0.1.0/src/bitsopay/__init__.py +64 -0
  26. bitsopay-0.1.0/src/bitsopay/__main__.py +6 -0
  27. bitsopay-0.1.0/src/bitsopay/cli.py +245 -0
  28. bitsopay-0.1.0/src/bitsopay/exceptions.py +31 -0
  29. bitsopay-0.1.0/src/bitsopay/link.py +122 -0
  30. bitsopay-0.1.0/src/bitsopay/models.py +57 -0
  31. bitsopay-0.1.0/src/bitsopay/page.py +133 -0
  32. bitsopay-0.1.0/src/bitsopay/py.typed +0 -0
  33. bitsopay-0.1.0/src/bitsopay/qr.py +87 -0
  34. bitsopay-0.1.0/src/bitsopay/ratelimit.py +69 -0
  35. bitsopay-0.1.0/src/bitsopay/server.py +520 -0
  36. bitsopay-0.1.0/src/bitsopay/session.py +67 -0
  37. bitsopay-0.1.0/src/bitsopay/shortlink.py +172 -0
  38. bitsopay-0.1.0/src/bitsopay/stateless.py +181 -0
  39. bitsopay-0.1.0/src/bitsopay/store.py +277 -0
  40. bitsopay-0.1.0/src/bitsopay/upi.py +47 -0
  41. bitsopay-0.1.0/src/bitsopay/validators.py +86 -0
  42. bitsopay-0.1.0/src/bitsopay.egg-info/PKG-INFO +234 -0
  43. bitsopay-0.1.0/src/bitsopay.egg-info/SOURCES.txt +53 -0
  44. bitsopay-0.1.0/src/bitsopay.egg-info/dependency_links.txt +1 -0
  45. bitsopay-0.1.0/src/bitsopay.egg-info/entry_points.txt +2 -0
  46. bitsopay-0.1.0/src/bitsopay.egg-info/requires.txt +12 -0
  47. bitsopay-0.1.0/src/bitsopay.egg-info/top_level.txt +1 -0
  48. bitsopay-0.1.0/tests/conftest.py +82 -0
  49. bitsopay-0.1.0/tests/test_bitsopay.py +256 -0
  50. bitsopay-0.1.0/tests/test_cli_and_core_extra.py +140 -0
  51. bitsopay-0.1.0/tests/test_http_integration.py +94 -0
  52. bitsopay-0.1.0/tests/test_ratelimit.py +39 -0
  53. bitsopay-0.1.0/tests/test_server_hardening.py +258 -0
  54. bitsopay-0.1.0/tests/test_shortlink.py +274 -0
  55. bitsopay-0.1.0/tests/test_stateless.py +232 -0
@@ -0,0 +1,33 @@
1
+ # Changelog
2
+
3
+ All notable changes are documented here. The format follows [Keep a Changelog](https://keepachangelog.com/en/1.1.0/)
4
+ and the project uses [Semantic Versioning](https://semver.org/).
5
+
6
+ ## [Unreleased]
7
+
8
+ ## [0.1.0] - 2026-11-14
9
+
10
+ First release, by Bitsophia.
11
+
12
+ ### Added
13
+ - `/ready` readiness probe; `X-Request-ID` propagation; structured request logging (`bitsopay.server` logger).
14
+ - Security headers on every response: `Content-Security-Policy`, HSTS (over HTTPS), `Permissions-Policy`,
15
+ `Cross-Origin-*`.
16
+ - Admin brute-force throttling (`bitsopay.ratelimit.FailureLimiter`, `429` + `Retry-After`).
17
+ - `BITSOPAY_TRUST_PROXY` and `BITSOPAY_LOG_LEVEL` settings; `HEAD` support.
18
+ - `python -m bitsopay`, `bitsopay --version`; `SQLiteStore` and the server app are context managers (`close()`).
19
+ - Full documentation set, Dockerfile, CI, CodeQL and PyPI Trusted Publishing workflows.
20
+
21
+ ### Changed
22
+ - `server.py` rewritten with strict typing; unhandled errors now return a generic 500 with a request id.
23
+ - A short `BITSOPAY_SECRET` now fails at startup instead of at the first request.
24
+ - Package metadata, `py.typed`, `ruff` and `mypy --strict` configuration.
25
+
26
+ ### Fixed
27
+ - `limit=-1` on the history endpoint returned every row (SQLite treats a negative `LIMIT` as unlimited); paging
28
+ parameters are now validated (400).
29
+ - Non-integer `expires_in` in the API caused a 500; it is now a 400.
30
+ - SQLite connections opened by the CLI were never closed.
31
+
32
+ [Unreleased]: https://github.com/Sudharsansm/Bitsopay/compare/v0.1.0...HEAD
33
+ [0.1.0]: https://github.com/Sudharsansm/Bitsopay/releases/tag/v0.1.0
@@ -0,0 +1,103 @@
1
+ # Contributor Covenant Code of Conduct
2
+
3
+ ## Our Pledge
4
+
5
+ We as members, contributors, and leaders pledge to make participation in our community a harassment-free
6
+ experience for everyone, regardless of age, body size, visible or invisible disability, ethnicity, sex
7
+ characteristics, gender identity and expression, level of experience, education, socio-economic status,
8
+ nationality, personal appearance, race, caste, color, religion, or sexual identity and orientation.
9
+
10
+ We pledge to act and interact in ways that contribute to an open, welcoming, diverse, inclusive, and healthy
11
+ community.
12
+
13
+ ## Our Standards
14
+
15
+ Examples of behavior that contributes to a positive environment for our community include:
16
+
17
+ * Demonstrating empathy and kindness toward other people
18
+ * Being respectful of differing opinions, viewpoints, and experiences
19
+ * Giving and gracefully accepting constructive feedback
20
+ * Accepting responsibility and apologizing to those affected by our mistakes, and learning from the experience
21
+ * Focusing on what is best not just for us as individuals, but for the overall community
22
+
23
+ Examples of unacceptable behavior include:
24
+
25
+ * The use of sexualized language or imagery, and sexual attention or advances of any kind
26
+ * Trolling, insulting or derogatory comments, and personal or political attacks
27
+ * Public or private harassment
28
+ * Publishing others' private information, such as a physical or email address, without their explicit permission
29
+ * Other conduct which could reasonably be considered inappropriate in a professional setting
30
+
31
+ ## Enforcement Responsibilities
32
+
33
+ Community leaders are responsible for clarifying and enforcing our standards of acceptable behavior and will take
34
+ appropriate and fair corrective action in response to any behavior that they deem inappropriate, threatening,
35
+ offensive, or harmful.
36
+
37
+ Community leaders have the right and responsibility to remove, edit, or reject comments, commits, code, wiki edits,
38
+ issues, and other contributions that are not aligned to this Code of Conduct, and will communicate reasons for
39
+ moderation decisions when appropriate.
40
+
41
+ ## Scope
42
+
43
+ This Code of Conduct applies within all community spaces, and also applies when an individual is officially
44
+ representing the community in public spaces. Examples of representing our community include using an official email
45
+ address, posting via an official social media account, or acting as an appointed representative at an online or
46
+ offline event.
47
+
48
+ ## Enforcement
49
+
50
+ Instances of abusive, harassing, or otherwise unacceptable behavior may be reported to the community leaders
51
+ responsible for enforcement by opening a **private** report through GitHub
52
+ ([Security → Report a vulnerability](https://github.com/Sudharsansm/Bitsopay/security/advisories/new), marked as a
53
+ conduct report) or by contacting the maintainer [@Sudharsansm](https://github.com/Sudharsansm) through their GitHub
54
+ profile. All complaints will be reviewed and investigated promptly and fairly.
55
+
56
+ All community leaders are obligated to respect the privacy and security of the reporter of any incident.
57
+
58
+ ## Enforcement Guidelines
59
+
60
+ Community leaders will follow these Community Impact Guidelines in determining the consequences for any action they
61
+ deem in violation of this Code of Conduct:
62
+
63
+ ### 1. Correction
64
+
65
+ **Community Impact**: Use of inappropriate language or other behavior deemed unprofessional or unwelcome in the
66
+ community.
67
+
68
+ **Consequence**: A private, written warning from community leaders, providing clarity around the nature of the
69
+ violation and an explanation of why the behavior was inappropriate. A public apology may be requested.
70
+
71
+ ### 2. Warning
72
+
73
+ **Community Impact**: A violation through a single incident or series of actions.
74
+
75
+ **Consequence**: A warning with consequences for continued behavior. No interaction with the people involved,
76
+ including unsolicited interaction with those enforcing the Code of Conduct, for a specified period of time. This
77
+ includes avoiding interactions in community spaces as well as external channels like social media. Violating these
78
+ terms may lead to a temporary or permanent ban.
79
+
80
+ ### 3. Temporary Ban
81
+
82
+ **Community Impact**: A serious violation of community standards, including sustained inappropriate behavior.
83
+
84
+ **Consequence**: A temporary ban from any sort of interaction or public communication with the community for a
85
+ specified period of time. No public or private interaction with the people involved, including unsolicited
86
+ interaction with those enforcing the Code of Conduct, is allowed during this period. Violating these terms may lead
87
+ to a permanent ban.
88
+
89
+ ### 4. Permanent Ban
90
+
91
+ **Community Impact**: Demonstrating a pattern of violation of community standards, including sustained inappropriate
92
+ behavior, harassment of an individual, or aggression toward or disparagement of classes of individuals.
93
+
94
+ **Consequence**: A permanent ban from any sort of public interaction within the community.
95
+
96
+ ## Attribution
97
+
98
+ This Code of Conduct is adapted from the [Contributor Covenant](https://www.contributor-covenant.org), version 2.1,
99
+ available at <https://www.contributor-covenant.org/version/2/1/code_of_conduct.html>.
100
+
101
+ Community Impact Guidelines were inspired by [Mozilla's code of conduct enforcement ladder](https://github.com/mozilla/diversity).
102
+
103
+ For answers to common questions about this code of conduct, see the FAQ at <https://www.contributor-covenant.org/faq>.
@@ -0,0 +1,47 @@
1
+ # Contributing to Bitsopay
2
+
3
+ Thanks for helping! Bitsopay is a small, security-sensitive library, so we value focused changes with tests.
4
+ By taking part you agree to follow the [Code of Conduct](CODE_OF_CONDUCT.md).
5
+
6
+ ## Ways to contribute
7
+
8
+ - **Report a bug** or **request a feature** via [issues](https://github.com/Sudharsansm/Bitsopay/issues) (use the templates).
9
+ - **Security problems**: do not file an issue; follow [SECURITY.md](SECURITY.md).
10
+ - **Improve docs**: typos, clearer examples and deployment notes are always welcome.
11
+ - **Send a pull request**: for anything larger than a small fix, open an issue first so we can agree on the approach.
12
+
13
+ ## Development setup
14
+
15
+ ```bash
16
+ git clone https://github.com/<you>/Bitsopay && cd Bitsopay
17
+ python -m venv .venv && . .venv/bin/activate
18
+ pip install -e ".[dev]"
19
+ pre-commit install # optional: runs ruff on commit (pip install pre-commit)
20
+ ```
21
+
22
+ ## Before you open a PR
23
+
24
+ ```bash
25
+ make check # = ruff check + ruff format --check + mypy --strict + pytest (coverage gate 92%)
26
+ ```
27
+
28
+ - Add or update **tests** for every behavior change; bug fixes need a test that fails without the fix.
29
+ - Keep the package at **one runtime dependency** (`segno`). New dependencies need a strong justification.
30
+ - Keep Python **3.9** compatibility (CI runs 3.9 to 3.13).
31
+ - Public API changes need docstrings, docs updates and a `CHANGELOG.md` entry under **Unreleased**.
32
+ - Never log or return secrets, amounts or UPI IDs on public routes.
33
+
34
+ ## Pull request guidelines
35
+
36
+ 1. Branch from `main`; one logical change per PR.
37
+ 2. Write a clear description: what, why, and how you tested.
38
+ 3. Use [Conventional Commits](https://www.conventionalcommits.org/) style subjects (`fix:`, `feat:`, `docs:`, `test:`, `chore:`).
39
+ 4. CI must be green. A maintainer will review; please respond to feedback and keep the PR up to date.
40
+
41
+ ## Releasing
42
+
43
+ Maintainers only; see [docs/releasing.md](docs/releasing.md).
44
+
45
+ ## License
46
+
47
+ Contributions are licensed under the project's [MIT license](LICENSE).
bitsopay-0.1.0/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Bitsophia
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,8 @@
1
+ include LICENSE README.md CHANGELOG.md SECURITY.md CODE_OF_CONDUCT.md CONTRIBUTING.md
2
+ recursive-include src/bitsopay py.typed
3
+ recursive-include docs *.md
4
+ recursive-include examples *.py
5
+ recursive-include deploy *
6
+ include tests/*.py
7
+ prune assets
8
+ global-exclude __pycache__ *.py[cod] .DS_Store
@@ -0,0 +1,234 @@
1
+ Metadata-Version: 2.4
2
+ Name: bitsopay
3
+ Version: 0.1.0
4
+ Summary: Dynamic UPI QR codes and tamper-proof payment links from a UPI ID and amount. Zero-gateway, merchant-verified payments.
5
+ Author: Bitsophia
6
+ Maintainer: Bitsophia
7
+ License-Expression: MIT
8
+ Project-URL: Homepage, https://github.com/Sudharsansm/Bitsopay
9
+ Project-URL: Documentation, https://github.com/Sudharsansm/Bitsopay/tree/main/docs
10
+ Project-URL: Repository, https://github.com/Sudharsansm/Bitsopay
11
+ Project-URL: Issues, https://github.com/Sudharsansm/Bitsopay/issues
12
+ Project-URL: Changelog, https://github.com/Sudharsansm/Bitsopay/blob/main/CHANGELOG.md
13
+ Project-URL: Security, https://github.com/Sudharsansm/Bitsopay/security/policy
14
+ Keywords: upi,qr,qr-code,payments,india,payment-link,bhim,gpay,phonepe,paytm,fintech,wsgi,bitsophia
15
+ Classifier: Development Status :: 4 - Beta
16
+ Classifier: Intended Audience :: Developers
17
+ Classifier: Intended Audience :: Financial and Insurance Industry
18
+ Classifier: Operating System :: OS Independent
19
+ Classifier: Programming Language :: Python :: 3
20
+ Classifier: Programming Language :: Python :: 3 :: Only
21
+ Classifier: Programming Language :: Python :: 3.11
22
+ Classifier: Programming Language :: Python :: 3.12
23
+ Classifier: Programming Language :: Python :: 3.13
24
+ Classifier: Topic :: Office/Business :: Financial :: Point-Of-Sale
25
+ Classifier: Topic :: Internet :: WWW/HTTP :: WSGI :: Application
26
+ Classifier: Typing :: Typed
27
+ Requires-Python: >=3.11
28
+ Description-Content-Type: text/markdown
29
+ License-File: LICENSE
30
+ Requires-Dist: segno<2,>=1.6
31
+ Provides-Extra: server
32
+ Requires-Dist: gunicorn>=22; extra == "server"
33
+ Provides-Extra: dev
34
+ Requires-Dist: pytest>=7; extra == "dev"
35
+ Requires-Dist: pytest-cov>=5; extra == "dev"
36
+ Requires-Dist: ruff==0.15.22; extra == "dev"
37
+ Requires-Dist: mypy==1.19.1; extra == "dev"
38
+ Requires-Dist: build>=1.2; extra == "dev"
39
+ Requires-Dist: twine>=5; extra == "dev"
40
+ Dynamic: license-file
41
+
42
+ <p align="center">
43
+ <img src="https://raw.githubusercontent.com/Sudharsansm/Bitsopay/main/assets/bitsopay-logo.png" alt="Bitsopay" width="420">
44
+ </p>
45
+
46
+ <p align="center"><b>Dynamic UPI QR codes and tamper-proof payment links, with no payment gateway.</b></p>
47
+
48
+ <p align="center">
49
+ <a href="https://pypi.org/project/bitsopay/"><img alt="PyPI" src="https://img.shields.io/pypi/v/bitsopay?label=PyPI&color=blue"></a>
50
+ <a href="https://github.com/Sudharsansm/Bitsopay/blob/main/pyproject.toml"><img alt="Python 3.11+" src="https://img.shields.io/badge/python-3.11%20%7C%203.12%20%7C%203.13-blue.svg"></a>
51
+ <a href="https://github.com/Sudharsansm/Bitsopay/actions/workflows/ci.yml"><img alt="CI" src="https://github.com/Sudharsansm/Bitsopay/actions/workflows/ci.yml/badge.svg"></a>
52
+ <a href="LICENSE"><img alt="License: MIT" src="https://img.shields.io/badge/license-MIT-blue.svg"></a>
53
+ <a href="https://docs.astral.sh/ruff/"><img alt="Ruff" src="https://img.shields.io/badge/lint-ruff-261230.svg"></a>
54
+ <img alt="Typed" src="https://img.shields.io/badge/typing-strict-2a6db2.svg">
55
+ </p>
56
+
57
+ <p align="center">
58
+ <a href="README.md">README</a> ·
59
+ <a href="CODE_OF_CONDUCT.md">Code of conduct</a> ·
60
+ <a href="CONTRIBUTING.md">Contributing</a> ·
61
+ <a href="LICENSE">MIT license</a> ·
62
+ <a href="SECURITY.md">Security</a>
63
+ </p>
64
+
65
+ ---
66
+
67
+ ## About
68
+
69
+ **Bitsopay** turns a UPI ID and an amount into a QR code or a shareable payment link. The customer scans
70
+ it with any UPI app (GPay, PhonePe, Paytm, BHIM, and others) and the amount is already filled in. Money goes
71
+ straight to *your* UPI ID.
72
+
73
+ It is a framework developed by **[Bitsophia](https://github.com/Sudharsansm)**, in the same family as
74
+ [Bitscrape](https://github.com/Sudharsansm/Bitscrape).
75
+
76
+ > **Bitsopay is not a payment gateway.** It never sees or moves money, and it cannot detect that a customer
77
+ > has paid. You confirm the payment in your bank or UPI app, then record it with `mark_paid`. In exchange there are
78
+ > no API keys, no gateway fees and no KYC with a third party.
79
+
80
+ ## Features
81
+
82
+ - **QR from UPI ID + amount**: PNG, SVG or base64 data URI, with validated UPI IDs, `Decimal` amounts, notes and references.
83
+ - **Three kinds of payment link**:
84
+ - *Short links with history*: the URL holds only a reference; UPI ID and amount stay on your server (SQLite or your own store).
85
+ - *Database-free short links*: amount and expiry are encrypted and signed inside the URL.
86
+ - *Signed links*: HMAC-SHA256 with expiry, for existing sites.
87
+ - **Payment page**: mobile-friendly, QR, UPI app buttons, live countdown, no external requests.
88
+ - **Production WSGI server**: merchant API, `/health` and `/ready` probes, security headers (CSP, HSTS), request IDs,
89
+ structured logging, admin brute-force throttling.
90
+ - **CLI** for scripting and operations.
91
+ - **One dependency** ([`segno`](https://pypi.org/project/segno/), pure Python). Python 3.11+. Fully typed (`mypy --strict`).
92
+
93
+ ## Install
94
+
95
+ ```bash
96
+ pip install bitsopay # library + CLI
97
+ pip install "bitsopay[server]" # plus gunicorn for production serving
98
+ ```
99
+
100
+ ## Quick start
101
+
102
+ ### 1. A QR code
103
+
104
+ ```python
105
+ from bitsopay import UPIPayment, new_reference, save_qr, qr_data_uri
106
+
107
+ pay = UPIPayment(
108
+ upi_id="shop@okhdfcbank",
109
+ payee_name="My Shop",
110
+ amount=499, # None lets the customer type the amount
111
+ note="Order 1042",
112
+ reference=new_reference(), # use it to match the payment when you verify
113
+ )
114
+ pay.uri # upi://pay?pa=shop@okhdfcbank&pn=My%20Shop&am=499.00&cu=INR&...
115
+ save_qr(pay, "order-1042.png") # or .svg
116
+ html_src = qr_data_uri(pay) # <img src="...">
117
+ ```
118
+
119
+ ### 2. Short links with payment history
120
+
121
+ ```python
122
+ from bitsopay import PaymentLinks, SQLiteStore
123
+
124
+ with SQLiteStore("payments.db") as store:
125
+ links = PaymentLinks(store, "https://pay.example.com")
126
+ link = links.create("shop@okhdfcbank", "My Shop", 499, note="Order 1042", expires_in=3600)
127
+ print(link.url) # https://pay.example.com/p/BP684BF1555E4B4907 -> send to the customer
128
+ link.save("link-qr.png")
129
+
130
+ # after YOU confirmed the money in your bank / UPI app:
131
+ links.mark_paid(link.reference, note="UTR 4123...")
132
+ links.history(status="pending", limit=20) # paid | pending | cancelled | expired
133
+ ```
134
+
135
+ ### 3. Database-free links
136
+
137
+ ```python
138
+ from bitsopay import StatelessLinks
139
+
140
+ links = StatelessLinks("shop@okhdfcbank", "My Shop", secret=SECRET, base_url="https://pay.example.com")
141
+ link = links.create(499, expires_in=3600)
142
+ link.url
143
+ ```
144
+
145
+ More in [docs/usage.md](docs/usage.md) and [`examples/`](examples).
146
+
147
+ ## Run the server
148
+
149
+ ```bash
150
+ pip install "bitsopay[server]"
151
+ export BITSOPAY_DB=/var/lib/bitsopay/payments.db
152
+ export BITSOPAY_ADMIN_TOKEN="$(python -c 'import secrets; print(secrets.token_urlsafe(32))')"
153
+ export BITSOPAY_BASE_URL=https://pay.example.com
154
+ gunicorn -c deploy/gunicorn.conf.py "bitsopay.server:create_app()"
155
+ ```
156
+
157
+ Or with Docker: `docker compose up -d` (see [docs/deployment.md](docs/deployment.md)).
158
+
159
+ ```bash
160
+ curl -X POST https://pay.example.com/api/payments \
161
+ -H "Authorization: Bearer $BITSOPAY_ADMIN_TOKEN" \
162
+ -d '{"upi_id":"shop@okhdfcbank","payee_name":"My Shop","amount":499,"expires_in":3600}'
163
+ ```
164
+
165
+ | Route | Purpose |
166
+ |---|---|
167
+ | `GET /p/<ref>` | Customer payment page |
168
+ | `GET /p/<ref>/qr.png` · `qr.svg` | QR image |
169
+ | `GET /p/<ref>/status` | Status only (no amount or UPI ID) |
170
+ | `POST /api/payments` | Create a link *(admin)* |
171
+ | `GET /api/payments?status=&limit=&offset=` | History *(admin)* |
172
+ | `GET /api/payments/<ref>` | One record *(admin)* |
173
+ | `POST /api/payments/<ref>/paid` · `/cancel` | Change status *(admin)* |
174
+ | `GET /health` · `/ready` | Liveness and readiness probes |
175
+
176
+ Full reference: [docs/api.md](docs/api.md).
177
+
178
+ ## Command line
179
+
180
+ ```bash
181
+ bitsopay qr --upi-id shop@okhdfcbank --name "My Shop" --amount 499 -o pay.png
182
+ bitsopay create-link --db payments.db --base-url https://pay.example.com \
183
+ --upi-id shop@okhdfcbank --name "My Shop" --amount 499 --expires-in 3600
184
+ bitsopay history --db payments.db --status pending
185
+ bitsopay mark-paid BP684BF1555E4B4907 --db payments.db --note "UTR 4123..."
186
+ ```
187
+
188
+ Run `bitsopay --help` for all commands. [docs/cli.md](docs/cli.md) has the details.
189
+
190
+ ## Configuration
191
+
192
+ | Variable | Purpose |
193
+ |---|---|
194
+ | `BITSOPAY_DB` | SQLite path; enables short links, history and the full merchant API |
195
+ | `BITSOPAY_SECRET` | 16+ char secret for signed and database-free links |
196
+ | `BITSOPAY_UPI_ID`, `BITSOPAY_PAYEE_NAME` | Merchant identity for database-free links |
197
+ | `BITSOPAY_ADMIN_TOKEN` | 16+ char bearer token for `/api/*` (API is off without it) |
198
+ | `BITSOPAY_BASE_URL` | Public root URL used in returned links |
199
+ | `BITSOPAY_TRUST_PROXY` | `1` to trust `X-Forwarded-For/Proto` (only behind your own proxy) |
200
+ | `BITSOPAY_LOG_LEVEL` | `DEBUG`, `INFO`, `WARNING`, ... |
201
+
202
+ ## Security
203
+
204
+ Links cannot be edited or guessed, secrets are compared in constant time, the page makes no third-party
205
+ requests, and the admin API is throttled against brute force. Read the [threat model](docs/security-model.md)
206
+ before going live, and report vulnerabilities privately as described in [SECURITY.md](SECURITY.md).
207
+
208
+ ## Documentation
209
+
210
+ | | |
211
+ |---|---|
212
+ | [Usage guide](docs/usage.md) | Library walkthrough |
213
+ | [API reference](docs/api.md) | HTTP routes, errors and status codes |
214
+ | [CLI](docs/cli.md) | Every command |
215
+ | [Architecture](docs/architecture.md) | How the pieces fit |
216
+ | [Deployment](docs/deployment.md) | gunicorn, nginx, Docker, systemd |
217
+ | [Security model](docs/security-model.md) | Threats and limits |
218
+ | [Releasing](docs/releasing.md) | Publishing to PyPI |
219
+ | [Changelog](CHANGELOG.md) | Version history |
220
+
221
+ ## Development
222
+
223
+ ```bash
224
+ git clone https://github.com/Sudharsansm/Bitsopay && cd Bitsopay
225
+ python -m venv .venv && . .venv/bin/activate
226
+ pip install -e ".[dev]"
227
+ make check # ruff, mypy --strict, pytest with coverage
228
+ ```
229
+
230
+ See [CONTRIBUTING.md](CONTRIBUTING.md). Participation is governed by the [Code of Conduct](CODE_OF_CONDUCT.md).
231
+
232
+ ## License
233
+
234
+ [MIT](LICENSE) © 2026 Bitsophia
@@ -0,0 +1,193 @@
1
+ <p align="center">
2
+ <img src="https://raw.githubusercontent.com/Sudharsansm/Bitsopay/main/assets/bitsopay-logo.png" alt="Bitsopay" width="420">
3
+ </p>
4
+
5
+ <p align="center"><b>Dynamic UPI QR codes and tamper-proof payment links, with no payment gateway.</b></p>
6
+
7
+ <p align="center">
8
+ <a href="https://pypi.org/project/bitsopay/"><img alt="PyPI" src="https://img.shields.io/pypi/v/bitsopay?label=PyPI&color=blue"></a>
9
+ <a href="https://github.com/Sudharsansm/Bitsopay/blob/main/pyproject.toml"><img alt="Python 3.11+" src="https://img.shields.io/badge/python-3.11%20%7C%203.12%20%7C%203.13-blue.svg"></a>
10
+ <a href="https://github.com/Sudharsansm/Bitsopay/actions/workflows/ci.yml"><img alt="CI" src="https://github.com/Sudharsansm/Bitsopay/actions/workflows/ci.yml/badge.svg"></a>
11
+ <a href="LICENSE"><img alt="License: MIT" src="https://img.shields.io/badge/license-MIT-blue.svg"></a>
12
+ <a href="https://docs.astral.sh/ruff/"><img alt="Ruff" src="https://img.shields.io/badge/lint-ruff-261230.svg"></a>
13
+ <img alt="Typed" src="https://img.shields.io/badge/typing-strict-2a6db2.svg">
14
+ </p>
15
+
16
+ <p align="center">
17
+ <a href="README.md">README</a> ·
18
+ <a href="CODE_OF_CONDUCT.md">Code of conduct</a> ·
19
+ <a href="CONTRIBUTING.md">Contributing</a> ·
20
+ <a href="LICENSE">MIT license</a> ·
21
+ <a href="SECURITY.md">Security</a>
22
+ </p>
23
+
24
+ ---
25
+
26
+ ## About
27
+
28
+ **Bitsopay** turns a UPI ID and an amount into a QR code or a shareable payment link. The customer scans
29
+ it with any UPI app (GPay, PhonePe, Paytm, BHIM, and others) and the amount is already filled in. Money goes
30
+ straight to *your* UPI ID.
31
+
32
+ It is a framework developed by **[Bitsophia](https://github.com/Sudharsansm)**, in the same family as
33
+ [Bitscrape](https://github.com/Sudharsansm/Bitscrape).
34
+
35
+ > **Bitsopay is not a payment gateway.** It never sees or moves money, and it cannot detect that a customer
36
+ > has paid. You confirm the payment in your bank or UPI app, then record it with `mark_paid`. In exchange there are
37
+ > no API keys, no gateway fees and no KYC with a third party.
38
+
39
+ ## Features
40
+
41
+ - **QR from UPI ID + amount**: PNG, SVG or base64 data URI, with validated UPI IDs, `Decimal` amounts, notes and references.
42
+ - **Three kinds of payment link**:
43
+ - *Short links with history*: the URL holds only a reference; UPI ID and amount stay on your server (SQLite or your own store).
44
+ - *Database-free short links*: amount and expiry are encrypted and signed inside the URL.
45
+ - *Signed links*: HMAC-SHA256 with expiry, for existing sites.
46
+ - **Payment page**: mobile-friendly, QR, UPI app buttons, live countdown, no external requests.
47
+ - **Production WSGI server**: merchant API, `/health` and `/ready` probes, security headers (CSP, HSTS), request IDs,
48
+ structured logging, admin brute-force throttling.
49
+ - **CLI** for scripting and operations.
50
+ - **One dependency** ([`segno`](https://pypi.org/project/segno/), pure Python). Python 3.11+. Fully typed (`mypy --strict`).
51
+
52
+ ## Install
53
+
54
+ ```bash
55
+ pip install bitsopay # library + CLI
56
+ pip install "bitsopay[server]" # plus gunicorn for production serving
57
+ ```
58
+
59
+ ## Quick start
60
+
61
+ ### 1. A QR code
62
+
63
+ ```python
64
+ from bitsopay import UPIPayment, new_reference, save_qr, qr_data_uri
65
+
66
+ pay = UPIPayment(
67
+ upi_id="shop@okhdfcbank",
68
+ payee_name="My Shop",
69
+ amount=499, # None lets the customer type the amount
70
+ note="Order 1042",
71
+ reference=new_reference(), # use it to match the payment when you verify
72
+ )
73
+ pay.uri # upi://pay?pa=shop@okhdfcbank&pn=My%20Shop&am=499.00&cu=INR&...
74
+ save_qr(pay, "order-1042.png") # or .svg
75
+ html_src = qr_data_uri(pay) # <img src="...">
76
+ ```
77
+
78
+ ### 2. Short links with payment history
79
+
80
+ ```python
81
+ from bitsopay import PaymentLinks, SQLiteStore
82
+
83
+ with SQLiteStore("payments.db") as store:
84
+ links = PaymentLinks(store, "https://pay.example.com")
85
+ link = links.create("shop@okhdfcbank", "My Shop", 499, note="Order 1042", expires_in=3600)
86
+ print(link.url) # https://pay.example.com/p/BP684BF1555E4B4907 -> send to the customer
87
+ link.save("link-qr.png")
88
+
89
+ # after YOU confirmed the money in your bank / UPI app:
90
+ links.mark_paid(link.reference, note="UTR 4123...")
91
+ links.history(status="pending", limit=20) # paid | pending | cancelled | expired
92
+ ```
93
+
94
+ ### 3. Database-free links
95
+
96
+ ```python
97
+ from bitsopay import StatelessLinks
98
+
99
+ links = StatelessLinks("shop@okhdfcbank", "My Shop", secret=SECRET, base_url="https://pay.example.com")
100
+ link = links.create(499, expires_in=3600)
101
+ link.url
102
+ ```
103
+
104
+ More in [docs/usage.md](docs/usage.md) and [`examples/`](examples).
105
+
106
+ ## Run the server
107
+
108
+ ```bash
109
+ pip install "bitsopay[server]"
110
+ export BITSOPAY_DB=/var/lib/bitsopay/payments.db
111
+ export BITSOPAY_ADMIN_TOKEN="$(python -c 'import secrets; print(secrets.token_urlsafe(32))')"
112
+ export BITSOPAY_BASE_URL=https://pay.example.com
113
+ gunicorn -c deploy/gunicorn.conf.py "bitsopay.server:create_app()"
114
+ ```
115
+
116
+ Or with Docker: `docker compose up -d` (see [docs/deployment.md](docs/deployment.md)).
117
+
118
+ ```bash
119
+ curl -X POST https://pay.example.com/api/payments \
120
+ -H "Authorization: Bearer $BITSOPAY_ADMIN_TOKEN" \
121
+ -d '{"upi_id":"shop@okhdfcbank","payee_name":"My Shop","amount":499,"expires_in":3600}'
122
+ ```
123
+
124
+ | Route | Purpose |
125
+ |---|---|
126
+ | `GET /p/<ref>` | Customer payment page |
127
+ | `GET /p/<ref>/qr.png` · `qr.svg` | QR image |
128
+ | `GET /p/<ref>/status` | Status only (no amount or UPI ID) |
129
+ | `POST /api/payments` | Create a link *(admin)* |
130
+ | `GET /api/payments?status=&limit=&offset=` | History *(admin)* |
131
+ | `GET /api/payments/<ref>` | One record *(admin)* |
132
+ | `POST /api/payments/<ref>/paid` · `/cancel` | Change status *(admin)* |
133
+ | `GET /health` · `/ready` | Liveness and readiness probes |
134
+
135
+ Full reference: [docs/api.md](docs/api.md).
136
+
137
+ ## Command line
138
+
139
+ ```bash
140
+ bitsopay qr --upi-id shop@okhdfcbank --name "My Shop" --amount 499 -o pay.png
141
+ bitsopay create-link --db payments.db --base-url https://pay.example.com \
142
+ --upi-id shop@okhdfcbank --name "My Shop" --amount 499 --expires-in 3600
143
+ bitsopay history --db payments.db --status pending
144
+ bitsopay mark-paid BP684BF1555E4B4907 --db payments.db --note "UTR 4123..."
145
+ ```
146
+
147
+ Run `bitsopay --help` for all commands. [docs/cli.md](docs/cli.md) has the details.
148
+
149
+ ## Configuration
150
+
151
+ | Variable | Purpose |
152
+ |---|---|
153
+ | `BITSOPAY_DB` | SQLite path; enables short links, history and the full merchant API |
154
+ | `BITSOPAY_SECRET` | 16+ char secret for signed and database-free links |
155
+ | `BITSOPAY_UPI_ID`, `BITSOPAY_PAYEE_NAME` | Merchant identity for database-free links |
156
+ | `BITSOPAY_ADMIN_TOKEN` | 16+ char bearer token for `/api/*` (API is off without it) |
157
+ | `BITSOPAY_BASE_URL` | Public root URL used in returned links |
158
+ | `BITSOPAY_TRUST_PROXY` | `1` to trust `X-Forwarded-For/Proto` (only behind your own proxy) |
159
+ | `BITSOPAY_LOG_LEVEL` | `DEBUG`, `INFO`, `WARNING`, ... |
160
+
161
+ ## Security
162
+
163
+ Links cannot be edited or guessed, secrets are compared in constant time, the page makes no third-party
164
+ requests, and the admin API is throttled against brute force. Read the [threat model](docs/security-model.md)
165
+ before going live, and report vulnerabilities privately as described in [SECURITY.md](SECURITY.md).
166
+
167
+ ## Documentation
168
+
169
+ | | |
170
+ |---|---|
171
+ | [Usage guide](docs/usage.md) | Library walkthrough |
172
+ | [API reference](docs/api.md) | HTTP routes, errors and status codes |
173
+ | [CLI](docs/cli.md) | Every command |
174
+ | [Architecture](docs/architecture.md) | How the pieces fit |
175
+ | [Deployment](docs/deployment.md) | gunicorn, nginx, Docker, systemd |
176
+ | [Security model](docs/security-model.md) | Threats and limits |
177
+ | [Releasing](docs/releasing.md) | Publishing to PyPI |
178
+ | [Changelog](CHANGELOG.md) | Version history |
179
+
180
+ ## Development
181
+
182
+ ```bash
183
+ git clone https://github.com/Sudharsansm/Bitsopay && cd Bitsopay
184
+ python -m venv .venv && . .venv/bin/activate
185
+ pip install -e ".[dev]"
186
+ make check # ruff, mypy --strict, pytest with coverage
187
+ ```
188
+
189
+ See [CONTRIBUTING.md](CONTRIBUTING.md). Participation is governed by the [Code of Conduct](CODE_OF_CONDUCT.md).
190
+
191
+ ## License
192
+
193
+ [MIT](LICENSE) © 2026 Bitsophia