Skip to main content

wfirma-sdk-python

Unofficial, minimal Python SDK for the wFirma.pl API (API Key & OAuth2).
Status: prototype for integrations. Before production, verify scopes, payloads and responses with official docs.

This SDK focuses on a pragmatic subset: contractors, invoices (get/add/download/send), and company accounts. It exposes a low-level call() escape hatch for everything else.


Install

pip install wfirma-sdk-python  # when published
poetry add wfirma-sdk-python

Python >= 3.9 recommended.


Quickstart

from wfirma_sdk import WFirmaAPIClient

client = WFirmaAPIClient(
    base_url="https://api2.wfirma.pl",
    company_id="YOUR_COMPANY_ID",   # optional but recommended

    # ---- Auth option A: API Key headers ----
    access_key="...",
    secret_key="...",
    app_key="...",

    # ---- OR Auth option B: OAuth2 ----
    # oauth2_token="eyJhbGciOi..."  # Bearer token
)

# Add contractor
resp = client.contractors.add({
    "name": "Nazwa kontrahenta",
    "zip": "12-345",
    "country": "PL",
    "tax_id_type": "custom",
    "nip": "1111111111",
})
print(resp)

# Get invoice
inv = client.invoices.get(12345678)
print(inv)

# Download invoice PDF link (valid for a short time on backend)
link = client.invoices.download(
    12345678,
    page="all",
    address=0,
    leaflet=0,
    duplicate=0,
    payment_cashbox_documents=0,
    warehouse_documents=0,
)
print(link["status"]["code"], link.get("response"))

# Send invoice by email
client.invoices.send(
    12345678,
    email="odbiorca@adres.pl",
    subject="Otrzymałeś fakturę",
    page="invoice",
    leaflet=0,
    duplicate=0,
    body="Przesyłam fakturę",
)

Running Examples

To run the demo example:

# Clone the repository
git clone https://github.com/musictechlab/mtl-wfirma-python-sdk.git
cd mtl-wfirma-python-sdk

# Install dependencies with poetry
poetry install

# Set up your environment variables
cp .env.example .env  # if available, or create .env manually
# Edit .env with your credentials:
# WFIRMA_OAUTH_TOKEN=your_oauth_token
# WFIRMA_COMPANY_ID=your_company_id

# Run the demo
poetry run python examples/demo.py

The demo will fetch the 20 most recent invoices from your wFirma account.


Authentication

API Key (headers)

Place keys in headers (client does it for you):

  • accessKey
  • secretKey
  • appKey
client = WFirmaAPIClient(
    company_id="...",
    access_key="...",
    secret_key="...",
    app_key="...",
)

OAuth2 (Bearer)

Use Authorization Code flow in your app to obtain an access_token. Pass it to the client:

client = WFirmaAPIClient(
    company_id="...",
    oauth2_token="ACCESS_TOKEN_VALUE",  # adds Authorization: Bearer ... and ?oauth_version=2
)

Tip: Regardless of auth method, remember company_id if your account has multiple companies.


Modules covered

  • contractors — add, get, edit, find
  • invoices — get, add, download, send, find (custom XML)
  • company_accounts — find, get
  • call(path, ...) — low-level escape hatch

Usage

Contractors

# add
client.contractors.add({
    "name": "ACME Sp. z o.o.",
    "zip": "00-000",
    "city": "Warszawa",
    "country": "PL",
    "tax_id_type": "nip",
    "nip": "1234567890",
})

# get
client.contractors.get(12345)

# edit
client.contractors.edit(12345, {"name": "ACME SA", "zip": "00-001"})

# find (basic paging/fields)
client.contractors.find(page=1, limit=50, fields=["Contractor.id", "Contractor.name"])

Advanced find — pass your own <parameters> as XML:

parameters_xml = b"""<?xml version="1.0" encoding="UTF-8"?>
<api>
  <contractors>
    <parameters>
      <page>1</page>
      <limit>50</limit>
      <fields>
        <field>Contractor.id</field>
        <field>Contractor.name</field>
      </fields>
      <conditions>
        <condition>
          <field>name</field>
          <operator>like</operator>
          <value>ACME</value>
        </condition>
      </conditions>
      <order>
        <asc>name</asc>
      </order>
    </parameters>
  </contractors>
</api>"""
client.contractors.find(conditions_xml=parameters_xml)

Invoices

# get
client.invoices.get(12345678)

add — for complex nested structures use raw XML from wFirma docs:

xml_body = b"""<api>
  <invoices>
    <invoice>
      <contractor>
        <name>Testowy kontrahent</name>
        <zip>10-100</zip>
        <city>Wrocław</city>
        <street>Prosta</street>
      </contractor>
      <type>correction</type>
      <parent_id>16679047</parent_id>
      <invoicecontents>
        <invoicecontent>
          <parent_id>19630727</parent_id>
          <name>produkt1</name>
          <count>1.0000</count>
          <price>11.00</price>
        </invoicecontent>
        <invoicecontent>
          <parent_id>19630791</parent_id>
          <name>produkt2</name>
          <count>1.0000</count>
          <price>11.00</price>
        </invoicecontent>
        <invoicecontent>
          <name>nowy - produkt3</name>
          <count>1.0000</count>
          <price>11.00</price>
        </invoicecontent>
      </invoicecontents>
    </invoice>
  </invoices>
</api>"""
client.invoices.add(invoice_xml_body=xml_body)

download — build <parameters> via helper:

client.invoices.download(
    12345678,
    page="all", address=0, leaflet=0, duplicate=0,
    payment_cashbox_documents=0, warehouse_documents=0,
)

send

client.invoices.send(
    12345678,
    email="odbiorca@adresmailowy123.pl",
    subject="Otrzymałeś fakturę",
    page="invoice",
    leaflet=0,
    duplicate=0,
    body="Przesyłam fakturę",
)

find — pass your own <parameters> XML for full control:

invoices_find_xml = b"""<?xml version="1.0" encoding="UTF-8"?>
<api>
  <invoices>
    <parameters>
      <page>1</page>
      <limit>20</limit>
      <fields>
        <field>Invoice.id</field>
        <field>Invoice.fullnumber</field>
        <field>Invoice.date</field>
        <field>InvoiceContent.name</field>
        <field>InvoiceContent.price</field>
      </fields>
      <conditions>
        <condition>
          <field>Invoice.remaining</field>
          <operator>gt</operator>
          <value>0</value>
        </condition>
      </conditions>
      <order>
        <desc>date</desc>
      </order>
    </parameters>
  </invoices>
</api>"""
client.invoices.find(parameters_xml=invoices_find_xml)

Company accounts

client.company_accounts.find()
client.company_accounts.get(999)

Errors

  • Network/HTTP/XML parsing errors ⇒ raises WFirmaAPIError.
  • API-level status checking: if <status><code>...</code></status> is not OK (or NO_CONTENT), WFirmaAPIError is raised with the decoded response for inspection.
from wfirma_sdk import WFirmaAPIError

try:
    client.invoices.get("bad-id")
except WFirmaAPIError as e:
    print(e, e.http_status, e.response)

Tips & gotchas

  • Format: SDK defaults to inputFormat=xml&outputFormat=xml and parses XML to Python dicts.
  • Multiple companies: set company_id in the client to avoid accidental requests to the wrong company.
  • Temporary links: /invoices/download returns a link that is valid only briefly (per backend rules).
  • Rate limits: avoid bursts; consider backoff/retries on TOTAL REQUESTS LIMIT EXCEEDED or TOTAL EXECUTION TIME LIMIT EXCEEDED.
  • Escape hatch: client.call(path, method=..., params=..., body_xml=...) to hit any endpoint not yet wrapped.

Versioning

This SDK is intentionally small. Breaking changes may occur until 1.0. Pin versions in production.


Contributing

Issues / PRs welcome. Keep the scope minimal and docs-linked.


🪪 License

MIT License — © 2025 MusicTech Lab
Built with ❤️ by MusicTech Lab.

Metadata

Release files for mtl-wfirma-python-sdk 0.0.6

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for mtl-wfirma-python-sdk 0.0.6
File Size Uploaded Provenance Actions
mtl_wfirma_python_sdk-0.0.6.tar.gz 8.1 kB Without provenance Details for mtl_wfirma_python_sdk-0.0.6.tar.gz

Built distribution (wheel)

Table of built distributions (wheels) for mtl-wfirma-python-sdk 0.0.6
File Interpreter ABI Platform Actions
mtl_wfirma_python_sdk-0.0.6-py3-none-any.whl Python 3 none any Details for mtl_wfirma_python_sdk-0.0.6-py3-none-any.whl

Total release size: 18.7 kB

Release files / mtl_wfirma_python_sdk-0.0.6.tar.gz

Download URL mtl_wfirma_python_sdk-0.0.6.tar.gz
Size 8.1 kB
Tags Source
SHA-256 checksum
How to use checksums
574d2b5f0b6b800723b5d353c043789c70e84e1dea6eeee1293af67000cf4319
BLAKE2b-256 checksum
How to use checksums
d4a569bb9fdf8b88365ecb66ed4666829f4d372ec56b237ab4f866b4debfcc6a
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/6.2.0 CPython/3.12.11

Release files / mtl_wfirma_python_sdk-0.0.6-py3-none-any.whl

Download URL mtl_wfirma_python_sdk-0.0.6-py3-none-any.whl
Size 10.6 kB
Tags Python 3
SHA-256 checksum
How to use checksums
64101ffab2f224fe46a112371210bc9efb4afbde640ec3543ff6aeecb4fc089a
BLAKE2b-256 checksum
How to use checksums
a24d6835cc0ac4cda463b701fa63ac5f07b9a4cf10813be2c026262a4460b4c5
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/6.2.0 CPython/3.12.11

Security for mtl-wfirma-python-sdk 0.0.6

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

No provenance found

None of the files in this release were uploaded with provenance metadata.

A note on package security

PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.

To learn more about protecting yourself from malicious actors, visit our package security documentation.

Release history Release notifications | RSS feed

This release

0.0.6 This release

2 release files No provenance

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