easy-fints 1.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.
- easy_fints-1.2.0/LICENSE +21 -0
- easy_fints-1.2.0/PKG-INFO +369 -0
- easy_fints-1.2.0/README.md +342 -0
- easy_fints-1.2.0/easy_fints/__init__.py +69 -0
- easy_fints-1.2.0/easy_fints/cli.py +188 -0
- easy_fints-1.2.0/easy_fints/client.py +1249 -0
- easy_fints-1.2.0/easy_fints/diagnostics.py +58 -0
- easy_fints-1.2.0/easy_fints/env_config.py +27 -0
- easy_fints-1.2.0/easy_fints/exceptions.py +80 -0
- easy_fints-1.2.0/easy_fints/fastapi_app.py +1135 -0
- easy_fints-1.2.0/easy_fints/helpers.py +907 -0
- easy_fints-1.2.0/easy_fints/models.py +626 -0
- easy_fints-1.2.0/easy_fints/service.py +133 -0
- easy_fints-1.2.0/easy_fints.egg-info/PKG-INFO +369 -0
- easy_fints-1.2.0/easy_fints.egg-info/SOURCES.txt +29 -0
- easy_fints-1.2.0/easy_fints.egg-info/dependency_links.txt +1 -0
- easy_fints-1.2.0/easy_fints.egg-info/entry_points.txt +2 -0
- easy_fints-1.2.0/easy_fints.egg-info/requires.txt +9 -0
- easy_fints-1.2.0/easy_fints.egg-info/top_level.txt +1 -0
- easy_fints-1.2.0/pyproject.toml +48 -0
- easy_fints-1.2.0/setup.cfg +4 -0
- easy_fints-1.2.0/tests/test_api_read_flows.py +41 -0
- easy_fints-1.2.0/tests/test_api_session_lifecycle.py +48 -0
- easy_fints-1.2.0/tests/test_api_transfer_flows.py +116 -0
- easy_fints-1.2.0/tests/test_cli.py +142 -0
- easy_fints-1.2.0/tests/test_client_transfer_resume.py +84 -0
- easy_fints-1.2.0/tests/test_ing_patch.py +48 -0
- easy_fints-1.2.0/tests/test_logging_sanitization.py +64 -0
- easy_fints-1.2.0/tests/test_package_exports.py +14 -0
- easy_fints-1.2.0/tests/test_retry_detection.py +58 -0
- easy_fints-1.2.0/tests/test_service.py +96 -0
easy_fints-1.2.0/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 qhle
|
|
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,369 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: easy-fints
|
|
3
|
+
Version: 1.2.0
|
|
4
|
+
Summary: Python library and FastAPI wrapper around python-fints
|
|
5
|
+
Author: qhle
|
|
6
|
+
License-Expression: MIT
|
|
7
|
+
Project-URL: Homepage, https://github.com/QHLe/easy-fints
|
|
8
|
+
Project-URL: Repository, https://github.com/QHLe/easy-fints
|
|
9
|
+
Project-URL: Issues, https://github.com/QHLe/easy-fints/issues
|
|
10
|
+
Keywords: fints,hbci,fastapi,banking,rest,api
|
|
11
|
+
Classifier: Programming Language :: Python :: 3
|
|
12
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
13
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
14
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
15
|
+
Requires-Python: >=3.11
|
|
16
|
+
Description-Content-Type: text/markdown
|
|
17
|
+
License-File: LICENSE
|
|
18
|
+
Requires-Dist: fastapi
|
|
19
|
+
Requires-Dist: uvicorn[standard]
|
|
20
|
+
Requires-Dist: fints
|
|
21
|
+
Requires-Dist: Markdown
|
|
22
|
+
Requires-Dist: python-dotenv
|
|
23
|
+
Provides-Extra: dev
|
|
24
|
+
Requires-Dist: build; extra == "dev"
|
|
25
|
+
Requires-Dist: pytest; extra == "dev"
|
|
26
|
+
Dynamic: license-file
|
|
27
|
+
|
|
28
|
+
# easy-fints
|
|
29
|
+
|
|
30
|
+
Python library with an optional FastAPI wrapper around `python-fints`.
|
|
31
|
+
|
|
32
|
+
PyPI package:
|
|
33
|
+
|
|
34
|
+
- `easy-fints`
|
|
35
|
+
|
|
36
|
+
Python import package:
|
|
37
|
+
|
|
38
|
+
- `easy_fints`
|
|
39
|
+
|
|
40
|
+
It currently supports:
|
|
41
|
+
|
|
42
|
+
- account listing
|
|
43
|
+
- balances
|
|
44
|
+
- transactions
|
|
45
|
+
- SEPA transfers
|
|
46
|
+
- TAN / decoupled confirmation flows
|
|
47
|
+
- payee verification (`VoP`) continuation
|
|
48
|
+
|
|
49
|
+
The package can be used in three ways:
|
|
50
|
+
|
|
51
|
+
- as a Python library
|
|
52
|
+
- as a FastAPI-based REST server
|
|
53
|
+
- as a Dockerized REST server
|
|
54
|
+
|
|
55
|
+
## Quick Start
|
|
56
|
+
|
|
57
|
+
Requirements:
|
|
58
|
+
|
|
59
|
+
- Python 3.11+
|
|
60
|
+
- a bank account with FinTS/HBCI access
|
|
61
|
+
- valid FinTS credentials and server URL
|
|
62
|
+
|
|
63
|
+
Install from PyPI:
|
|
64
|
+
|
|
65
|
+
```bash
|
|
66
|
+
pip install easy-fints
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
For local development:
|
|
70
|
+
|
|
71
|
+
```bash
|
|
72
|
+
python -m venv .venv
|
|
73
|
+
source .venv/bin/activate
|
|
74
|
+
pip install -e .[dev]
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
Minimal `.env`:
|
|
78
|
+
|
|
79
|
+
```env
|
|
80
|
+
FINTS_PRODUCT_ID=YourProductID
|
|
81
|
+
FINTS_PRODUCT_NAME=YourProductName
|
|
82
|
+
FINTS_PRODUCT_VERSION=YourProductVersion
|
|
83
|
+
FINTS_SESSION_TTL_SECONDS=300
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
A FinTS product ID can be requested via the official registration page:
|
|
87
|
+
|
|
88
|
+
- `https://www.fints.org/de/hersteller/produktregistrierung`
|
|
89
|
+
|
|
90
|
+
## Usage Modes
|
|
91
|
+
|
|
92
|
+
- `Library`: import `FinTS` directly in your Python application
|
|
93
|
+
- `REST server`: run the built-in FastAPI service locally
|
|
94
|
+
- `Docker`: run the REST server through `Dockerfile` or `docker-compose.yml`
|
|
95
|
+
|
|
96
|
+
## Library
|
|
97
|
+
|
|
98
|
+
Use the package directly in Python:
|
|
99
|
+
|
|
100
|
+
```python
|
|
101
|
+
from easy_fints import (
|
|
102
|
+
FinTS,
|
|
103
|
+
TanRequiredError,
|
|
104
|
+
)
|
|
105
|
+
|
|
106
|
+
with FinTS(
|
|
107
|
+
product_id="YourProductID",
|
|
108
|
+
bank="12345678",
|
|
109
|
+
user="your-user",
|
|
110
|
+
pin="your-pin",
|
|
111
|
+
server="https://bank.example/fints",
|
|
112
|
+
) as fints:
|
|
113
|
+
try:
|
|
114
|
+
accounts = fints.accounts()
|
|
115
|
+
transactions = fints.transactions(days=30)
|
|
116
|
+
except TanRequiredError as exc:
|
|
117
|
+
print(exc.challenge.message)
|
|
118
|
+
```
|
|
119
|
+
|
|
120
|
+
## REST Server
|
|
121
|
+
|
|
122
|
+
Run the optional local HTTP server with the bundled CLI:
|
|
123
|
+
|
|
124
|
+
```bash
|
|
125
|
+
fints-rest-server start
|
|
126
|
+
fints-rest-server status
|
|
127
|
+
fints-rest-server stop
|
|
128
|
+
```
|
|
129
|
+
|
|
130
|
+
Configuration priority for the CLI:
|
|
131
|
+
|
|
132
|
+
- explicit CLI flags like `--host` or `--port`
|
|
133
|
+
- values loaded from `--env-file`
|
|
134
|
+
- process environment variables
|
|
135
|
+
- built-in defaults
|
|
136
|
+
|
|
137
|
+
Installed CLI defaults:
|
|
138
|
+
|
|
139
|
+
- server host: `0.0.0.0`
|
|
140
|
+
- server port: `8000`
|
|
141
|
+
- PID file: `.fints-rest-server.pid`
|
|
142
|
+
- log file: `.fints-rest-server.log`
|
|
143
|
+
|
|
144
|
+
CLI examples:
|
|
145
|
+
|
|
146
|
+
```bash
|
|
147
|
+
fints-rest-server start --host 127.0.0.1 --port 9686
|
|
148
|
+
fints-rest-server start --env-file /etc/easy-fints.env
|
|
149
|
+
fints-rest-server stop
|
|
150
|
+
```
|
|
151
|
+
|
|
152
|
+
OpenAPI:
|
|
153
|
+
|
|
154
|
+
- `http://127.0.0.1:8000/docs`
|
|
155
|
+
- `http://127.0.0.1:8000/openapi.json`
|
|
156
|
+
|
|
157
|
+
## Docker
|
|
158
|
+
|
|
159
|
+
The repository includes both [`Dockerfile`](Dockerfile) and [`docker-compose.yml`](docker-compose.yml).
|
|
160
|
+
|
|
161
|
+
Start the REST server with Docker Compose:
|
|
162
|
+
|
|
163
|
+
```bash
|
|
164
|
+
docker compose up --build -d
|
|
165
|
+
docker compose logs -f api
|
|
166
|
+
docker compose down
|
|
167
|
+
```
|
|
168
|
+
|
|
169
|
+
Current Docker defaults:
|
|
170
|
+
|
|
171
|
+
- container port: `9686`
|
|
172
|
+
- published port: `9686`
|
|
173
|
+
- env file: `.env`
|
|
174
|
+
- log volume: `./logs:/app/logs`
|
|
175
|
+
|
|
176
|
+
Docker OpenAPI:
|
|
177
|
+
|
|
178
|
+
- `http://127.0.0.1:9686/docs`
|
|
179
|
+
- `http://127.0.0.1:9686/openapi.json`
|
|
180
|
+
|
|
181
|
+
## REST API
|
|
182
|
+
|
|
183
|
+
Optional HTTP endpoints:
|
|
184
|
+
|
|
185
|
+
- `GET /health`
|
|
186
|
+
- `POST /accounts`
|
|
187
|
+
- `POST /balance`
|
|
188
|
+
- `POST /transactions`
|
|
189
|
+
- `POST /transfer`
|
|
190
|
+
- `POST /transfer/retry-with-name`
|
|
191
|
+
- `POST /confirm`
|
|
192
|
+
- `GET /sessions/{session_id}`
|
|
193
|
+
- `DELETE /sessions/{session_id}`
|
|
194
|
+
|
|
195
|
+
All operation endpoints accept a JSON body with a `config` object. Request values override env defaults.
|
|
196
|
+
|
|
197
|
+
Supported `config` fields:
|
|
198
|
+
|
|
199
|
+
- `bank`
|
|
200
|
+
- `user`
|
|
201
|
+
- `pin`
|
|
202
|
+
- `server`
|
|
203
|
+
|
|
204
|
+
## Transfer Support
|
|
205
|
+
|
|
206
|
+
`POST /transfer` supports a single SEPA credit transfer per request.
|
|
207
|
+
|
|
208
|
+
Transfer request fields:
|
|
209
|
+
|
|
210
|
+
- `source_account`
|
|
211
|
+
- `account_name`
|
|
212
|
+
- `recipient_name`
|
|
213
|
+
- `recipient_iban`
|
|
214
|
+
- `recipient_bic`
|
|
215
|
+
- `amount`
|
|
216
|
+
- `purpose`
|
|
217
|
+
- `endtoend_id`
|
|
218
|
+
- `instant_payment`
|
|
219
|
+
- `execution_date`
|
|
220
|
+
|
|
221
|
+
Current behavior:
|
|
222
|
+
|
|
223
|
+
- `account_name` is required because `python-fints.simple_sepa_transfer(...)` expects the sender name explicitly
|
|
224
|
+
- `instant_payment=true` requests SCT Inst when the bank supports it
|
|
225
|
+
- `execution_date=YYYY-MM-DD` requests a dated transfer
|
|
226
|
+
- `instant_payment` and `execution_date` cannot be combined
|
|
227
|
+
- unsupported transfer products return HTTP `422` with `error="unsupported_transfer_product"`
|
|
228
|
+
- transfer challenge responses and final transfer responses include `transfer_overview`
|
|
229
|
+
|
|
230
|
+
## Confirmation Flow
|
|
231
|
+
|
|
232
|
+
The API uses a session-based confirmation flow.
|
|
233
|
+
|
|
234
|
+
Typical sequence:
|
|
235
|
+
|
|
236
|
+
1. `POST /transfer` or another operation endpoint
|
|
237
|
+
2. either immediate `200`, or a challenge response like `409 tan_required`
|
|
238
|
+
3. continue with `POST /confirm`
|
|
239
|
+
4. repeat `/confirm` for decoupled app confirmation if needed
|
|
240
|
+
5. for payee verification, call `/confirm` with `approve_vop=true`
|
|
241
|
+
6. if the recipient name should be corrected after VoP, call `POST /transfer/retry-with-name`
|
|
242
|
+
|
|
243
|
+
Session helpers:
|
|
244
|
+
|
|
245
|
+
- `GET /sessions/{session_id}` inspects the current state
|
|
246
|
+
- `DELETE /sessions/{session_id}` cancels the active session
|
|
247
|
+
|
|
248
|
+
Session states currently used:
|
|
249
|
+
|
|
250
|
+
- `awaiting_tan`
|
|
251
|
+
- `awaiting_decoupled`
|
|
252
|
+
- `awaiting_vop`
|
|
253
|
+
- `running`
|
|
254
|
+
- `resuming`
|
|
255
|
+
|
|
256
|
+
Sessions are:
|
|
257
|
+
|
|
258
|
+
- stored in memory only
|
|
259
|
+
- process-local
|
|
260
|
+
- expired after an inactivity TTL
|
|
261
|
+
|
|
262
|
+
The TTL defaults to `300` seconds and can be changed with `FINTS_SESSION_TTL_SECONDS`.
|
|
263
|
+
|
|
264
|
+
## Examples
|
|
265
|
+
|
|
266
|
+
The repository includes small scripts for manual API testing:
|
|
267
|
+
|
|
268
|
+
Library examples:
|
|
269
|
+
|
|
270
|
+
- [`examples/accounts_lib.py`](examples/accounts_lib.py)
|
|
271
|
+
- [`examples/balance_lib.py`](examples/balance_lib.py)
|
|
272
|
+
- [`examples/transactions_lib.py`](examples/transactions_lib.py)
|
|
273
|
+
- [`examples/single_account_lib.py`](examples/single_account_lib.py)
|
|
274
|
+
- [`examples/transfer_lib.py`](examples/transfer_lib.py)
|
|
275
|
+
|
|
276
|
+
They use [`examples/lib_helper.py`](examples/lib_helper.py) and talk directly to `FinTS`.
|
|
277
|
+
|
|
278
|
+
REST API examples:
|
|
279
|
+
|
|
280
|
+
- [`examples/accounts_api_tan.py`](examples/accounts_api_tan.py)
|
|
281
|
+
- [`examples/balance_api_tan.py`](examples/balance_api_tan.py)
|
|
282
|
+
- [`examples/transactions_api_tan.py`](examples/transactions_api_tan.py)
|
|
283
|
+
- [`examples/single_account_api_tan.py`](examples/single_account_api_tan.py)
|
|
284
|
+
- [`examples/transfer_api_tan.py`](examples/transfer_api_tan.py)
|
|
285
|
+
|
|
286
|
+
They use [`examples/api_tan_helper.py`](examples/api_tan_helper.py) and read credentials from `.env`.
|
|
287
|
+
|
|
288
|
+
Optional helper-script env vars for manual transfer runs only:
|
|
289
|
+
|
|
290
|
+
- `FINTS_TRANSFER_INSTANT_PAYMENT=true`
|
|
291
|
+
- `FINTS_TRANSFER_EXECUTION_DATE=YYYY-MM-DD`
|
|
292
|
+
|
|
293
|
+
## Documentation
|
|
294
|
+
|
|
295
|
+
Detailed REST API reference:
|
|
296
|
+
|
|
297
|
+
- [`docs/API.md`](docs/API.md)
|
|
298
|
+
|
|
299
|
+
Transfer workflow:
|
|
300
|
+
|
|
301
|
+
- [`POST_transfer_workflow.md`](POST_transfer_workflow.md)
|
|
302
|
+
|
|
303
|
+
High-level testing/verification notes:
|
|
304
|
+
|
|
305
|
+
- [`USECASE.md`](USECASE.md)
|
|
306
|
+
- [`VERIFICATION.md`](VERIFICATION.md)
|
|
307
|
+
|
|
308
|
+
## Development
|
|
309
|
+
|
|
310
|
+
Important files:
|
|
311
|
+
|
|
312
|
+
- [`easy_fints/fastapi_app.py`](easy_fints/fastapi_app.py)
|
|
313
|
+
- [`easy_fints/client.py`](easy_fints/client.py)
|
|
314
|
+
- [`easy_fints/helpers.py`](easy_fints/helpers.py)
|
|
315
|
+
- [`easy_fints/models.py`](easy_fints/models.py)
|
|
316
|
+
|
|
317
|
+
Basic checks:
|
|
318
|
+
|
|
319
|
+
```bash
|
|
320
|
+
python -m compileall easy_fints examples
|
|
321
|
+
.venv/bin/python -m pytest tests -q
|
|
322
|
+
```
|
|
323
|
+
|
|
324
|
+
Package build:
|
|
325
|
+
|
|
326
|
+
```bash
|
|
327
|
+
python -m build
|
|
328
|
+
```
|
|
329
|
+
|
|
330
|
+
GitHub Actions:
|
|
331
|
+
|
|
332
|
+
- CI runs on pushes to `main` and on pull requests
|
|
333
|
+
- publishing to PyPI runs when a GitHub Release is published
|
|
334
|
+
|
|
335
|
+
## Packaging
|
|
336
|
+
|
|
337
|
+
Package name on PyPI:
|
|
338
|
+
|
|
339
|
+
- `easy-fints`
|
|
340
|
+
|
|
341
|
+
Import package in Python:
|
|
342
|
+
|
|
343
|
+
- `easy_fints`
|
|
344
|
+
|
|
345
|
+
Install from PyPI after the first published release:
|
|
346
|
+
|
|
347
|
+
```bash
|
|
348
|
+
pip install easy-fints
|
|
349
|
+
```
|
|
350
|
+
|
|
351
|
+
## Deployment Notes
|
|
352
|
+
|
|
353
|
+
This project intentionally keeps the API simple:
|
|
354
|
+
|
|
355
|
+
- no server-side profile model
|
|
356
|
+
- no persistent credential store
|
|
357
|
+
- no server-managed account data
|
|
358
|
+
- no built-in authentication layer
|
|
359
|
+
|
|
360
|
+
Recommended deployment style:
|
|
361
|
+
|
|
362
|
+
- trusted network only
|
|
363
|
+
- TLS at the edge
|
|
364
|
+
- optional reverse proxy, VPN, mTLS, or network isolation depending on your stack
|
|
365
|
+
- operation logs are sanitized by default and do not store raw PINs, TANs, or raw FinTS payloads
|
|
366
|
+
|
|
367
|
+
Current limitation:
|
|
368
|
+
|
|
369
|
+
- active confirmation sessions are in-memory and process-local, so the simplest supported runtime is a single API process
|
|
@@ -0,0 +1,342 @@
|
|
|
1
|
+
# easy-fints
|
|
2
|
+
|
|
3
|
+
Python library with an optional FastAPI wrapper around `python-fints`.
|
|
4
|
+
|
|
5
|
+
PyPI package:
|
|
6
|
+
|
|
7
|
+
- `easy-fints`
|
|
8
|
+
|
|
9
|
+
Python import package:
|
|
10
|
+
|
|
11
|
+
- `easy_fints`
|
|
12
|
+
|
|
13
|
+
It currently supports:
|
|
14
|
+
|
|
15
|
+
- account listing
|
|
16
|
+
- balances
|
|
17
|
+
- transactions
|
|
18
|
+
- SEPA transfers
|
|
19
|
+
- TAN / decoupled confirmation flows
|
|
20
|
+
- payee verification (`VoP`) continuation
|
|
21
|
+
|
|
22
|
+
The package can be used in three ways:
|
|
23
|
+
|
|
24
|
+
- as a Python library
|
|
25
|
+
- as a FastAPI-based REST server
|
|
26
|
+
- as a Dockerized REST server
|
|
27
|
+
|
|
28
|
+
## Quick Start
|
|
29
|
+
|
|
30
|
+
Requirements:
|
|
31
|
+
|
|
32
|
+
- Python 3.11+
|
|
33
|
+
- a bank account with FinTS/HBCI access
|
|
34
|
+
- valid FinTS credentials and server URL
|
|
35
|
+
|
|
36
|
+
Install from PyPI:
|
|
37
|
+
|
|
38
|
+
```bash
|
|
39
|
+
pip install easy-fints
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
For local development:
|
|
43
|
+
|
|
44
|
+
```bash
|
|
45
|
+
python -m venv .venv
|
|
46
|
+
source .venv/bin/activate
|
|
47
|
+
pip install -e .[dev]
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
Minimal `.env`:
|
|
51
|
+
|
|
52
|
+
```env
|
|
53
|
+
FINTS_PRODUCT_ID=YourProductID
|
|
54
|
+
FINTS_PRODUCT_NAME=YourProductName
|
|
55
|
+
FINTS_PRODUCT_VERSION=YourProductVersion
|
|
56
|
+
FINTS_SESSION_TTL_SECONDS=300
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
A FinTS product ID can be requested via the official registration page:
|
|
60
|
+
|
|
61
|
+
- `https://www.fints.org/de/hersteller/produktregistrierung`
|
|
62
|
+
|
|
63
|
+
## Usage Modes
|
|
64
|
+
|
|
65
|
+
- `Library`: import `FinTS` directly in your Python application
|
|
66
|
+
- `REST server`: run the built-in FastAPI service locally
|
|
67
|
+
- `Docker`: run the REST server through `Dockerfile` or `docker-compose.yml`
|
|
68
|
+
|
|
69
|
+
## Library
|
|
70
|
+
|
|
71
|
+
Use the package directly in Python:
|
|
72
|
+
|
|
73
|
+
```python
|
|
74
|
+
from easy_fints import (
|
|
75
|
+
FinTS,
|
|
76
|
+
TanRequiredError,
|
|
77
|
+
)
|
|
78
|
+
|
|
79
|
+
with FinTS(
|
|
80
|
+
product_id="YourProductID",
|
|
81
|
+
bank="12345678",
|
|
82
|
+
user="your-user",
|
|
83
|
+
pin="your-pin",
|
|
84
|
+
server="https://bank.example/fints",
|
|
85
|
+
) as fints:
|
|
86
|
+
try:
|
|
87
|
+
accounts = fints.accounts()
|
|
88
|
+
transactions = fints.transactions(days=30)
|
|
89
|
+
except TanRequiredError as exc:
|
|
90
|
+
print(exc.challenge.message)
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
## REST Server
|
|
94
|
+
|
|
95
|
+
Run the optional local HTTP server with the bundled CLI:
|
|
96
|
+
|
|
97
|
+
```bash
|
|
98
|
+
fints-rest-server start
|
|
99
|
+
fints-rest-server status
|
|
100
|
+
fints-rest-server stop
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
Configuration priority for the CLI:
|
|
104
|
+
|
|
105
|
+
- explicit CLI flags like `--host` or `--port`
|
|
106
|
+
- values loaded from `--env-file`
|
|
107
|
+
- process environment variables
|
|
108
|
+
- built-in defaults
|
|
109
|
+
|
|
110
|
+
Installed CLI defaults:
|
|
111
|
+
|
|
112
|
+
- server host: `0.0.0.0`
|
|
113
|
+
- server port: `8000`
|
|
114
|
+
- PID file: `.fints-rest-server.pid`
|
|
115
|
+
- log file: `.fints-rest-server.log`
|
|
116
|
+
|
|
117
|
+
CLI examples:
|
|
118
|
+
|
|
119
|
+
```bash
|
|
120
|
+
fints-rest-server start --host 127.0.0.1 --port 9686
|
|
121
|
+
fints-rest-server start --env-file /etc/easy-fints.env
|
|
122
|
+
fints-rest-server stop
|
|
123
|
+
```
|
|
124
|
+
|
|
125
|
+
OpenAPI:
|
|
126
|
+
|
|
127
|
+
- `http://127.0.0.1:8000/docs`
|
|
128
|
+
- `http://127.0.0.1:8000/openapi.json`
|
|
129
|
+
|
|
130
|
+
## Docker
|
|
131
|
+
|
|
132
|
+
The repository includes both [`Dockerfile`](Dockerfile) and [`docker-compose.yml`](docker-compose.yml).
|
|
133
|
+
|
|
134
|
+
Start the REST server with Docker Compose:
|
|
135
|
+
|
|
136
|
+
```bash
|
|
137
|
+
docker compose up --build -d
|
|
138
|
+
docker compose logs -f api
|
|
139
|
+
docker compose down
|
|
140
|
+
```
|
|
141
|
+
|
|
142
|
+
Current Docker defaults:
|
|
143
|
+
|
|
144
|
+
- container port: `9686`
|
|
145
|
+
- published port: `9686`
|
|
146
|
+
- env file: `.env`
|
|
147
|
+
- log volume: `./logs:/app/logs`
|
|
148
|
+
|
|
149
|
+
Docker OpenAPI:
|
|
150
|
+
|
|
151
|
+
- `http://127.0.0.1:9686/docs`
|
|
152
|
+
- `http://127.0.0.1:9686/openapi.json`
|
|
153
|
+
|
|
154
|
+
## REST API
|
|
155
|
+
|
|
156
|
+
Optional HTTP endpoints:
|
|
157
|
+
|
|
158
|
+
- `GET /health`
|
|
159
|
+
- `POST /accounts`
|
|
160
|
+
- `POST /balance`
|
|
161
|
+
- `POST /transactions`
|
|
162
|
+
- `POST /transfer`
|
|
163
|
+
- `POST /transfer/retry-with-name`
|
|
164
|
+
- `POST /confirm`
|
|
165
|
+
- `GET /sessions/{session_id}`
|
|
166
|
+
- `DELETE /sessions/{session_id}`
|
|
167
|
+
|
|
168
|
+
All operation endpoints accept a JSON body with a `config` object. Request values override env defaults.
|
|
169
|
+
|
|
170
|
+
Supported `config` fields:
|
|
171
|
+
|
|
172
|
+
- `bank`
|
|
173
|
+
- `user`
|
|
174
|
+
- `pin`
|
|
175
|
+
- `server`
|
|
176
|
+
|
|
177
|
+
## Transfer Support
|
|
178
|
+
|
|
179
|
+
`POST /transfer` supports a single SEPA credit transfer per request.
|
|
180
|
+
|
|
181
|
+
Transfer request fields:
|
|
182
|
+
|
|
183
|
+
- `source_account`
|
|
184
|
+
- `account_name`
|
|
185
|
+
- `recipient_name`
|
|
186
|
+
- `recipient_iban`
|
|
187
|
+
- `recipient_bic`
|
|
188
|
+
- `amount`
|
|
189
|
+
- `purpose`
|
|
190
|
+
- `endtoend_id`
|
|
191
|
+
- `instant_payment`
|
|
192
|
+
- `execution_date`
|
|
193
|
+
|
|
194
|
+
Current behavior:
|
|
195
|
+
|
|
196
|
+
- `account_name` is required because `python-fints.simple_sepa_transfer(...)` expects the sender name explicitly
|
|
197
|
+
- `instant_payment=true` requests SCT Inst when the bank supports it
|
|
198
|
+
- `execution_date=YYYY-MM-DD` requests a dated transfer
|
|
199
|
+
- `instant_payment` and `execution_date` cannot be combined
|
|
200
|
+
- unsupported transfer products return HTTP `422` with `error="unsupported_transfer_product"`
|
|
201
|
+
- transfer challenge responses and final transfer responses include `transfer_overview`
|
|
202
|
+
|
|
203
|
+
## Confirmation Flow
|
|
204
|
+
|
|
205
|
+
The API uses a session-based confirmation flow.
|
|
206
|
+
|
|
207
|
+
Typical sequence:
|
|
208
|
+
|
|
209
|
+
1. `POST /transfer` or another operation endpoint
|
|
210
|
+
2. either immediate `200`, or a challenge response like `409 tan_required`
|
|
211
|
+
3. continue with `POST /confirm`
|
|
212
|
+
4. repeat `/confirm` for decoupled app confirmation if needed
|
|
213
|
+
5. for payee verification, call `/confirm` with `approve_vop=true`
|
|
214
|
+
6. if the recipient name should be corrected after VoP, call `POST /transfer/retry-with-name`
|
|
215
|
+
|
|
216
|
+
Session helpers:
|
|
217
|
+
|
|
218
|
+
- `GET /sessions/{session_id}` inspects the current state
|
|
219
|
+
- `DELETE /sessions/{session_id}` cancels the active session
|
|
220
|
+
|
|
221
|
+
Session states currently used:
|
|
222
|
+
|
|
223
|
+
- `awaiting_tan`
|
|
224
|
+
- `awaiting_decoupled`
|
|
225
|
+
- `awaiting_vop`
|
|
226
|
+
- `running`
|
|
227
|
+
- `resuming`
|
|
228
|
+
|
|
229
|
+
Sessions are:
|
|
230
|
+
|
|
231
|
+
- stored in memory only
|
|
232
|
+
- process-local
|
|
233
|
+
- expired after an inactivity TTL
|
|
234
|
+
|
|
235
|
+
The TTL defaults to `300` seconds and can be changed with `FINTS_SESSION_TTL_SECONDS`.
|
|
236
|
+
|
|
237
|
+
## Examples
|
|
238
|
+
|
|
239
|
+
The repository includes small scripts for manual API testing:
|
|
240
|
+
|
|
241
|
+
Library examples:
|
|
242
|
+
|
|
243
|
+
- [`examples/accounts_lib.py`](examples/accounts_lib.py)
|
|
244
|
+
- [`examples/balance_lib.py`](examples/balance_lib.py)
|
|
245
|
+
- [`examples/transactions_lib.py`](examples/transactions_lib.py)
|
|
246
|
+
- [`examples/single_account_lib.py`](examples/single_account_lib.py)
|
|
247
|
+
- [`examples/transfer_lib.py`](examples/transfer_lib.py)
|
|
248
|
+
|
|
249
|
+
They use [`examples/lib_helper.py`](examples/lib_helper.py) and talk directly to `FinTS`.
|
|
250
|
+
|
|
251
|
+
REST API examples:
|
|
252
|
+
|
|
253
|
+
- [`examples/accounts_api_tan.py`](examples/accounts_api_tan.py)
|
|
254
|
+
- [`examples/balance_api_tan.py`](examples/balance_api_tan.py)
|
|
255
|
+
- [`examples/transactions_api_tan.py`](examples/transactions_api_tan.py)
|
|
256
|
+
- [`examples/single_account_api_tan.py`](examples/single_account_api_tan.py)
|
|
257
|
+
- [`examples/transfer_api_tan.py`](examples/transfer_api_tan.py)
|
|
258
|
+
|
|
259
|
+
They use [`examples/api_tan_helper.py`](examples/api_tan_helper.py) and read credentials from `.env`.
|
|
260
|
+
|
|
261
|
+
Optional helper-script env vars for manual transfer runs only:
|
|
262
|
+
|
|
263
|
+
- `FINTS_TRANSFER_INSTANT_PAYMENT=true`
|
|
264
|
+
- `FINTS_TRANSFER_EXECUTION_DATE=YYYY-MM-DD`
|
|
265
|
+
|
|
266
|
+
## Documentation
|
|
267
|
+
|
|
268
|
+
Detailed REST API reference:
|
|
269
|
+
|
|
270
|
+
- [`docs/API.md`](docs/API.md)
|
|
271
|
+
|
|
272
|
+
Transfer workflow:
|
|
273
|
+
|
|
274
|
+
- [`POST_transfer_workflow.md`](POST_transfer_workflow.md)
|
|
275
|
+
|
|
276
|
+
High-level testing/verification notes:
|
|
277
|
+
|
|
278
|
+
- [`USECASE.md`](USECASE.md)
|
|
279
|
+
- [`VERIFICATION.md`](VERIFICATION.md)
|
|
280
|
+
|
|
281
|
+
## Development
|
|
282
|
+
|
|
283
|
+
Important files:
|
|
284
|
+
|
|
285
|
+
- [`easy_fints/fastapi_app.py`](easy_fints/fastapi_app.py)
|
|
286
|
+
- [`easy_fints/client.py`](easy_fints/client.py)
|
|
287
|
+
- [`easy_fints/helpers.py`](easy_fints/helpers.py)
|
|
288
|
+
- [`easy_fints/models.py`](easy_fints/models.py)
|
|
289
|
+
|
|
290
|
+
Basic checks:
|
|
291
|
+
|
|
292
|
+
```bash
|
|
293
|
+
python -m compileall easy_fints examples
|
|
294
|
+
.venv/bin/python -m pytest tests -q
|
|
295
|
+
```
|
|
296
|
+
|
|
297
|
+
Package build:
|
|
298
|
+
|
|
299
|
+
```bash
|
|
300
|
+
python -m build
|
|
301
|
+
```
|
|
302
|
+
|
|
303
|
+
GitHub Actions:
|
|
304
|
+
|
|
305
|
+
- CI runs on pushes to `main` and on pull requests
|
|
306
|
+
- publishing to PyPI runs when a GitHub Release is published
|
|
307
|
+
|
|
308
|
+
## Packaging
|
|
309
|
+
|
|
310
|
+
Package name on PyPI:
|
|
311
|
+
|
|
312
|
+
- `easy-fints`
|
|
313
|
+
|
|
314
|
+
Import package in Python:
|
|
315
|
+
|
|
316
|
+
- `easy_fints`
|
|
317
|
+
|
|
318
|
+
Install from PyPI after the first published release:
|
|
319
|
+
|
|
320
|
+
```bash
|
|
321
|
+
pip install easy-fints
|
|
322
|
+
```
|
|
323
|
+
|
|
324
|
+
## Deployment Notes
|
|
325
|
+
|
|
326
|
+
This project intentionally keeps the API simple:
|
|
327
|
+
|
|
328
|
+
- no server-side profile model
|
|
329
|
+
- no persistent credential store
|
|
330
|
+
- no server-managed account data
|
|
331
|
+
- no built-in authentication layer
|
|
332
|
+
|
|
333
|
+
Recommended deployment style:
|
|
334
|
+
|
|
335
|
+
- trusted network only
|
|
336
|
+
- TLS at the edge
|
|
337
|
+
- optional reverse proxy, VPN, mTLS, or network isolation depending on your stack
|
|
338
|
+
- operation logs are sanitized by default and do not store raw PINs, TANs, or raw FinTS payloads
|
|
339
|
+
|
|
340
|
+
Current limitation:
|
|
341
|
+
|
|
342
|
+
- active confirmation sessions are in-memory and process-local, so the simplest supported runtime is a single API process
|