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.
- bitsopay-0.1.0/CHANGELOG.md +33 -0
- bitsopay-0.1.0/CODE_OF_CONDUCT.md +103 -0
- bitsopay-0.1.0/CONTRIBUTING.md +47 -0
- bitsopay-0.1.0/LICENSE +21 -0
- bitsopay-0.1.0/MANIFEST.in +8 -0
- bitsopay-0.1.0/PKG-INFO +234 -0
- bitsopay-0.1.0/README.md +193 -0
- bitsopay-0.1.0/SECURITY.md +44 -0
- bitsopay-0.1.0/deploy/.env.example +9 -0
- bitsopay-0.1.0/deploy/bitsopay.service +21 -0
- bitsopay-0.1.0/deploy/gunicorn.conf.py +16 -0
- bitsopay-0.1.0/deploy/nginx.conf +31 -0
- bitsopay-0.1.0/docs/api.md +52 -0
- bitsopay-0.1.0/docs/architecture.md +37 -0
- bitsopay-0.1.0/docs/cli.md +20 -0
- bitsopay-0.1.0/docs/deployment.md +39 -0
- bitsopay-0.1.0/docs/releasing.md +31 -0
- bitsopay-0.1.0/docs/security-model.md +34 -0
- bitsopay-0.1.0/docs/usage.md +70 -0
- bitsopay-0.1.0/examples/basic_qr.py +13 -0
- bitsopay-0.1.0/examples/embed_in_wsgi.py +13 -0
- bitsopay-0.1.0/examples/short_links.py +14 -0
- bitsopay-0.1.0/pyproject.toml +101 -0
- bitsopay-0.1.0/setup.cfg +4 -0
- bitsopay-0.1.0/src/bitsopay/__init__.py +64 -0
- bitsopay-0.1.0/src/bitsopay/__main__.py +6 -0
- bitsopay-0.1.0/src/bitsopay/cli.py +245 -0
- bitsopay-0.1.0/src/bitsopay/exceptions.py +31 -0
- bitsopay-0.1.0/src/bitsopay/link.py +122 -0
- bitsopay-0.1.0/src/bitsopay/models.py +57 -0
- bitsopay-0.1.0/src/bitsopay/page.py +133 -0
- bitsopay-0.1.0/src/bitsopay/py.typed +0 -0
- bitsopay-0.1.0/src/bitsopay/qr.py +87 -0
- bitsopay-0.1.0/src/bitsopay/ratelimit.py +69 -0
- bitsopay-0.1.0/src/bitsopay/server.py +520 -0
- bitsopay-0.1.0/src/bitsopay/session.py +67 -0
- bitsopay-0.1.0/src/bitsopay/shortlink.py +172 -0
- bitsopay-0.1.0/src/bitsopay/stateless.py +181 -0
- bitsopay-0.1.0/src/bitsopay/store.py +277 -0
- bitsopay-0.1.0/src/bitsopay/upi.py +47 -0
- bitsopay-0.1.0/src/bitsopay/validators.py +86 -0
- bitsopay-0.1.0/src/bitsopay.egg-info/PKG-INFO +234 -0
- bitsopay-0.1.0/src/bitsopay.egg-info/SOURCES.txt +53 -0
- bitsopay-0.1.0/src/bitsopay.egg-info/dependency_links.txt +1 -0
- bitsopay-0.1.0/src/bitsopay.egg-info/entry_points.txt +2 -0
- bitsopay-0.1.0/src/bitsopay.egg-info/requires.txt +12 -0
- bitsopay-0.1.0/src/bitsopay.egg-info/top_level.txt +1 -0
- bitsopay-0.1.0/tests/conftest.py +82 -0
- bitsopay-0.1.0/tests/test_bitsopay.py +256 -0
- bitsopay-0.1.0/tests/test_cli_and_core_extra.py +140 -0
- bitsopay-0.1.0/tests/test_http_integration.py +94 -0
- bitsopay-0.1.0/tests/test_ratelimit.py +39 -0
- bitsopay-0.1.0/tests/test_server_hardening.py +258 -0
- bitsopay-0.1.0/tests/test_shortlink.py +274 -0
- 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
|
bitsopay-0.1.0/PKG-INFO
ADDED
|
@@ -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
|
bitsopay-0.1.0/README.md
ADDED
|
@@ -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
|