Repository navigation
v1.0.0
Fixed
-
Fix English and Polish documentation examples for limits, authentication,
token activation, imports, async entry points, certificate file paths, and
sample identifiers. Document client and session concurrency boundaries. -
Add safe filename/path hints for PEM, PKCS#12, and XML content inputs. Existing
PEM string paths retain their 1.x deprecation behavior. -
Report synchronous
close()misuse on async clients and sessions with
KSeFArgumentErrorand guidance to useawait ...aclose()orasync with. -
Enable full jitter for retry backoff through
RetryConfig.jitter, including
HTTP retries during polling.jitter=Falsekeeps deterministic backoff;
Retry-Aftervalues and their existing ceiling remain unchanged. -
Wrap invalid non-builder public model and request-conversion inputs in the
SDK validation-error hierarchy, preserving the Pydantic cause and naming the
public parameter. Validate KSeF invoice-number filters at construction,
including both current and legacy formats. -
Reject invalid PESEL checksums and PESEL/NIP formats in permission grants, mismatched
identifier types, empty permission lists, empty revoke IDs, and empty KSeF
token credentials before HTTP requests. Person and entity grants accept
snake_case strings or permission enums; PascalCase permissions suggest the
corresponding snake_case value. -
Completed exports with zero invoices return immediately from deprecated polling
helpers. Bothexport().wait()andexport().download(path)return empty
metadata and invoice lists for these packages without opening an archive. -
In-memory export downloads verify encrypted and plaintext sizes and SHA-256
hashes using the same checks as downloads to disk. -
Require an explicit FA(3) partial-payment status before building payment entries,
correct both builder guides, and report invalid builder fields as
KSeFValidationErrorwith the original validation error as the cause. Builder
amount, quantity, price, and exchange-rate hints now accept floats and numeric
strings, matching runtime decimal conversion. -
Restore deprecated
ksef2.clients.*submodule imports throughout 1.x.
ksef2 1.0.0 is being prepared as the first stable release. It targets KSeF
OpenAPI 2.8.1 and starts the 1.x compatibility contract. Collective-identifier
invoice queries change because KSeF replaced the endpoint. Old SDK import paths
and method names remain functional throughout 1.x (#171). Read
Breaking changes and Deprecated before upgrading.
Highlights
-
ExportJob.download(Path)decrypts export parts to disk with per-part size and
hash verification, andExportedInvoices.from_path()reads ZIP and TarGz
archives without loading the whole archive into memory (#305). Both accept
anyos.PathLikeand rejectstr/byteswithKSeFArgumentError. -
Offline validation rejects invoice metadata ranges longer than 100 days, documents
metadata page-size bounds, checks invoice sizes before sending or batch
encryption, computes batch part counts before encryption, validates signing
certificates and transport configuration, and defaults FA(3) XML serialization
to compact output (#299). PDF exports reject malformed roots and KSeF numbers,
and the token example stops before a placeholder can be sent. -
Public input handling follows one rule:
bytesandstrare content, while
Pathis a file. Batch preparation catches strings that name existing files,
FA(3) parsing accepts XML text with declarations, and PEM helpers warn when
legacy string paths are used (#297, #304). -
The documented import paths (
ksef2,ksef2.clients,ksef2.models,
ksef2.fa3,ksef2.xades,ksef2.logging,ksef2.profiles,
ksef2.renderers,ksef2.raw,
ksef2.raw.mappers, and the newksef2.testdata) are the compatibility
contract for the whole 1.x line. The rule is simple: a module path with no
underscore is public, and anything with an underscore is private and may change
in any release. See the
public API contract
and the 1.0.0 release notes. -
model_dump()andmodel_dump_json()redact secrets by default and are not a
persistence format. Useto_dict()/to_json()/from_dict()on resume
states andto_sensitive_dict()to persist. -
The invoice and admin workflows have their final 1.x shape: operations that
start asynchronous KSeF work return a handle with.wait(), every collection
returns onePager, and access tokens refresh automatically (#162, #163, #165).
See the 1.0.0 release notes
for a before/after. -
KSeF errors come from one pipeline with one message format, carry
ksef_code,
trace_idanddetails, and say what to do next inhint(#167). -
Public Pydantic model validation and invoice-builder validation raise SDK
exceptions; HTTP 403 raisesKSeFPermissionDeniedError, separate from
KSeFAuthError; terminal operation failures shareKSeFOperationFailedError
(#296). -
Deprecations are visible to type checkers and IDEs (PEP 702
@deprecated) and
remain functional through the 1.x line. Removal is a 2.0 decision (#171). -
Polling helpers continue through retryable server, rate-limit and transport
errors until their timeout. Invoice sends and refresh-token requests retry
only after an explicit429; ambiguous transport failures are not retried.
Connect failures are reported as non-ambiguous and lost invoice responses
include a recovery hint (#300).
Fixed
- FA(3) builder (#293, #304). Emit summary amounts for VAT buckets with
rows even when rounding or correction arithmetic produces zero, validate
foreign-currency VAT exchange rates, and document rounding, corrections, and
large-invoice performance. #304 parser string handling remains in #297; the
missing corrected-invoice error remains in #296.
Breaking changes
-
Explicit client environments and URL alignment (#294, #295).
Client,
AsyncClient, andInvoicePDFExporternow require an environment. Pass an
Environmentor a case-insensitive name such as"test". A supplied
http_clientwith nobase_urlinherits the selected environment URL; a
conflicting URL raisesKSeFArgumentErrorduring construction. This prevents
environment guards and network routing from disagreeing. -
Collective-identifier invoice queries (#128). KSeF API 2.8.1 replaced
GET /collective-identifiers/{collectiveIdentifierNumber}/invoiceswith
POST /collective-identifiers/invoices, which takes up to 10 identifiers in
the body. The old call is removed, not deprecated. Migration is mechanical:# before (0.22.x) page = auth.collective_identifiers.list_invoices(collective_identifier_number=cid) everything = auth.collective_identifiers.list_all_invoices( collective_identifier_number=cid ) # after (1.0.0) for invoice in auth.collective_identifiers.list_invoices( collective_identifier_numbers=[cid] ): ...
list_invoicesnow returns aPager(iterate items,.pages(),.first_page())
and no longer takescontinuation_token;list_all_invoicesremains as a
deprecated alias that still returns pages (#163). The high-level client
validates 1 to 10 identifiers before sending. The raw
endpoint takes a request body instead of a path parameter:from ksef2.raw import spec # before (0.22.x) auth.raw.collective_identifiers.list_invoices(cid) # after (1.0.0) auth.raw.collective_identifiers.list_invoices( spec.CollectiveIdentifierInvoicesQueryRequest(collectiveIdentifierNumbers=[cid]) )
Deprecated
-
Keep the former
ksef2.core,domain,infraandservicesimports,
including submodules, as deprecated aliases throughout 1.x (#171). The first
import loads the canonical package tree and warns once per package family. -
Keep deprecated call names, including invoice send/wait/UPO, metadata search,
download and export aliases, through 1.x. Removal is a 2.0 decision and may
happen no earlier than 2.0.0, replacing the former 1.10.0 removal schedule. -
Add English and Polish migration examples for legacy imports and workflows.
-
Former implementation imports (#153, #171). Implementations moved to
private_-prefixed paths. The old paths remain as deprecated aliases
throughout 1.x, warning with the public replacement. #171 supplies those aliases
and the migration examples. Use documented public modules rather than the private paths
in the table below for new code.Old import Private implementation ksef2.coreksef2._coreksef2.domainksef2._domainksef2.infraksef2._infraksef2.endpointsksef2._endpointsksef2.servicesksef2._servicesksef2.clients.<module>(base,auth,online,async_*, ...)ksef2._clients.<module>(ksef2.clientsstays the public facade with the same__all__)ksef2.configksef2._config(names stay exported fromksef2)ksef2._loggingksef2.logging(configure_logging)ksef2.raw.facade,ksef2.raw.async_facadeksef2.raw._facade,ksef2.raw._async_facade(names stay exported fromksef2.raw)If you imported something from an old path, import it from the public module
instead (see Added for names newly exported fromksef2.models).
Old SDK imports and method names remain functional through 1.x. Replaced
methods keep their old behavior and return type and carry deprecation warnings.
Removal is a 2.0 decision (#171), including APIs deprecated in 0.19.0. See the
deprecated APIs table
on the public API page for every alias and its replacement.
- The invoice, batch and export workflows (#162):
send_invoice_and_wait,
wait_for_invoice_ready, theauth.batch.*prepare_batch/submit_batch/
wait_for_completionfamily,query_metadata/all_metadata/
wait_for_invoices,download_invoice,schedule_export/
wait_for_export_package/fetch_packageand related names.
auth.resume_online_session()andauth.resume_batch_session()give way to
online_session(state=...)andbatch_session(state=...). - The token, certificate, PEPPOL, session, collective-identifier and permission
query/all/list_page/query_*methods give way tolist()/
list_*()(#163). InvoicesClientandAsyncInvoicesClientimported fromksef2.clients; use
auth.invoices(#163).- The 0.19.0 deprecations (
Client.authenticated(),get_state(),
*SessionStatealiases,dump_state()/model_dump_sensitive()/
from_state(),BatchSessionClient.access_token,from_encoded(access_token=...),
the storedaccess_tokenkey) and the legacyauth_timeoutprofile key
(#150, #162).
Added
-
SDK events use the standard
ksef2logger and remain silent unless the
application configures logging.ksef2.logging.configure_logging()opts in
to the SDK console or JSON renderer. SDK events use standard logging levels
and do not include tokens, cryptographic keys or presigned URLs (#301). -
ksef2.renderersis the public path for XSLT and PDF rendering. PDF use
requiresksef2[pdf];InvoicePDFExporterraises an actionableImportError
on first use when that extra is absent.InvoiceBuilderis the canonical
ksef2.fa3name;FA3InvoiceBuilderremains a deprecated alias with removal
no earlier than 2.0.0 (#302). -
PreparedBatch.to_sensitive_dict()andto_sensitive_json()export a prepared
batch in full, including encrypted parts as URL-safe Base64 with=padding
and the AES material. Save the output in protected storage and restore it with
PreparedBatch.from_sensitive_json()for upload recovery after a restart.
The JSON-only envelope is{"version": "1", "payload": {...}}; dictionary export
uses the same shape and has a matchingfrom_sensitive_dict()reader. Readers
reject unsupported or missing versions, unversioned development exports and
unknown fields with sanitizedValueErrormessages. Readers in 1.x
retain support for released persistence versions. Incompatible formats require
a new version and a documented migration. Every
persisted state (format_version) and this envelope now write the version as a
dotted string such as"1". Readers accept any version with major1, such as
"1.2"or"1.0.1", and still read the integer1that earlier releases wrote;
true,1.0and malformed strings are rejected. Pagination cursors keep
their integerv. A minor or patch version never adds or changes fields, so an
earlier 1.x reader can read it; additions that older readers cannot ignore
take a new major version.
Generic model dumps and repr still hide payload bytes and keys (#270). -
Save and resume every handle KSeF finishes asynchronously.
resume_state()on a
GeneratedToken,CertificateEnrollment,PermissionOperationor
InvoiceSubmissionreturns a versioned state model withto_dict(),
to_json(),from_dict()andfrom_json(), and
auth.tokens.generation(state),auth.certificates.enrollment(state),
auth.permissions.operation(state)orsession.submission(state=...)builds the
handle again after a restart, so a background worker can keep
waiting without holding the client that started the operation. A resumed handle
polls the saved reference number and does not invent data: the one-time token
never appears inGeneratedTokenResumeState, in any of its exports or inrepr(),
so a resumed token has notoken, and a resumed enrollment has notimestamp.
InvoiceSubmissionResumeStatealso keeps the session reference, and
submission(state=...)rejects a state from another session, or a call that
passes both a reference and a state, withKSeFArgumentError(#266). -
Restore a finished invoice export from plain archive bytes with
ExportedInvoices.from_archive(archive, compression="zip"). Use"tar_gz"
for TarGz archives. PersistExportedInvoices.archivedirectly; metadata is
read lazily from_metadata.json, and no package status or download URLs are
persisted. Invoice iteration and safe extraction work for both formats, and
asyncwait()returns the same result type (#276). -
Authenticate with
with_xades(nip=..., credentials=XAdESCredentials...).
XAdESCredentials.from_pem,.from_derand.from_pkcs12load certificate,
private-key or archive bytes with an optional password. The holder stores loaded
cryptography objects, retains no password or input bytes, and hides both objects
inrepr(). It has no Pydantic schema or JSON serialization API. Construction
rejects unsupported keys and mismatched certificate/key pairs once, before any
request. Authentication and signing reuse the loaded objects without private-key
serialization or reparsing. The existingcert=/private_key=form is unchanged.
Passing both forms or neither raisesKSeFArgumentError(#267, #277). -
Read complete invoice search responses with
responses()andfirst_response(),
including the permanent-storage checkpoint on empty pages. Correct the English
and Polish incremental-sync examples (#258). -
Download a UPO after a restart from a stored session reference with
auth.invoice_sessions.download_upo(), selecting it by invoice reference,
KSeF number or session UPO reference. No open session is needed, and a UPO
KSeF has not issued raisesKSeFNotReadyError(#172). -
Resume a failed batch upload with
auth.batch_session(state=..., prepared_batch=...).KSeFBatchUploadErrorkeeps
the exact prepared payload and returns it fromrecovery_prepared_batch(), so a
batch prepared insidesubmit(invoices)recovers too. A payload that no longer
matches the session is rejected before anything is uploaded, and part bytes plus
encryption material stay out of repr and model dumps (#256). -
Handles with
.wait()for operations KSeF finishes asynchronously, each exposing
the fields of the response it replaces:InvoiceSubmissionfrom
session.send_invoice(xml)(alsoget_status(),download_upo()),ExportJob,
GeneratedTokenfromtokens.generate(),PermissionOperationfrom
permissions.grant_*()/revoke(),CertificateEnrollmentfrom
certificates.enroll(), and the genericOperationHandle(#162, #163). -
auth.invoices.search(filters), returning aPager;auth.invoices.download(ksef_number);
andauth.invoices.export(filters), whoseExportJob.wait()returns
ExportedInvoices(.invoices(),.metadata,.archive,.save()) (#162). -
auth.batch.prepare()andauth.batch.submit(), which opens, uploads and closes
the batch and returns the closedBatchSessionClient(#162). -
One
Pagerfor every collection (tokens, certificates, PEPPOL, sessions,
collective identifiers and allpermissions.list_*()): iterate items,.pages(),
.first_page()(#162, #163). -
Resume through the method that starts the work, with
state=(the resume-state
object or its JSON):auth.online_session(state=...),
auth.batch_session(state=...),auth.invoices.export(state=...). Exports are
resumable throughExportJob.resume_state()and the newExportResumeState, and
session.submission(reference_number)returns the handle for an invoice sent
earlier (#162). -
Automatic access-token refresh: shortly before expiry and once after a 401, shared
by concurrent requests. Disable withTransportConfig(auto_refresh_tokens=False)
(#165). -
New exceptions:
KSeFArgumentError,KSeFAuthenticationExpiredError,
KSeFExportFailedError,KSeFOnlineSessionTimeoutError,
KSeFPermissionOperationFailedError,KSeFPermissionOperationTimeoutError,
KSeFCertificateEnrollmentFailedErrorand
KSeFCertificateEnrollmentTimeoutError(#162, #163, #165). -
Narrower exception classes, so callers can catch what they mean instead of
checkingksef_code:KSeFNotFoundError(KSeF codes 21164, 21173, 21175, 25005,
25008 and 71001),KSeFServerError(21184),KSeFResponseValidationError,
KSeFProfileConfigError,KSeFSessionFailedErrorand
KSeFTokenActivationFailedError. Codes 21301, 21304 and 21308 raise
KSeFAuthErroreven on HTTP 400. Every polling timeout derives from
KSeFPollingTimeoutError, which exposestimeout. All of them subclass the
classes callers already catch (#273). -
tokens.get_status(),sessions.terminate(reference_number)and
permissions.revoke()(#163). -
KSeFApiError.ksef_code(the raw KSeF code, also for codes the SDK does not
list),trace_idanddetails;KSeFException.hint, which says what to do next;
andKSeFNotReadyErrorfor KSeF codes 21165 and 21178 (#167). -
Explicit processing waits through
wait(timeout=..., poll_interval=...);
download_upo()never polls (#169). -
Problem Details responses by default, including trace IDs for HTTP 400 and
429. SetTransportConfig(error_format="legacy")for the older response
format; HTTP 401, 403 and 410 always use Problem Details (#169, #175). -
RetryConfig.max_retry_after, defaulting to 120 seconds. Retry-After values
within this ceiling are honored even abovemax_delay; larger values fail
immediately withKSeFRateLimitErrorso the caller can reschedule (#178). -
Retry-Afteris read in its HTTP-date form as well as in seconds, in errors and
in the retry middleware (#167). -
ksef2.testdatawithgenerate_nip()andgenerate_pesel()for TEST-environment
data (#148). -
CertUsageEnumis exported fromksef2.models(#148). -
21 new
ksef2.modelsexports, so code that imported them from internal paths has
a public home (#153):ContextIdentifierTypeEnum,CertificateStatusEnum,
CertificateTypeEnum,RevocationReasonEnum,
validate_certificate_serial_number,AuthorizationPermissionTypeEnum,
AuthorizationSubjectIdentifierTypeEnum,EntityPermissionTypeEnum,
EuEntityAdminContextIdentifierTypeEnum,EuEntityPermissionTypeEnum,
IndirectPermissionTypeEnum,IndirectTargetIdentifierTypeEnum,
SubunitIdentifierTypeEnum,AuthContextIdentifierTypeEnum,
IdentifierTypeEnum(the TEST-data one:nip,pesel,fingerprint,
system),PermissionTypeEnum,SubjectTypeEnum,
TokenAuthorIdentifierTypeEnum,TokenPermissionEnum,TokenStatusEnumand
CurrencyCodes. -
Python 3.14 support: tested in CI and smoke-tested on the built wheel on 3.12,
3.13 and 3.14 (#146). -
PyPI project URLs and classifiers, including
Development Status :: 5 - Production/Stable(#146). -
ProfileConfigaccepts the flatauth_timeoutkey written by ksef2-cli 0.0.2,
maps it tomax_poll_attemptsand warns, instead of silently using the 60-second
default (#150). -
typing-extensionsis now a direct dependency, for@deprecated(#150). -
Page any collection one cursor at a time with
pager.page(cursor), which returns
aPageholdingitemsandnext_cursor. A cursor is opaque, versioned SDK
state, so a job that stops, restarts, or hands work to another process continues
with the next request instead of replaying the pages it already read. Every
Pager-returning collection answerspage(), andpages()plus iteration follow
the same cursor chain. An invoice search cursor carries the filters, parameters
and truncation boundary of the page it resumes, so a search continues across KSeF
truncation after a restart, and records which search issued it. A cursor from
another collection, from a different search, or one this SDK cannot read,
raisesKSeFArgumentErrorbefore any request is sent, without echoing the
cursor back. Resume a search cursor on a search built with the same filters,
page size and sort order. An explicitdate_tomust match the original end
date; an omitted default uses the bound saved in the cursor. The cursor shows those filters in readable form,
so keep it out of logs and URLs. A truncated page that cannot advance is still
returned with its invoices, and resuming its cursor raises
KSeFMetadataPaginationErrorwithout sending a request (#265).
Changed
-
Deprecation policy: old imports and methods remain functional through 1.x;
removal is a 2.0 decision (#171). This supersedes the earlier 1.10.0 plan. -
session.send_invoice()keeps its name but now returns anInvoiceSubmission
handle (#162). -
Argument errors from
batch_session(),online_session()andexport()are
nowKSeFArgumentError, which subclassesKSeFValidationError(and
TypeError), so existing handlers still catch them (#162). -
PermissionOperation.wait()raisesKSeFPermissionOperationFailedErrorwhen
KSeF rejects a grant, for example with status 440 on TEST (#163). -
API error messages have one format:
KSeF rejected <METHOD path> (HTTP ..., KSeF code ...): <description>, followed byDetails,Trace IDandHintlines. The
response body is no longer dumped into the message; it stays one.response.
Messages are for people: branch on the exception class orksef_code, never on
message text (#167). -
download_upo()fetches immediately. To poll until the UPO is ready, use
wait(timeout=..., poll_interval=...)beforedownload_upo()on a submission
or a closed online or batch session (#169). -
KSeFAuthError.exception_codenow reflects the KSeF code instead of always
beingUNKNOWN_ERROR(#167). -
The PyPI page now carries discoverability metadata: package keywords, a
description naming KSeF 2.0, FA(3) and sync/async,Natural Language
classifiers and project URLs (Homepage, Documentation, Repository, Issues,
Changelog) pointing atstackinghq.com,docs.stackinghq.comand
github.com/stacking-hq/ksef2. Both READMEs open with a plain-text
"KSeF Python SDK" heading and a Polish sentence (#284, #285). -
auth.tokens.list_page()is supported, not deprecated: it stays the single
request that takes KSeF's own continuation token, which resumablepage()
paging does not replace.auth.tokens.list_all()remains deprecated in favour
ofauth.tokens.list()(#265). -
FormSchemais written to JSON as its member name, such as"FA3", in model
dumps, saved state and pagination cursors, and reads back from that name or from
the list form earlier versions wrote. A model holding aFormSchemanow survives a
JSON round trip, so an invoice search filtered byinvoice_schemaresumes from its
cursor, and its JSON Schema is a string enum of the member names (#265).
KSeF API
- Targets KSeF OpenAPI 2.9.0; API coverage is 100% of the 83 endpoints in the spec.
The personal-permissions query response gainsownerPermissionsand the
OwnerPermissionScopeenum in the raw models (#264). - Policy: a breaking change forced by KSeF itself may ship in a minor release under
a "KSeF API changes" heading. Breaking changes the SDK chooses to make need a
new major version.
Fixed
- Enum inputs now accept documented values case-insensitively across online session
form codes, invoice export compression and sort order, FA(3) VAT markers, and PDF
page sizes. Invalid enum inputs raiseKSeFArgumentErrorwith valid choices.
Numeric VAT rates such as23andDecimal("0.23")are rejected; pass the FA(3)
marker as a string, such as"23"or"zw"(#298). - FA(3) tax exemptions write only the selected legal basis, and new-transport
annotations can be attached without supplying other annotation fields (#179, #176). - Give each invoice in the batch examples its own FA(3) number (#135).
- Compare
(method, path)pairs in the API coverage check and enforce the result,
so a missing or SDK-only endpoint fails the check (#129). - Remove the invalid
[project] pythonpathsetting frompyproject.toml(#146).
Build and CI
- Run the invoice workflows against KSeF TEST instead of skipping them (#138), on
every push tomain, pull request and dispatch through a newintegration.yml,
and in the release path with a check that rejects workflows that never ran (#139). - Releases no longer dispatch a docs deployment. The ksef2-docs site picks up the
new release on its daily run or a manual run (#154). - Smoke-test the built wheel on Python 3.12, 3.13 and 3.14 before publishing, and
add 3.14 to the CI matrix (#146). scripts/validate_examples.pyrejects examples and documentation code blocks that
import from a module path with an underscore-prefixed component;
scripts/validate_docs_paths.pyand the OpenAPI-version check cover the docs
pages (#148, #153, #136).- Public-module visibility checks cover the documented imports. The legacy
compatibility gate checks the retained import paths and methods (#171). - A docstring test and ruff pydocstyle keep every public API documented (#159).
scripts/validate_docs_markdown.pychecks the docs Markdown (#158).- Remove the in-repo CLI script and its integration test; the CLI lives in the
separateksef2-clipackage (#137).
Docs
- Rewrite the examples and documentation snippets to import from public paths only;
the one example that needs internals moved toscripts/advanced_examples/(#148). - Document the public API contract, the "Deprecated APIs" table, the secrets and
serialization rules and the KSeF-driven change policy, in English and Polish
(#148, #150). - Correct the 1.0.0 release notes (OpenAPI 2.8.1, collective-identifier surface),
drop the stale pre-1.0 migration page and add drift gates (#136). - Document every public API with Google-style docstrings (1428 of 1428 public
units and 957 of 957 model fields). The docstrings are now the source of the
generated API reference (#159). - The SDK docs are plain Markdown instead of MDX (#158).
Release history note
Two earlier versions never reached PyPI. v0.21.0 was bumped but never tagged; its
changes (OpenAPI 2.8.1) shipped in v0.22.0. The v0.22.1 tag points at a commit whose
project version was still 0.22.0, so the publish run failed its version check; its
fix (#118) shipped in v0.22.2. PyPI goes 0.20.0, 0.22.0, 0.22.2, 1.0.0.
Breaking
- Wrap failed HTTP requests in
KSeFTransportError(code = "TRANSPORT_ERROR"),
so no public method lets anhttpxexception escape and every SDK failure is a
KSeFException. It covers everyhttpx.RequestError, plushttpx.InvalidURLandhttpx.StreamError: connection and timeout
failures, a response the HTTP client could not decode, and an abandoned redirect
chain. The error carries the requestmethod, the URL pathname aspath
(userinfo, host, query and fragment are dropped) andoutcome_ambiguousfor
requests that may have reached KSeF; the originalhttpxexception stays
available as__cause__. It does not subclasshttpx.HTTPError, so handlers
that caughthttpx.HTTPErrormust nameKSeFTransportErrorinstead. Retries,
retryable statuses and API error classification are unchanged, and
KSeFExternalTransferError,KSeFBatchUploadErrorand
KSeFAuthTokenRedemptionErrornow derive fromKSeFTransportErrorwhile keeping
their own codes, attributes and recovery behaviour (#268).
Fixed
- Person permission queries no longer duplicate the entity name and no longer
drop the entity address.PersonPermissionDetailmaps the API's
subjectEntityDetails.fullNametoentity_full_nameand exposes
subjectEntityDetails.addressasentity_address, replacing
entity_first_nameandentity_last_name, which held the same full name in
both fields and discarded the address (#205).