Modern, typed async Python SDK for the Powens API.
Project description
py-powens
Unofficial, third-party SDK. Not affiliated with or endorsed by Powens. "Powens" is used here only to describe compatibility with the Powens API. Users of this SDK are bound by Powens' own Terms of Service.
Status
Alpha (0.x) — the public surface may still change in minor versions
until 1.0. Pin strictly (py-powens==0.1.*) for reproducibility.
Semantic versioning applies from 1.0.0 onwards.
A modern, typed, async-only Python SDK for the Powens banking API, built 1:1 from the public API reference.
- Python 3.13+, fully typed,
py.typed. - Async-only on top of
httpx. - Immutable Pydantic v2 models, permissive on unknown fields.
- Both paginations supported: offset (most endpoints) and relational
cursor (
_links.next.href, used by transactions). - Typed exception hierarchy that parses the Powens error envelope
{ code, description, message, request_id }. - Light retry on transient errors + injectable circuit breaker.
- Composition over inheritance — inject an
httpx.AsyncClientor a test transport for full control.
The SDK speaks to the Powens API and nothing else: no DB, no cache, no scheduler, no cross-provider abstractions. Anything beyond "talk to the Powens API" is the caller's job.
Installation
uv add py-powens # recommended
pip install py-powens
poetry add py-powens
Requires Python 3.13+. Runtime dependencies: httpx and pydantic (v2).
30-second example
import asyncio
from powens import PowensClient
async def main() -> None:
async with PowensClient(
base_url="https://demo.biapi.pro/2.0",
access_token="<USER_TOKEN>",
) as client:
async for account in client.accounts.list_all():
print(account.id, account.name, account.balance)
asyncio.run(main())
Quickstart
import asyncio
from powens import PowensClient
async def main() -> None:
async with PowensClient(
base_url="https://your-domain.biapi.pro/2.0",
access_token="<USER_TOKEN>",
) as client:
# Offset-paginated listing
async for conn in client.connections.list():
print(conn.id, conn.state)
# Cursor-paginated listing (transactions)
async for tx in client.transactions.list(limit=500):
print(tx.id, tx.value, tx.wording)
asyncio.run(main())
Authentication
The SDK exposes every documented auth endpoint:
# Create a new end-user
token = await c.auth.init_user(client_id="...", client_secret="...")
c.set_access_token(token.auth_token)
# Generate a temporary webview code
code = await c.auth.generate_code(type_="singleAccess")
# Exchange a code for a permanent token
permanent = await c.auth.exchange_code(
code=code.code, client_id="...", client_secret="...",
)
# Renew a token (for a known user)
new = await c.auth.renew_token(
client_id="...", client_secret="...", id_user=42,
)
# Revoke the current permanent token
await c.auth.revoke_token()
# Issue a service token (Pay product)
svc = await c.auth.generate_service_token(
client_id="...", client_secret="...",
scope="payments:admin",
)
Webview
The Powens webview is served from a separate host
(https://webview.powens.com/{lang}/{flow}). The SDK exposes URL
builders — no HTTP call is issued:
url = client.webview.connect_url(
client_id="...",
redirect_uri="https://your-app/cb",
lang="fr",
connector_capabilities=["bank"],
).url
Four flows are supported: connect, reconnect, manage, payment.
For the separate /webauth-url API endpoint (not the webview), use
client.connections.webauth_url(...).
Resources
| Resource | Coverage |
|---|---|
client.auth |
init_user, generate_code, exchange_code, revoke_token, renew_token, generate_service_token |
client.users |
me, get(id), list_all, delete |
client.connectors |
list, get, update, batch_update, list_sources, get_source, update_source |
client.connections |
create, list, list_all, get, update (incl. OTP via fields), sync, delete, list_sources, get_source, update_source, webauth_url, list_logs_raw |
client.accounts |
list, list_all (envelope with balances/coming_balances), get, update |
client.account_types |
list, get |
client.currencies |
list |
client.transactions |
list (cursor), list_page, get, update |
client.investments |
list, list_all (portfolio aggregates), get, history |
client.market_orders |
list, get |
client.pockets |
list, get |
client.loan_amortizations |
list |
client.balances |
get |
client.account_ownerships |
list (feature-gated) |
client.indicators |
get |
client.webview |
connect_url, reconnect_url, manage_url, payment_url |
Pagination
# Offset (connections, accounts, investments, market orders, …)
async for c in client.connections.list():
...
async for page in client.connections.list(limit=50).by_page():
print(page.total, [c.id for c in page.items])
# Relational cursor (transactions)
async for tx in client.transactions.list(limit=1000):
...
# Single-page call that exposes the envelope dates
env = await client.transactions.list_page(
account_id=1, min_date=date(2024, 1, 1),
)
print(env.first_date, env.last_date)
Error handling
The SDK parses the common Powens error envelope and exposes a typed
hierarchy. Powens explicitly recommends branching on error_code over
HTTP status — so PowensHTTPError.error_code is a first-class attribute.
PowensError
├── PowensHTTPError # base (has .error_code, .error_description, ...)
│ ├── PowensBadRequestError # 400
│ ├── PowensAuthError # 401 / 403
│ ├── PowensNotFoundError # 404
│ ├── PowensConflictError # 409
│ ├── PowensRateLimitError # 429 (has .retry_after)
│ ├── PowensServerError # 500
│ └── PowensServiceUnavailableError# 503
├── PowensConnectionError # network failure
├── PowensSerializationError # response shape mismatch
└── PowensCircuitOpenError # injected breaker short-circuited
from powens import PowensErrorCode, PowensHTTPError
try:
await client.accounts.get(account_id=999)
except PowensHTTPError as err:
if err.error_code == PowensErrorCode.WRONG_PASS.value:
...
Retry + circuit breaker
Transient retries apply to network errors, 429, 502, 503, 504 — never 500 (a 500 on a finance API is ambiguous; silently retrying write requests risks double-effects). Only idempotent verbs (GET/HEAD/OPTIONS/PUT/DELETE) are retried by default.
from powens import PowensClient, RetryPolicy
policy = RetryPolicy(max_attempts=5, base_delay=0.5, max_delay=5.0)
async with PowensClient(base_url=..., retry_policy=policy) as c:
...
A NoOpCircuitBreaker ships by default. Inject your own implementation
(conforming to the CircuitBreaker protocol) to integrate with an
observability / control plane.
Development
mise install
uv sync
uv run ruff check .
uv run ruff format --check .
uv run mypy .
uv run pytest
Tests use respx and do not need network access.
Fidelity
This SDK mirrors the public Powens API reference 1:1 — every documented field appears on the corresponding Pydantic model, including deprecated fields (marked in code). Enums list the documented values but tolerate unknown strings, as the reference requires.
Known limitations
- Async-only; no sync wrapper. Use
asyncio.run(...)in scripts or integrate inside an existing event loop. client.indicatorsandclient.account_ownershipsdepend on feature-gated Powens endpoints — your domain must have them enabled.- Webhooks are not covered (they are a server-side concern, not an API-client one).
- The SDK does not persist tokens; token refresh and storage are the caller's responsibility.
Support
This is a community-maintained SDK. For bugs and feature requests, use GitHub Issues. For questions about the Powens API itself, refer to the official documentation.
License
MIT — see LICENSE.
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file py_powens-0.1.0.tar.gz.
File metadata
- Download URL: py_powens-0.1.0.tar.gz
- Upload date:
- Size: 49.5 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
f5cfd2ed68e9bf508a7bc07a91f54a97e9f2b0e7b52f2e93764e33276115739c
|
|
| MD5 |
0744c4b318541ff87e97545e67fcda19
|
|
| BLAKE2b-256 |
7ef1da9a53fec0bc1291dca223eda8a91d8e0eba37649320977c68cee41f7b0f
|
Provenance
The following attestation bundles were made for py_powens-0.1.0.tar.gz:
Publisher:
release.yml on militu/py-powens
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
py_powens-0.1.0.tar.gz -
Subject digest:
f5cfd2ed68e9bf508a7bc07a91f54a97e9f2b0e7b52f2e93764e33276115739c - Sigstore transparency entry: 1359578179
- Sigstore integration time:
-
Permalink:
militu/py-powens@ee6379cff050c4e46e7a26b339d6ebba5b477168 -
Branch / Tag:
refs/tags/v0.1.0 - Owner: https://github.com/militu
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@ee6379cff050c4e46e7a26b339d6ebba5b477168 -
Trigger Event:
push
-
Statement type:
File details
Details for the file py_powens-0.1.0-py3-none-any.whl.
File metadata
- Download URL: py_powens-0.1.0-py3-none-any.whl
- Upload date:
- Size: 56.7 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
a688e0408d52c0b2cf08d4d7f501497a838b1036acc48a99c5a69dfc64bc687d
|
|
| MD5 |
6c09909eea0a0673b0a0139e64532938
|
|
| BLAKE2b-256 |
8d0a4794f565cf8d46ec1e44751bf6051234070bcc5e5ce4234e5453fb73c83a
|
Provenance
The following attestation bundles were made for py_powens-0.1.0-py3-none-any.whl:
Publisher:
release.yml on militu/py-powens
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
py_powens-0.1.0-py3-none-any.whl -
Subject digest:
a688e0408d52c0b2cf08d4d7f501497a838b1036acc48a99c5a69dfc64bc687d - Sigstore transparency entry: 1359578243
- Sigstore integration time:
-
Permalink:
militu/py-powens@ee6379cff050c4e46e7a26b339d6ebba5b477168 -
Branch / Tag:
refs/tags/v0.1.0 - Owner: https://github.com/militu
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@ee6379cff050c4e46e7a26b339d6ebba5b477168 -
Trigger Event:
push
-
Statement type: