beangulp importer for Wise balance statements (statement.json), with a thin SCA-capable API client: idempotent drafts via referenceNumber, conversion-leg merging, fee splitting, closing-balance assertions
Project description
beangulp-wise
beangulp importer for Wise (formerly TransferWise) balance statements, plus a thin, SCA-capable API client to fetch them.
Wise has no official Python SDK, and the community clients are either
experimental or AGPL-licensed; the import workflow needs exactly three GET
endpoints, so this package owns a ~100-line client instead
(beangulp_wise.client.WiseClient).
Design
The importer consumes statement.json files (one per currency balance),
not the API directly — fetching writes files to disk first, so every import
is auditable, replayable, and testable offline.
referenceNumber(CARD-…,TRANSFER-…,CONVERSION-…) is stored aswise_id:metadata and is the idempotency key:extract()skips references already anywhere in the existing ledger. Re-imports are always safe.- Payee by detail type: merchant name for card payments, recipient/sender for transfers, description otherwise.
totalFeesbecomes an explicit posting tofees_account— fees stay visible instead of dissolving into the counter leg.payee_rules((regex, account, flag)) draft the counter leg; unmatched entries keep the!review flag and the cash leg only.endOfStatementBalance→ abalanceassertion the day after the interval.- Conversions: each leg appears in a different currency's statement,
sharing one
referenceNumber.merge_conversions(entries)joins them into a single two-currency transaction — the incoming leg priced@@what left the other balance net of fees, so it balances exactly.
Usage
from beangulp_wise import Importer, merge_conversions
importer = Importer(
{"EUR": "Assets:Wise:EUR", "USD": "Assets:Wise:USD"},
fees_account="Expenses:BankFees:Wise",
holder="My GmbH", # a token may see several profiles
payee_rules=((r"cloudflare", "Expenses:IT:Hosting", "!"),),
)
entries = merge_conversions(
importer.extract("statement-eur.json", existing=ledger_entries)
+ importer.extract("statement-usd.json", existing=ledger_entries)
)
Fetching statements (SCA)
Statement endpoints are protected by Strong Customer Authentication: Wise
answers 403 with a one-time token in the x-2fa-approval header, which must
be signed (RSA-SHA256, PKCS#1 v1.5) with a private key whose public half is
registered on the Wise account (Settings → API tokens → Manage public keys).
from beangulp_wise import WiseClient
client = WiseClient(token, private_key_pem=open("private.pem", "rb").read())
pid = client.profile_id("My GmbH")
for balance in client.balances(pid):
statement = client.balance_statement(
pid, balance["id"], balance["currency"],
"2026-07-01T00:00:00.000Z", "2026-07-31T23:59:59.999Z",
)
cryptography is an optional dependency (beangulp-wise[sca]) — importing
statement files works without it.
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 beangulp_wise-0.1.1.tar.gz.
File metadata
- Download URL: beangulp_wise-0.1.1.tar.gz
- Upload date:
- Size: 17.8 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.14
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
508f51045b8f44ae072a777ad1cf15c5a84555e6bfd0ef40a5ace1ed66f349cb
|
|
| MD5 |
326201d19bc4e8e09599086c3c7717ff
|
|
| BLAKE2b-256 |
7a381b5264d6719000f679fba76d27f6cb8d0a91b8dbef559a3297a7a300cce5
|
Provenance
The following attestation bundles were made for beangulp_wise-0.1.1.tar.gz:
Publisher:
publish.yaml on sealambda/quints
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
beangulp_wise-0.1.1.tar.gz -
Subject digest:
508f51045b8f44ae072a777ad1cf15c5a84555e6bfd0ef40a5ace1ed66f349cb - Sigstore transparency entry: 2202478536
- Sigstore integration time:
-
Permalink:
sealambda/quints@dcdde75977a0f8bc4304a4e91ca7dd0f28550001 -
Branch / Tag:
refs/tags/v0.4.1 - Owner: https://github.com/sealambda
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yaml@dcdde75977a0f8bc4304a4e91ca7dd0f28550001 -
Trigger Event:
push
-
Statement type:
File details
Details for the file beangulp_wise-0.1.1-py3-none-any.whl.
File metadata
- Download URL: beangulp_wise-0.1.1-py3-none-any.whl
- Upload date:
- Size: 15.9 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.14
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
62b0ab375532114460b1c51c15bf613a375875c359ed35d8ff6bf191ab642543
|
|
| MD5 |
9d0da90f18cade782d9e691a3f3ef338
|
|
| BLAKE2b-256 |
0999bd2097c5d41e9faf785a5bf160185f29534142dd3498832ec6efea8be177
|
Provenance
The following attestation bundles were made for beangulp_wise-0.1.1-py3-none-any.whl:
Publisher:
publish.yaml on sealambda/quints
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
beangulp_wise-0.1.1-py3-none-any.whl -
Subject digest:
62b0ab375532114460b1c51c15bf613a375875c359ed35d8ff6bf191ab642543 - Sigstore transparency entry: 2202479150
- Sigstore integration time:
-
Permalink:
sealambda/quints@dcdde75977a0f8bc4304a4e91ca7dd0f28550001 -
Branch / Tag:
refs/tags/v0.4.1 - Owner: https://github.com/sealambda
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yaml@dcdde75977a0f8bc4304a4e91ca7dd0f28550001 -
Trigger Event:
push
-
Statement type: