python-wfirma
Python client for the wFirma accounting API. Supports both synchronous and asynchronous usage.
Status: Stable (
1.0.0).WFirmaClientsupports API Key, OAuth 2.0, and OAuth 1.0a in this release.
Installation
pip install python-wfirma
Or with uv:
uv add python-wfirma
Usage
Safe Read-Only Start
from wfirma.sync.auth import APIKeyAuth
from wfirma.sync.client import WFirmaClient
auth = APIKeyAuth(
access_key="your_access_key",
secret_key="your_secret_key",
app_key="your_app_key",
)
with WFirmaClient(auth=auth, company_id=123) as client:
company = client.company.get()
terms = client.terms.find()
print(company.name)
print(len(terms))
CLI Read-Only Verification
wfirma company show
wfirma tags list
wfirma terms list
wfirma warehouses list
Write Operations
These examples mutate real production data. Do not run them casually.
from wfirma.sync.auth import APIKeyAuth
from wfirma.sync.client import WFirmaClient
auth = APIKeyAuth(
access_key="your_access_key",
secret_key="your_secret_key",
app_key="your_app_key",
)
with WFirmaClient(auth=auth, company_id=123) as client:
contractor = client.contractors.add(name="ACME Sp. z o.o.", nip="1234567890")
invoice = client.invoices.add(
invoice={
"contractor_id": contractor.id,
"type": "normal",
"paid": "0",
}
)
Async
import asyncio
from wfirma.async_.auth import APIKeyAuth
from wfirma.async_.client import WFirmaClient
async def main() -> None:
auth = APIKeyAuth(
access_key="your_access_key",
secret_key="your_secret_key",
app_key="your_app_key",
)
async with WFirmaClient(auth=auth, company_id=123) as client:
contractor = await client.contractors.add(
name="ACME Sp. z o.o.", nip="1234567890"
)
invoices = await client.invoices.find()
asyncio.run(main())
OAuth 2.0
from wfirma.sync.auth import OAuth2Auth
from wfirma.sync.client import WFirmaClient
from wfirma.config import Environment
oauth = OAuth2Auth(
client_id="your_client_id",
client_secret="your_client_secret",
redirect_uri="https://yourapp.example.com/callback",
environment=Environment.PRODUCTION,
)
# Step 1: redirect user to authorization URL
url = oauth.build_authorization_url(scope="invoices-read")
# Step 2: exchange the code from callback
token = oauth.exchange_code(code="authorization_code_from_callback")
# Step 3: use the client
with WFirmaClient(auth=oauth, company_id=123) as client:
invoices = client.invoices.find()
Configuration
The library has two different environment-driven helpers:
APIKeyAuth.from_env()reads API key credentials forWFirmaClientget_config()/WFirmaConfig.from_env()read shared application settings
API key authentication from environment:
# .env
WFIRMA_APP_KEY=your_app_key
WFIRMA_ACCESS_KEY=your_access_key
WFIRMA_SECRET_KEY=your_secret_key
WFIRMA_ENVIRONMENT=production
WFIRMA_COMPANY_ID=123
from wfirma.sync.auth import APIKeyAuth
auth = APIKeyAuth.from_env()
Shared configuration helper:
# .env
WFIRMA_APP_KEY=your_app_key
WFIRMA_APP_SECRET=your_app_secret
WFIRMA_ENVIRONMENT=production
WFIRMA_COMPANY_ID=123
from wfirma import get_config
config = get_config()
print(config.base_url) # https://api2.wfirma.pl
Custom API base URL override (useful for local simulators):
# .env
WFIRMA_BASE_URL=http://localhost:18088
from wfirma.sync.auth import APIKeyAuth
from wfirma.sync.client import WFirmaClient
auth = APIKeyAuth(
access_key="your_access_key",
secret_key="your_secret_key",
app_key="your_app_key",
)
with WFirmaClient(
auth=auth,
company_id=123,
base_url="http://localhost:18088",
) as client:
company = client.company.get()
Choosing Auth Mode
APIKeyAuth: best for service integrations and manual CLI verificationOAuth2Auth: best when you need upstream read/write scope control and user authorization flowsOAuth1Auth: supported for upstream compatibility, but use it only when the target workflow requires it
Handling API Errors
from wfirma.exceptions import APIError
try:
with WFirmaClient(auth=auth, company_id=123) as client:
company = client.company.get()
except APIError as exc:
print(exc.to_dict())
Production Use Checklist
- use least-privilege credentials
- prefer read-only verification first (
company,tags,terms,warehouses) - treat write examples as production mutations
- run the CLI after install, not only from the repository checkout
- follow
RELEASING.mdbefore tagging or publishing
Stability Policy
1.0rc1started the API freeze, and1.0.0ships within that contract- the freeze covers import paths, auth constructors, exception semantics, client defaults, and CLI command names and flags
Supported Resources
The client exposes the following wFirma API resources. Each resource provides methods matching the upstream API (typically add, find, get, edit, delete):
Core: invoices, contractors, goods, payments, expenses, documents
Company: company, company_accounts, company_packs
Declarations: declaration_countries, declaration_body_jpkvat, declaration_body_pit
Warehouse: warehouses, warehouse documents (PW, PZ, R, RW, WZ, ZD, ZPD, ZPM)
Reference data: tags, series, terms, term_groups, vat_codes, translation_languages, taxregisters, interests, ledger_accountant_years, ledger_operation_schemas
Users & misc: users, user_companies, vehicles, vehicle_run_rates, payment_cashboxes, invoice_deliveries, invoice_descriptions, notes, webhooks
Development
Requires Python 3.12+. The project uses uv for dependency management.
git clone https://github.com/dekoza/python-wfirma.git
cd python-wfirma
uv venv && uv sync --extra dev
uv run pre-commit install
Tests
uv run pytest # all tests
uv run pytest --cov=wfirma --cov-report=html # with coverage
uv run pytest -m integration # opt-in live integration tests
CLI
The package now ships a small read-only CLI for manual API verification.
Required environment variables:
export WFIRMA_APP_KEY='...'
export WFIRMA_ACCESS_KEY='...'
export WFIRMA_SECRET_KEY='...'
export WFIRMA_COMPANY_ID='123'
Examples:
wfirma company show
wfirma company show --json
wfirma tags list
wfirma terms list
wfirma term-groups list --json
wfirma warehouses list
wfirma vat-codes list
Default list output uses ID and Label. company show uses ID and Name.
Linting & type-checking
uv run ruff format src tests
uv run ruff check --fix src tests
uv run mypy src
Contributing
See CONTRIBUTING.md.
License
MIT — see LICENSE.
This library is not affiliated with wFirma. It is an independent project. Built on httpx, Pydantic, and authlib.
Metadata
Release files for python-wfirma 1.0.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| python_wfirma-1.0.0.tar.gz | 229.0 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| python_wfirma-1.0.0-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 402.0 kB
Release files / python_wfirma-1.0.0.tar.gz
| Download URL | python_wfirma-1.0.0.tar.gz |
|---|---|
| Size | 229.0 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
336efac0ac4984a07b0263503a2ea74df2cdd0b67bc5aeab0c247d06162e887d
|
|
BLAKE2b-256 checksum How to use checksums |
04de5714da83328a03797984a8b2c9e9e1b85363e631955228961d469bdb4c47
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
uv/0.11.26 {"installer":{"name":"uv","version":"0.11.26","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Arch Linux","version":null,"id":null,"libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}
|
Release files / python_wfirma-1.0.0-py3-none-any.whl
| Download URL | python_wfirma-1.0.0-py3-none-any.whl |
|---|---|
| Size | 173.1 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
e41e616807f9f589bb2d41bf3b44401d3bfcbcb4748d92948dfb8ff531cd48fe
|
|
BLAKE2b-256 checksum How to use checksums |
b7562af759f54b40ac52ae5d092a0c4a16569afec4d69b536bf25dbe4919b68a
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
uv/0.11.26 {"installer":{"name":"uv","version":"0.11.26","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Arch Linux","version":null,"id":null,"libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}
|