All notable changes to this project will be documented in this file.
The format is based on Keep a Changelog, and this project adheres to Semantic Versioning.
0.1.2 - 2026-06-06
Documentation/site release — no library code or wire behaviour changed.
- The documentation site moved to a custom domain: https://vendus.bilouro.com/
(was
bilouro.github.io/vendus-python). The packageDocumentationURL, the sitemap / canonical / JSON-LD,robots.txt, and all in-repo links now point there; the old GitHub Pages URLs 301-redirect to it. - README: the documentation links are split into separate English and Português lines.
0.1.1 - 2026-06-04
Metadata, packaging, and documentation release — no library code or wire behaviour changed.
- Discoverability/SEO: per-page meta descriptions across the docs, auto-generated
social/OG cards (built in CI), JSON-LD
SoftwareApplicationstructured data on the docs home page, and arobots.txtthat advertises the sitemap. - Maintainer contact email and a
Sourceproject URL in the package metadata; aFUNDING.ymltemplate for the GitHub sponsor button.
- Richer PyPI metadata for discoverability: expanded
description,keywords, and troveclassifiers. - README now opens with a keyword-focused summary and uses absolute links — the previous relative links (LICENSE, examples, CONTRIBUTING, SECURITY) 404'd on the PyPI project page.
0.1.0 - 2026-05-31
create_simplified_invoice(FS) andcreate_receipt(RG), sync + async. An FS is a simplified invoice paid on issue (requirespayments); an RG (Recibo) acknowledges payment of one or more invoices, referenced by document number. Both live-validated; a real RG was cancellable (receipts can be cancelled, unlike FT/FR/NC).modeparameter (DocumentModeenum:NORMAL/TESTS) oncreate_invoice,create_invoice_receipt,create_credit_note(sync + async) — issue non-fiscal test-mode documents that Vendus does not communicate to the ATdefault_modeonVendusClient/from_env— applied to every create that omitsmode, so the intended mode is set once (a per-callmodestill overrides it).modeotherwise inherits the register's mode, which istestson new accountsDocument.tax_authority_id— the AT-generated id, empty until Vendus reports the document to the AT (lets you confirm a test document was not reported)TaxCategoryenum (NORMAL/INTERMEDIATE/REDUCED/EXEMPT/OTHER) for line-item VATPaymentmodel andlist_payment_methods()(sync + async) — a Fatura-Recibo now takespayments=[Payment(method_id=..., amount=...)]; method ids are account-specificPaymentMethodmodel returned bylist_payment_methods()CreditLinemodel +linesargument oncreate_credit_note— credit only specific rows/quantities (partial credit); omit for a full credit, which now skips lines that are already fully credited. Verified live on a real multi-line invoiceerror_codeattribute on every exception (the Vendus error code, e.g.P001)DocumentTypenow covers the fulldocuments/typesreference (FG,GA,GD,GR,DC,PF,OT,EC) plusRG(observed live)- Docs: a dedicated Payment methods page (
list_payment_methods, thePaymentmodel, split payments,date_due), all live-validated list_registers()(sync + async) and theRegistermodel — read the account's registers (caixas) to discover aregister_idand its working mode. Registers are read-only via the API (configured in the Vendus backoffice)DocumentType.UNKNOWN— forward-compat sentinel so the SDK does not crash on type codes the API returns but the enum does not model (e.g.RG); the raw code stays inraw_response- Live integration tests (
tests/integration/, excluded by default): FT and FR in test mode, plus read-onlylist_payment_methods/list/getagainst real documents - Initial project skeleton
VendusClientwith HTTP Basic AuthDocumentsService.create_invoice(sync + async)DocumentsService.create_simplified_invoice(sync + async)DocumentsService.create_invoice_receipt(sync + async)DocumentsService.create_receipt(sync + async)DocumentsService.create_credit_note(sync + async)get/list/cancel(sync + async)ClientDatasupports three shapes: with NIF, name-only, or omitted (final consumer)- Pydantic v2 models for documents, items, taxes, inline client data
- Portuguese NIF validation
- PII redaction filter for logging
- HttpTransport with conditional POST retries (R3)
- 100 unit tests with
respxmocks (94% coverage), plus live integration tests - Bilingual documentation (PT/EN) with mkdocs-material + i18n
- 10 runnable examples, including an all-scenarios reference
- CI workflow (ruff, mypy --strict, pytest on Python 3.9–3.13)
- Docs auto-deploy to GitHub Pages
- Release workflow (
release.yml) — publishes to PyPI via Trusted Publishing (OIDC) on a GitHub Release; no tokens or secrets - Issue/PR templates and Dependabot config
- A Vendus
P001(field-validation error, returned with HTTP 403) now raisesValidationErrorinstead of the misleadingAuthorizationError. DocumentType.QUOTEis now"OT"(was the incorrect"OR") andDocumentType.RECEIPTis"RG"(observed live; was the unverified"RC"), aligning with the Vendus reference.- Breaking:
DocumentItem.tax_rate(aDecimalpercentage) is nowtax_category(aTaxCategoryenum). Vendus classifies line-item VAT by category (tax_id: NOR/INT/RED/ISE/OUT), not by a numeric rate — the rate is defined by the category in the merchant's Vendus configuration. - Breaking:
cancel(document_id)no longer takes areason— the Vendus document PATCH endpoint has no field for a cancellation reason. It now also fetches the document and refuses to cancel FT/FR/NC (fiscal documents cannot be cancelled; reverse them with a credit note), raisingValidationErrorwith that guidance. - Breaking:
create_credit_note(reference_document_id, reason, ...)no longer takesregister_id/items/client. It fetches the original and credits its full set of lines (the original must be a real, retrievable document). The previous signature never worked: Vendus rejected the old top-levelreference_document_idfield. - Breaking:
create_invoice_receipt(...)now requirespayments— an FR records payment on issue and Vendus rejects it otherwise. - Docs: replaced the "Sandbox" section with a sourced "Testing" section. Vendus has no separate sandbox host; testing is done via document-level test mode. Corrects a prior unsourced claim that every call creates real fiscal documents.
- Line items now send the field names the real Vendus API actually accepts — found by
live validation, which returned
P001for the old names:tax_id(wastax_rate),discount_percentage(wasdiscount),id(wasproduct_id).create_invoicehad never succeeded against the live API before this. cancelno longer sendsnotes(rejected by the document PATCH endpoint, which accepts onlystatus/mode).- Credit notes now build the wire body Vendus accepts — found live: each credit line
references the original via
reference_document(number + row) and the original line id, instead of the rejected top-levelreference_document_id. _parse_documenttolerates unknown document type codes instead of raising (the live account returnedRG, which is absent from the documents/types reference).create_credit_noteraises a clearerNotFoundErrorwhen the original can't be read (e.g. a test-mode document), explaining it must be a real, retrievable document.- Error-message extraction for the
{"errors": [{"code", "message"}]}body shape — the message (not the raw dict) is now used for the exception text.
mypy --strictpasses with zero errorsruff check/ruff formatclean