pywayforpay 0.2.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 (59) hide show
  1. pywayforpay-0.2.0/.github/workflows/ci.yml +99 -0
  2. pywayforpay-0.2.0/.github/workflows/publish.yml +41 -0
  3. pywayforpay-0.2.0/.github/workflows/release.yml +56 -0
  4. pywayforpay-0.2.0/.gitignore +16 -0
  5. pywayforpay-0.2.0/.pre-commit-config.yaml +6 -0
  6. pywayforpay-0.2.0/CHANGELOG.md +9 -0
  7. pywayforpay-0.2.0/LICENSE +21 -0
  8. pywayforpay-0.2.0/PKG-INFO +194 -0
  9. pywayforpay-0.2.0/README.md +169 -0
  10. pywayforpay-0.2.0/docs/antifraud.md +35 -0
  11. pywayforpay-0.2.0/docs/api/clients.md +17 -0
  12. pywayforpay-0.2.0/docs/api/data.md +23 -0
  13. pywayforpay-0.2.0/docs/api/enums.md +25 -0
  14. pywayforpay-0.2.0/docs/api/requests.md +37 -0
  15. pywayforpay-0.2.0/docs/api/responses.md +22 -0
  16. pywayforpay-0.2.0/docs/api/webhooks.md +7 -0
  17. pywayforpay-0.2.0/docs/errors.md +57 -0
  18. pywayforpay-0.2.0/docs/index.md +87 -0
  19. pywayforpay-0.2.0/docs/mms.md +31 -0
  20. pywayforpay-0.2.0/docs/payment-flows.md +119 -0
  21. pywayforpay-0.2.0/docs/pci-dss.md +43 -0
  22. pywayforpay-0.2.0/docs/quickstart.md +82 -0
  23. pywayforpay-0.2.0/docs/recurring.md +61 -0
  24. pywayforpay-0.2.0/docs/signing.md +38 -0
  25. pywayforpay-0.2.0/docs/webhooks.md +62 -0
  26. pywayforpay-0.2.0/docs/widget.md +63 -0
  27. pywayforpay-0.2.0/examples/async_api.py +50 -0
  28. pywayforpay-0.2.0/examples/charge.py +49 -0
  29. pywayforpay-0.2.0/examples/purchase_form.py +43 -0
  30. pywayforpay-0.2.0/examples/verify_form.py +33 -0
  31. pywayforpay-0.2.0/examples/webhooks.py +55 -0
  32. pywayforpay-0.2.0/examples/widget.py +39 -0
  33. pywayforpay-0.2.0/mkdocs.yml +52 -0
  34. pywayforpay-0.2.0/pyproject.toml +96 -0
  35. pywayforpay-0.2.0/scripts/apply-protection.sh +69 -0
  36. pywayforpay-0.2.0/src/wayforpay/__init__.py +31 -0
  37. pywayforpay-0.2.0/src/wayforpay/_async_client.py +486 -0
  38. pywayforpay-0.2.0/src/wayforpay/_constants.py +22 -0
  39. pywayforpay-0.2.0/src/wayforpay/_encoding.py +56 -0
  40. pywayforpay-0.2.0/src/wayforpay/_errors.py +18 -0
  41. pywayforpay-0.2.0/src/wayforpay/_money.py +7 -0
  42. pywayforpay-0.2.0/src/wayforpay/_signature.py +49 -0
  43. pywayforpay-0.2.0/src/wayforpay/_transports.py +76 -0
  44. pywayforpay-0.2.0/src/wayforpay/client.py +509 -0
  45. pywayforpay-0.2.0/src/wayforpay/models/__init__.py +179 -0
  46. pywayforpay-0.2.0/src/wayforpay/models/_base.py +17 -0
  47. pywayforpay-0.2.0/src/wayforpay/models/antifraud.py +124 -0
  48. pywayforpay-0.2.0/src/wayforpay/models/data.py +108 -0
  49. pywayforpay-0.2.0/src/wayforpay/models/enums.py +365 -0
  50. pywayforpay-0.2.0/src/wayforpay/models/requests.py +737 -0
  51. pywayforpay-0.2.0/src/wayforpay/models/responses.py +198 -0
  52. pywayforpay-0.2.0/src/wayforpay/py.typed +0 -0
  53. pywayforpay-0.2.0/src/wayforpay/webhooks.py +103 -0
  54. pywayforpay-0.2.0/tests/test_client_async.py +88 -0
  55. pywayforpay-0.2.0/tests/test_client_sync.py +315 -0
  56. pywayforpay-0.2.0/tests/test_models.py +144 -0
  57. pywayforpay-0.2.0/tests/test_signature.py +52 -0
  58. pywayforpay-0.2.0/tests/test_webhooks.py +127 -0
  59. pywayforpay-0.2.0/uv.lock +1288 -0
@@ -0,0 +1,99 @@
1
+ name: CI
2
+
3
+ on:
4
+ push:
5
+ branches: [master]
6
+ pull_request:
7
+
8
+ jobs:
9
+ commit-lint:
10
+ runs-on: ubuntu-latest
11
+ steps:
12
+ - uses: actions/checkout@v4
13
+ with:
14
+ fetch-depth: 0
15
+
16
+ - name: Install uv
17
+ uses: astral-sh/setup-uv@v5
18
+
19
+ - name: Set up Python
20
+ uses: actions/setup-python@v5
21
+ with:
22
+ python-version: "3.12"
23
+
24
+ - name: Install project
25
+ run: uv sync
26
+
27
+ - name: Check conventional commits
28
+ run: |
29
+ if [ "$GITHUB_EVENT_NAME" = "pull_request" ]; then
30
+ uv run cz check --rev-range "${{ github.event.pull_request.base.sha }}..${{ github.event.pull_request.head.sha }}"
31
+ uv run cz check -m "${{ github.event.pull_request.title }}"
32
+ elif [ "${{ github.event.before }}" != "0000000000000000000000000000000000000000" ]; then
33
+ uv run cz check --rev-range "${{ github.event.before }}..HEAD"
34
+ else
35
+ uv run cz check --rev-range HEAD~1..HEAD
36
+ fi
37
+
38
+ lint-type-test:
39
+ strategy:
40
+ matrix:
41
+ python-version: ["3.11", "3.12", "3.13"]
42
+ runs-on: ubuntu-latest
43
+ steps:
44
+ - uses: actions/checkout@v4
45
+
46
+ - name: Install uv
47
+ uses: astral-sh/setup-uv@v5
48
+
49
+ - name: Set up Python ${{ matrix.python-version }}
50
+ uses: actions/setup-python@v5
51
+ with:
52
+ python-version: ${{ matrix.python-version }}
53
+
54
+ - name: Install project
55
+ run: uv sync --python ${{ matrix.python-version }}
56
+
57
+ - name: Lint
58
+ run: uv run ruff check .
59
+
60
+ - name: Type check
61
+ run: uv run basedpyright
62
+
63
+ - name: Test
64
+ run: uv run pytest
65
+
66
+ - name: Upload coverage reports to Codecov
67
+ uses: codecov/codecov-action@v5
68
+ with:
69
+ token: ${{ secrets.CODECOV_TOKEN }}
70
+ files: coverage.xml
71
+ fail_ci_if_error: false
72
+
73
+ docs:
74
+ runs-on: ubuntu-latest
75
+ permissions:
76
+ contents: write
77
+ steps:
78
+ - uses: actions/checkout@v4
79
+
80
+ - name: Install uv
81
+ uses: astral-sh/setup-uv@v5
82
+
83
+ - name: Set up Python
84
+ uses: actions/setup-python@v5
85
+ with:
86
+ python-version: "3.12"
87
+
88
+ - name: Install project
89
+ run: uv sync
90
+
91
+ - name: Build docs
92
+ run: uv run mkdocs build --strict
93
+
94
+ - name: Deploy to GitHub Pages
95
+ if: github.ref == 'refs/heads/master' && github.event_name == 'push'
96
+ uses: peaceiris/actions-gh-pages@v4
97
+ with:
98
+ github_token: ${{ secrets.GITHUB_TOKEN }}
99
+ publish_dir: ./site
@@ -0,0 +1,41 @@
1
+ name: Publish to PyPI
2
+
3
+ on:
4
+ release:
5
+ types: [published]
6
+ workflow_dispatch:
7
+ inputs:
8
+ repository:
9
+ description: PyPI repository to publish to
10
+ type: choice
11
+ default: testpypi
12
+ options:
13
+ - testpypi
14
+ - pypi
15
+
16
+ jobs:
17
+ publish:
18
+ runs-on: ubuntu-latest
19
+ environment: release
20
+ permissions:
21
+ id-token: write
22
+ env:
23
+ PYPI_REPOSITORY_URL: ${{ github.event.inputs.repository == 'testpypi' && 'https://test.pypi.org/legacy/' || 'https://upload.pypi.org/legacy/' }}
24
+ steps:
25
+ - uses: actions/checkout@v4
26
+
27
+ - name: Install uv
28
+ uses: astral-sh/setup-uv@v5
29
+
30
+ - name: Set up Python
31
+ uses: actions/setup-python@v5
32
+ with:
33
+ python-version: "3.12"
34
+
35
+ - name: Build distributions
36
+ run: uv build
37
+
38
+ - name: Publish package distributions to PyPI
39
+ uses: pypa/gh-action-pypi-publish@release/v1
40
+ with:
41
+ packages-dir: dist
@@ -0,0 +1,56 @@
1
+ name: Release
2
+
3
+ on:
4
+ push:
5
+ tags: ["v*"]
6
+
7
+ jobs:
8
+ release:
9
+ runs-on: ubuntu-latest
10
+ permissions:
11
+ contents: write
12
+ steps:
13
+ - uses: actions/checkout@v4
14
+ with:
15
+ fetch-depth: 0
16
+
17
+ - name: Install uv
18
+ uses: astral-sh/setup-uv@v5
19
+
20
+ - name: Set up Python
21
+ uses: actions/setup-python@v5
22
+ with:
23
+ python-version: "3.12"
24
+
25
+ - name: Install project
26
+ run: uv sync
27
+
28
+ - name: Generate changelog
29
+ run: uv run cz changelog
30
+
31
+ - name: Extract changelog section for this tag
32
+ run: |
33
+ python - "${{ github.ref_name }}" <<'PY'
34
+ import sys
35
+ tag = sys.argv[1]
36
+ lines = open("CHANGELOG.md").read().splitlines()
37
+ start = next(i for i, l in enumerate(lines) if l.startswith("## ") and tag in l)
38
+ end = next(
39
+ (i for i in range(start + 1, len(lines)) if lines[i].startswith("## ")),
40
+ len(lines),
41
+ )
42
+ open("/tmp/release-notes.md", "w").write("\n".join(lines[start:end]) + "\n")
43
+ PY
44
+
45
+ - name: Commit changelog back to master
46
+ run: |
47
+ git config user.name "github-actions[bot]"
48
+ git config user.email "github-actions[bot]@users.noreply.github.com"
49
+ git add CHANGELOG.md
50
+ git commit -m "docs: update CHANGELOG.md for ${{ github.ref_name }}" || true
51
+ git push origin HEAD:master || true
52
+
53
+ - name: Create GitHub release
54
+ uses: softprops/action-gh-release@v2
55
+ with:
56
+ body_path: /tmp/release-notes.md
@@ -0,0 +1,16 @@
1
+ __pycache__/
2
+ *.py[cod]
3
+ *.egg-info/
4
+ dist/
5
+ build/
6
+ .venv/
7
+ .uv/
8
+ .ruff_cache/
9
+ .pytest_cache/
10
+ .mypy_cache/
11
+ .pyright/
12
+ *.log
13
+ .coverage
14
+ coverage.xml
15
+ htmlcov/
16
+ site/
@@ -0,0 +1,6 @@
1
+ repos:
2
+ - repo: https://github.com/commitizen-tools/commitizen
3
+ rev: v4.18.0
4
+ hooks:
5
+ - id: commitizen
6
+ stages: [commit-msg]
@@ -0,0 +1,9 @@
1
+ ## v0.2.0 (2026-09-02)
2
+
3
+ ### Feat
4
+
5
+ - typed msgspec WayForPay SDK (sync+async, all endpoints)
6
+
7
+ ### Fix
8
+
9
+ - widget auth casing, url helpers, callback hardening, py.typed
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Filip Shramko
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,194 @@
1
+ Metadata-Version: 2.5
2
+ Name: pywayforpay
3
+ Version: 0.2.0
4
+ Summary: Strongly typed WayForPay PSP API SDK (msgspec-based, sync + async)
5
+ Project-URL: Documentation, https://wiki.wayforpay.com/en/
6
+ Project-URL: Repository, https://github.com/HermanPlay/pywayforpay
7
+ Author: Filip Shramko
8
+ License: MIT
9
+ License-File: LICENSE
10
+ Keywords: api,msgspec,payment-gateway,payments,psp,sdk,wayforpay
11
+ Classifier: Development Status :: 3 - Alpha
12
+ Classifier: Intended Audience :: Developers
13
+ Classifier: License :: OSI Approved :: MIT License
14
+ Classifier: Operating System :: OS Independent
15
+ Classifier: Programming Language :: Python :: 3
16
+ Classifier: Programming Language :: Python :: 3.11
17
+ Classifier: Programming Language :: Python :: 3.12
18
+ Classifier: Programming Language :: Python :: 3.13
19
+ Classifier: Topic :: Internet :: WWW/HTTP
20
+ Classifier: Topic :: Software Development :: Libraries :: Python Modules
21
+ Requires-Python: >=3.11
22
+ Requires-Dist: httpx>=0.27
23
+ Requires-Dist: msgspec>=0.18
24
+ Description-Content-Type: text/markdown
25
+
26
+ # pywayforpay
27
+
28
+ [![CI](https://img.shields.io/github/actions/workflow/status/HermanPlay/pywayforpay/ci.yml?branch=master&label=CI)](https://github.com/HermanPlay/pywayforpay/actions/workflows/ci.yml)
29
+ [![codecov](https://codecov.io/gh/HermanPlay/pywayforpay/graph/badge.svg?token=8V2RQUJEMM)](https://codecov.io/gh/HermanPlay/pywayforpay)
30
+ [![Python](https://img.shields.io/pypi/pyversions/pywayforpay)](https://pypi.org/project/pywayforpay/)
31
+ [![Docs](https://img.shields.io/badge/docs-mkdocs-blue)](https://HermanPlay.github.io/pywayforpay/)
32
+
33
+ Strongly typed [WayForPay](https://wiki.wayforpay.com/en/) PSP API SDK for Python (3.11+),
34
+ built on [msgspec](https://msgspec.dev/) with explicit structs, HMAC-MD5 signature handling,
35
+ and sync + async [httpx](https://www.python-httpx.org/) clients.
36
+
37
+ ## Features
38
+
39
+ - **Payments** — purchase (redirect form, widget, offline link), verify, charge (host-to-host),
40
+ 3-DS completion, settle, refund, invoices, QR, P2P transfers, currency rates.
41
+ - **Recurring payments** — status, suspend, resume, remove, change.
42
+ - **Reporting** — check status, transaction list.
43
+ - **Merchant management (MMS)** — merchants, partners, balances.
44
+ - **Antifraud** — validate and check status.
45
+ - **Webhooks** — verify callbacks and acks, build acks.
46
+ - Fully typed (`py.typed`), documented, sync + async APIs in lockstep.
47
+
48
+ ## Installation
49
+
50
+ ```bash
51
+ pip install pywayforpay
52
+ ```
53
+
54
+ Requires Python 3.11+.
55
+
56
+ ## Quickstart
57
+
58
+ ```python
59
+ from wayforpay import Client, Credentials, money
60
+ from wayforpay.models import PurchaseRequest, Product, Currency
61
+
62
+ creds = Credentials(
63
+ merchant_account="test_merch_n1",
64
+ merchant_secret_key="flk3409refn54t54t*FNJRET",
65
+ merchant_domain_name="www.market.ua",
66
+ )
67
+
68
+ product = Product(name="Dell XPS", price=money("1547.36"), count=1)
69
+ request = PurchaseRequest.from_products(
70
+ order_reference="DH783023",
71
+ order_date=1415379863,
72
+ amount=money("1547.36"),
73
+ currency=Currency.UAH,
74
+ products=[product],
75
+ )
76
+
77
+ with Client(creds) as client:
78
+ url = client.purchase_url() # https://secure.wayforpay.com/pay
79
+ form = client.purchase_form(request) # signed POST payload for the payment page
80
+ ```
81
+
82
+ Render `form` as hidden fields inside `<form action="{url}" method="POST">`.
83
+
84
+ Async mirrors sync:
85
+
86
+ ```python
87
+ import asyncio
88
+ from wayforpay import AsyncClient, Credentials
89
+
90
+ async def main() -> None:
91
+ async with AsyncClient(creds) as client:
92
+ result = await client.check_status(CheckStatusRequest(order_reference="DH783023"))
93
+
94
+ asyncio.run(main())
95
+ ```
96
+
97
+ ## Examples
98
+
99
+ Runnable examples live in [`examples/`](examples/):
100
+
101
+ ```bash
102
+ uv run python examples/purchase_form.py # signed purchase form + HTML snippet
103
+ uv run python examples/widget.py # payment-widget config
104
+ uv run python examples/webhooks.py # callback verification + ack
105
+ uv run python examples/verify_form.py # card verification form
106
+ uv run python examples/async_api.py # async client (dry-run; add --live)
107
+ uv run python examples/charge.py # host-to-host charge (dry-run; add --live)
108
+ ```
109
+
110
+ ## Documentation
111
+
112
+ Full documentation is available at <https://HermanPlay.github.io/pywayforpay/>.
113
+
114
+ - [Quickstart](https://HermanPlay.github.io/pywayforpay/quickstart/)
115
+ - [Payments](https://HermanPlay.github.io/pywayforpay/payment-flows/)
116
+ - [Payment widget](https://HermanPlay.github.io/pywayforpay/widget/)
117
+ - [Webhooks](https://HermanPlay.github.io/pywayforpay/webhooks/)
118
+ - [Recurring payments](https://HermanPlay.github.io/pywayforpay/recurring/)
119
+ - [Merchant management (MMS)](https://HermanPlay.github.io/pywayforpay/mms/)
120
+ - [Antifraud](https://HermanPlay.github.io/pywayforpay/antifraud/)
121
+ - [Errors & reason codes](https://HermanPlay.github.io/pywayforpay/errors/)
122
+ - [PCI DSS](https://HermanPlay.github.io/pywayforpay/pci-dss/)
123
+ - [API reference](https://HermanPlay.github.io/pywayforpay/api/clients/)
124
+
125
+ WayForPay API docs: <https://wiki.wayforpay.com/en/>
126
+
127
+ ## PCI DSS
128
+
129
+ This library exposes host-to-host card operations (`ChargeRequest`, `CardData`).
130
+ Handling raw card data carries PCI DSS obligations; the merchant/integrator remains
131
+ responsible for compliance. Prefer the hosted payment widget or redirect form to avoid
132
+ touching card data. See the [PCI DSS guide](https://HermanPlay.github.io/pywayforpay/pci-dss/).
133
+
134
+ ## Development
135
+
136
+ Install dev deps: `uv sync`.
137
+
138
+ ### Conventional commits
139
+
140
+ Commit messages follow [Conventional Commits](https://www.conventionalcommits.org/)
141
+ (`feat:`, `fix:`, `docs:`, `refactor:`, `ci:`, ...). The `commit-lint` CI job checks
142
+ every commit in a PR (and the PR title) with commitizen and fails on violations.
143
+
144
+ The `master` branch is protected by a GitHub ruleset (`scripts/apply-protection.sh`):
145
+
146
+ - direct pushes and force-pushes to `master` are rejected — all changes go through PRs;
147
+ - a PR needs one approving review and a green `commit-lint` check before merge.
148
+
149
+ So the remote rejects non-conventional commits even if a contributor skips local hooks.
150
+ The pre-commit hook is convenience only:
151
+
152
+ ```bash
153
+ uv run pre-commit install --hook-type commit-msg # one-time local setup
154
+ ```
155
+
156
+ ### Releases
157
+
158
+ Publishing creates a version tag, a GitHub release with a changelog generated from
159
+ the commit log, and a PyPI package published via trusted publishing (OIDC).
160
+
161
+ 1. Bump the version and tag it:
162
+
163
+ ```bash
164
+ uv run cz bump
165
+ ```
166
+
167
+ Bumps `pyproject.toml`, `__init__.py` and `uv.lock`, updates `CHANGELOG.md`, and
168
+ creates a `vX.Y.Z` tag. Add `--yes --increment patch|minor|major` to skip the
169
+ interactive prompt (e.g. in scripts/CI).
170
+
171
+ 2. Push the tag:
172
+
173
+ ```bash
174
+ git push origin master --tags
175
+ ```
176
+
177
+ The `release` workflow builds the changelog for the tag and creates a GitHub
178
+ release. The `publish` workflow then publishes the package to PyPI.
179
+
180
+ #### One-time PyPI setup (trusted publishing)
181
+
182
+ The `publish` workflow uses PyPI trusted publishing (OIDC) — no API tokens stored.
183
+
184
+ - Enable 2FA on your PyPI and TestPyPI accounts (PyPI policy requirement).
185
+ - Register the project `pywayforpay` on PyPI (and TestPyPI).
186
+ - Add a trusted publisher on each: owner `HermanPlay`, repository `pywayforpay`,
187
+ workflow file `publish.yml`, environment `release`.
188
+
189
+ To validate a release against TestPyPI first, trigger the `publish` workflow manually
190
+ with repository `testpypi` (Actions tab → Publish to PyPI → Run workflow).
191
+
192
+ ## License
193
+
194
+ [MIT](LICENSE)
@@ -0,0 +1,169 @@
1
+ # pywayforpay
2
+
3
+ [![CI](https://img.shields.io/github/actions/workflow/status/HermanPlay/pywayforpay/ci.yml?branch=master&label=CI)](https://github.com/HermanPlay/pywayforpay/actions/workflows/ci.yml)
4
+ [![codecov](https://codecov.io/gh/HermanPlay/pywayforpay/graph/badge.svg?token=8V2RQUJEMM)](https://codecov.io/gh/HermanPlay/pywayforpay)
5
+ [![Python](https://img.shields.io/pypi/pyversions/pywayforpay)](https://pypi.org/project/pywayforpay/)
6
+ [![Docs](https://img.shields.io/badge/docs-mkdocs-blue)](https://HermanPlay.github.io/pywayforpay/)
7
+
8
+ Strongly typed [WayForPay](https://wiki.wayforpay.com/en/) PSP API SDK for Python (3.11+),
9
+ built on [msgspec](https://msgspec.dev/) with explicit structs, HMAC-MD5 signature handling,
10
+ and sync + async [httpx](https://www.python-httpx.org/) clients.
11
+
12
+ ## Features
13
+
14
+ - **Payments** — purchase (redirect form, widget, offline link), verify, charge (host-to-host),
15
+ 3-DS completion, settle, refund, invoices, QR, P2P transfers, currency rates.
16
+ - **Recurring payments** — status, suspend, resume, remove, change.
17
+ - **Reporting** — check status, transaction list.
18
+ - **Merchant management (MMS)** — merchants, partners, balances.
19
+ - **Antifraud** — validate and check status.
20
+ - **Webhooks** — verify callbacks and acks, build acks.
21
+ - Fully typed (`py.typed`), documented, sync + async APIs in lockstep.
22
+
23
+ ## Installation
24
+
25
+ ```bash
26
+ pip install pywayforpay
27
+ ```
28
+
29
+ Requires Python 3.11+.
30
+
31
+ ## Quickstart
32
+
33
+ ```python
34
+ from wayforpay import Client, Credentials, money
35
+ from wayforpay.models import PurchaseRequest, Product, Currency
36
+
37
+ creds = Credentials(
38
+ merchant_account="test_merch_n1",
39
+ merchant_secret_key="flk3409refn54t54t*FNJRET",
40
+ merchant_domain_name="www.market.ua",
41
+ )
42
+
43
+ product = Product(name="Dell XPS", price=money("1547.36"), count=1)
44
+ request = PurchaseRequest.from_products(
45
+ order_reference="DH783023",
46
+ order_date=1415379863,
47
+ amount=money("1547.36"),
48
+ currency=Currency.UAH,
49
+ products=[product],
50
+ )
51
+
52
+ with Client(creds) as client:
53
+ url = client.purchase_url() # https://secure.wayforpay.com/pay
54
+ form = client.purchase_form(request) # signed POST payload for the payment page
55
+ ```
56
+
57
+ Render `form` as hidden fields inside `<form action="{url}" method="POST">`.
58
+
59
+ Async mirrors sync:
60
+
61
+ ```python
62
+ import asyncio
63
+ from wayforpay import AsyncClient, Credentials
64
+
65
+ async def main() -> None:
66
+ async with AsyncClient(creds) as client:
67
+ result = await client.check_status(CheckStatusRequest(order_reference="DH783023"))
68
+
69
+ asyncio.run(main())
70
+ ```
71
+
72
+ ## Examples
73
+
74
+ Runnable examples live in [`examples/`](examples/):
75
+
76
+ ```bash
77
+ uv run python examples/purchase_form.py # signed purchase form + HTML snippet
78
+ uv run python examples/widget.py # payment-widget config
79
+ uv run python examples/webhooks.py # callback verification + ack
80
+ uv run python examples/verify_form.py # card verification form
81
+ uv run python examples/async_api.py # async client (dry-run; add --live)
82
+ uv run python examples/charge.py # host-to-host charge (dry-run; add --live)
83
+ ```
84
+
85
+ ## Documentation
86
+
87
+ Full documentation is available at <https://HermanPlay.github.io/pywayforpay/>.
88
+
89
+ - [Quickstart](https://HermanPlay.github.io/pywayforpay/quickstart/)
90
+ - [Payments](https://HermanPlay.github.io/pywayforpay/payment-flows/)
91
+ - [Payment widget](https://HermanPlay.github.io/pywayforpay/widget/)
92
+ - [Webhooks](https://HermanPlay.github.io/pywayforpay/webhooks/)
93
+ - [Recurring payments](https://HermanPlay.github.io/pywayforpay/recurring/)
94
+ - [Merchant management (MMS)](https://HermanPlay.github.io/pywayforpay/mms/)
95
+ - [Antifraud](https://HermanPlay.github.io/pywayforpay/antifraud/)
96
+ - [Errors & reason codes](https://HermanPlay.github.io/pywayforpay/errors/)
97
+ - [PCI DSS](https://HermanPlay.github.io/pywayforpay/pci-dss/)
98
+ - [API reference](https://HermanPlay.github.io/pywayforpay/api/clients/)
99
+
100
+ WayForPay API docs: <https://wiki.wayforpay.com/en/>
101
+
102
+ ## PCI DSS
103
+
104
+ This library exposes host-to-host card operations (`ChargeRequest`, `CardData`).
105
+ Handling raw card data carries PCI DSS obligations; the merchant/integrator remains
106
+ responsible for compliance. Prefer the hosted payment widget or redirect form to avoid
107
+ touching card data. See the [PCI DSS guide](https://HermanPlay.github.io/pywayforpay/pci-dss/).
108
+
109
+ ## Development
110
+
111
+ Install dev deps: `uv sync`.
112
+
113
+ ### Conventional commits
114
+
115
+ Commit messages follow [Conventional Commits](https://www.conventionalcommits.org/)
116
+ (`feat:`, `fix:`, `docs:`, `refactor:`, `ci:`, ...). The `commit-lint` CI job checks
117
+ every commit in a PR (and the PR title) with commitizen and fails on violations.
118
+
119
+ The `master` branch is protected by a GitHub ruleset (`scripts/apply-protection.sh`):
120
+
121
+ - direct pushes and force-pushes to `master` are rejected — all changes go through PRs;
122
+ - a PR needs one approving review and a green `commit-lint` check before merge.
123
+
124
+ So the remote rejects non-conventional commits even if a contributor skips local hooks.
125
+ The pre-commit hook is convenience only:
126
+
127
+ ```bash
128
+ uv run pre-commit install --hook-type commit-msg # one-time local setup
129
+ ```
130
+
131
+ ### Releases
132
+
133
+ Publishing creates a version tag, a GitHub release with a changelog generated from
134
+ the commit log, and a PyPI package published via trusted publishing (OIDC).
135
+
136
+ 1. Bump the version and tag it:
137
+
138
+ ```bash
139
+ uv run cz bump
140
+ ```
141
+
142
+ Bumps `pyproject.toml`, `__init__.py` and `uv.lock`, updates `CHANGELOG.md`, and
143
+ creates a `vX.Y.Z` tag. Add `--yes --increment patch|minor|major` to skip the
144
+ interactive prompt (e.g. in scripts/CI).
145
+
146
+ 2. Push the tag:
147
+
148
+ ```bash
149
+ git push origin master --tags
150
+ ```
151
+
152
+ The `release` workflow builds the changelog for the tag and creates a GitHub
153
+ release. The `publish` workflow then publishes the package to PyPI.
154
+
155
+ #### One-time PyPI setup (trusted publishing)
156
+
157
+ The `publish` workflow uses PyPI trusted publishing (OIDC) — no API tokens stored.
158
+
159
+ - Enable 2FA on your PyPI and TestPyPI accounts (PyPI policy requirement).
160
+ - Register the project `pywayforpay` on PyPI (and TestPyPI).
161
+ - Add a trusted publisher on each: owner `HermanPlay`, repository `pywayforpay`,
162
+ workflow file `publish.yml`, environment `release`.
163
+
164
+ To validate a release against TestPyPI first, trigger the `publish` workflow manually
165
+ with repository `testpypi` (Actions tab → Publish to PyPI → Run workflow).
166
+
167
+ ## License
168
+
169
+ [MIT](LICENSE)
@@ -0,0 +1,35 @@
1
+ # Antifraud
2
+
3
+ The antifraud API (`AntifraudClient` / `AsyncAntifraudClient`) runs custom risk rules
4
+ against a proposed payment and reports back whether to accept or decline it.
5
+
6
+ It uses its own `login` / `password` (not merchant credentials):
7
+
8
+ ```python
9
+ from wayforpay import AntifraudClient
10
+ from wayforpay.models import AfValidateRequest
11
+
12
+ with AntifraudClient(login="af_login", password="af_password") as client:
13
+ result = client.validate(AfValidateRequest(...))
14
+ print(result.result) # AfResult.SUCCESS == 10
15
+ ```
16
+
17
+ ## Methods
18
+
19
+ - `validate(request, *, verify=False)` — run validation rules; returns `AfResponse`.
20
+ - `check_status(request, *, verify=False)` — check the status of a prior validation.
21
+
22
+ Setting `verify=True` forces a live check against the card issuer.
23
+
24
+ ## Result codes
25
+
26
+ `AfResponse.result` is an `AfResult` (`IntEnum`):
27
+
28
+ - `AfResult.SUCCESS` (`10`) — pass.
29
+ - Anything else is treated as failure and raises `ResponseError`.
30
+
31
+ Async equivalents are on `AsyncAntifraudClient`.
32
+
33
+ ## Reference
34
+
35
+ - WayForPay antifraud docs: <https://wiki.wayforpay.com/en/view/852223>
@@ -0,0 +1,17 @@
1
+ # Clients
2
+
3
+ ## Sync
4
+
5
+ ::: wayforpay.Client
6
+ ::: wayforpay.MMSClient
7
+ ::: wayforpay.AntifraudClient
8
+
9
+ ## Async
10
+
11
+ ::: wayforpay.AsyncClient
12
+ ::: wayforpay.AsyncMMSClient
13
+ ::: wayforpay.AsyncAntifraudClient
14
+
15
+ ## Credentials
16
+
17
+ ::: wayforpay.Credentials