Skip to main content

python-wfirma

Python client for the wFirma accounting API. Supports both synchronous and asynchronous usage.

Status: Stable (1.0.0). WFirmaClient supports 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 for WFirmaClient
  • get_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 verification
  • OAuth2Auth: best when you need upstream read/write scope control and user authorization flows
  • OAuth1Auth: 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.md before tagging or publishing

Stability Policy

  • 1.0rc1 started the API freeze, and 1.0.0 ships 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)

Source distribution for python-wfirma 1.0.0
File Size Uploaded
python_wfirma-1.0.0.tar.gz 229.0 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for python-wfirma 1.0.0
File Interpreter ABI Platform
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}
Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page