Download the PHP package b44x/ksef-php without Composer

On this page you can find all versions of the php package b44x/ksef-php. It is possible to download/install these versions without Composer. Possible dependencies are resolved automatically.

FAQ

After the download, you have to make one include require_once('vendor/autoload.php');. After that you have to import the classes with use statements.

Example:
If you use only one package a project is not needed. But if you use more then one package, without a project it is not possible to import the classes with use statements.

In general, it is recommended to use always a project to download your libraries. In an application normally there is more than one library needed.
Some PHP packages are not free to download and because of that hosted in private repositories. In this case some credentials are needed to access such packages. Please use the auth.json textarea to insert credentials, if a package is coming from a private repository. You can look here for more information.

  • Some hosting areas are not accessible by a terminal or SSH. Then it is not possible to use Composer.
  • To use Composer is sometimes complicated. Especially for beginners.
  • Composer needs much resources. Sometimes they are not available on a simple webspace.
  • If you are using private repositories you don't need to share your credentials. You can set up everything on our site and then you provide a simple download link to your team member.
  • Simplify your Composer build process. Use our own command line tool to download the vendor folder as binary. This makes your build process faster and you don't need to expose your credentials for private repositories.
Please rate this library. Is it a good library?

Informations about the package ksef-php

ksef-php

English · Polski

Framework-agnostic PHP SDK for the Polish National e-Invoice System (KSeF) API 2.0.

It takes care of everything between your application and KSeF: authentication (XAdES certificate or KSeF token), token refresh, client-side encryption, FA(3) invoice XML generation with XSD validation, interactive sessions, asynchronous status polling, UPO retrieval, invoice download and search. Your code works with domain objects, not with endpoints, XML or cryptography.

Status: pre-1.0. The public API is documented below and covered by tests, but may still receive adjustments before 1.0.0. See CHANGELOG.md.

Requirements

Installation

guzzlehttp/guzzle is only one possible HTTP client; the SDK itself depends on the PSR interfaces only.

Try it in 60 seconds

This needs no account: it runs against the public KSeF TEST environment with a throw-away taxpayer (the examples use Guzzle, a dev dependency). See examples/ for the fourteen guided examples and docs/GETTING-STARTED.md for the path to production.

Quick start

Runnable, fully typed variants live in examples/.

Concepts you need to know

KSeF processing is asynchronous, and the SDK models that honestly:

Step Meaning SDK
Request created Invoice validated, XML built, XSD-checked Invoice::builder()->build(), InvoiceDocument
Request sent / accepted KSeF returned HTTP 202: accepted for processing InvoiceSubmission
Processed status 200 and a KSeF number, or a rejection (4xx codes) waitForInvoice() → SessionInvoice
Stored permanentStorageDate set; the document can be downloaded waitForInvoice(..., untilStored: true), isPermanentlyStored()
UPO available signed confirmation of receipt invoiceUpo()

Configuration

Environments

Environment::Test (self-signed certificates allowed, no real data), Environment::Demo (pre-production) and Environment::Production. Use baseUrl() for a mock server.

Authentication

KSeF issues a short-lived access token (JWT) plus a refresh token. The SDK performs the full flow transparently on first use: challenge → proof of identity → status polling → token redemption, refreshes the access token before it expires, and falls back to a fresh authentication when the refresh token is rejected. A 401 answer triggers exactly one re-authentication and retry.

Two kinds of credentials are supported:

Use CertificateCredentials with a custom XadesSigner to keep the private key in an HSM or a remote signing service. Restrict where an access token may be used with ->allowedIps(new AllowedIps([...])).

Qualified certificates are verified by KSeF through OCSP/CRL on PRE/PROD, so "authentication in progress" can last a while. The wait is bounded and configurable (authenticationPolling()). KSeF recommends authenticating with a KSeF certificate in production.

Signing outside the SDK

No certificate? Many small businesses sign with a trusted profile (Profil Zaufany / ePUAP) or a qualified signature app. The SDK cannot sign for them, so the login is split in two and the signature is made elsewhere:

Before that, any call throws ManualSignatureRequiredException. With a token store the tokens serve the following requests until the refresh token expires, so the person signs once, not on every request (examples/14-manual-signing.php).

Builder options

Timeouts and TLS verification are properties of your PSR-18 client; configure sensible timeouts and keep certificate verification enabled.

Creating an invoice

Invoice is an immutable, always-valid aggregate. Amounts are exact decimals (Decimal, strings in the API) – floats are never accepted. Net-priced lines; tax is computed per rate bucket on the summed net value and rounded half away from zero, as the VAT Act prescribes.

Supported: standard (VAT) and correction (KOR) invoices, one seller, one buyer (Polish NIP, EU VAT, foreign tax id or none), all common VAT treatments (23/22/8/7/5 %, 0 % variants, zw, oo, np), GTU codes, payment details, annotations and a footer. Corrections: mark the original state with InvoiceLine::asBefore() and add the corrected lines, or reverse the original lines with a negative quantity or price; totals become differences automatically.

Other invoice forms. Besides FA(3) the SDK handles FA_RR (1) farmer purchase invoices with a typed model (RrInvoice, see examples/11-farmer-rr-invoice.php) and accepts Peppol documents (PEF (3) invoices and PEF_KOR (3) credit notes) as verified raw XML: InvoiceDocument::fromXml($ublXml) recognises the form from the root element and checks it against the bundled schema. Sending PEF invoices as a Peppol provider is verified end to end on TEST (examples/13-peppol-invoice.php, docs/PEPPOL.md), credit notes (PEF_KOR) included.

Optional extras (all in examples/12-rich-invoice.php): InvoiceLine::withDiscount(), deliveredOn(), withProcedure(), withExcise(); addInfo() remarks, addWarehouseDocument(); additionalSettlement() (charges and deductions); Payment::partlyPaid(), early-payment discount and other payment methods; terms() (contracts, orders, batch numbers, delivery terms); margin schemes and related-party flags in Annotations; and a structured attachment(). KSeF accepts attachments only in batch sessions and only from taxpayers who gave their consent beforehand (attachmentStatus()); the SDK refuses to send them in an interactive session.

Additional parties (Podmiot3: recipient, payer, factor, ...) are added with addThirdParty(ThirdParty::of(ThirdPartyRole::Recipient, ...)).

The typed model covers every part of FA(3), including the intra-Community supply of new means of transport (Annotations::$newTransport). Seller/buyer data before a correction (Podmiot1K/Podmiot2K) go into Correction, transports and the contractual currency into TransactionTerms, EORI numbers, the JST/VAT-group flags and correspondence addresses into Seller and Buyer.

Special kinds (how each field is filled, and what to confirm with an accountant: docs/ADVANCE-INVOICES.md):

Raw XML escape hatch. Any FA(3) document can be sent after verification:

Sending invoices

Each invoice is encrypted with a per-session AES-256-CBC key which is wrapped with the Ministry's RSA key (OAEP, SHA-256). Hashes and sizes of plaintext and ciphertext are computed for you.

Batch sessions

For large volumes send a batch: the SDK validates every invoice, builds a ZIP (temporary file, never fully in memory), splits it into parts of at most 100 MB (max. 50 parts, 10,000 invoices), encrypts each part, uploads them to the pre-signed URLs KSeF returns and closes the session. Requires ext-zip.

Permissions

Grants and revocations are asynchronous in KSeF; these calls wait for the operation and throw PermissionOperationException (with KSeF's status code) when it is refused. Also available: listMyPermissions(), listEntityPermissions().

Special arrangements have their own calls, all asynchronous in KSeF and awaited by the SDK:

Export, limits and logins

Collective identifiers and Peppol

KSeF certificates

KSeF issues its own certificates (type Authentication for logging in, type Offline for signing KOD II links). requestCertificate() runs the whole enrolment: limit check, subject lookup, local key + CSR generation (EC P-256 by default, RSA 2048 optional), submission, waiting, retrieval. The private key exists only in the returned object: store it in a secret manager. The session must be authenticated with a signature (CertificateCredentials); KSeF refuses enrolment from token sessions.

QR codes

Offline invoicing (issue without KSeF, deliver later, technical correction) has its own guide: docs/OFFLINE.md.

VerificationLinks builds the links for the QR codes of an invoice visualisation, and QrCodeRenderer draws them as SVG with the caption underneath (needs composer require bacon/bacon-qr-code):

When KSeF is down, $ksef->availability()->isFailure() says so, and new OfflineDeadline() tells you by when the offline invoices must be delivered (docs/OFFLINE.md).

Reading invoices

An invoice downloaded from KSeF (a purchase invoice, an export, a stored document) becomes typed data with read():

The XML is verified against the FA(3) schema first, and every figure is the issuer's own: nothing is recalculated. This is a read model, separate from the Invoice you issue with. FA_RR and Peppol documents are not read yet.

Is KSeF up?

The Ministry publishes the service for TEST and production only; on Demo these calls throw a ConfigurationException unless you point the builder at one with ->latarniaUrl().

Checking your setup (ksef-doctor)

Before the first real invoice, let the doctor check that everything works. It is read-only: it logs in (and ends that login again), reads the limits, permissions and invoices, and sends nothing.

It checks PHP and its extensions, the certificate (expiry, self-signed on production), that KSeF is reachable and that the clock is right, KSeF's availability, the login (with KSeF's own explanation and trace id when it is refused), the limits, the permissions and read access to invoices. Exit code 0 means nothing failed, 1 a check failed, 2 the settings are wrong; --json prints the report for scripts. Secrets come from environment variables, never from arguments. It uses Guzzle (composer require guzzlehttp/guzzle).

Tokens between requests

PHP starts every request with an empty memory, so by default every request authenticates again. Give the client a store and requests share the access and refresh tokens until they expire:

The stored tokens are secrets: keep the directory or cache private to your application. Different credentials or contexts never share entries.

Verifying a UPO

Without a certificate you trust, a valid signature proves the document was not changed, not who signed it; take the certificate from the Ministry's official publication.

Reliability: timeouts, retries and duplicates

A timeout or 5xx while an invoice is being sent never proves that KSeF did not receive it. The SDK therefore reconciles automatically instead of guessing (SubmissionRecoveryPolicy, on by default):

  1. it searches the session for the document's hash; if KSeF has it, the submission is returned with $submission->recovered === true and nothing is sent again;
  2. otherwise the identical document is re-sent (default: up to 2 times, 1 s then 2 s backoff). This cannot create a second invoice: KSeF detects duplicates globally by seller NIP + invoice type + invoice number and answers 440 with originalKsefNumber;
  3. if that stays inconclusive, SubmissionOutcomeUnknownException is thrown (session reference and hash included; findSubmission() can still resolve it later).

A refusal (4xx) at any point is final and propagates unchanged. Tune or switch off with ->submissionRecovery(new SubmissionRecoveryPolicy(maxResends: 3)) / SubmissionRecoveryPolicy::disabled(). For recovered submissions use assertStored() (also accepts a 440 duplicate: the document is in KSeF).

Other calls: only HTTP 429 is retried for mutating requests (Retry-After honoured up to a cap); read-only calls are also retried on network errors and 500/502/503/504. Polling is always bounded (PollingPolicy); a PollingTimeoutException means "unknown yet", not "failed".

Checking status

Retrieving UPO, invoices and searching

Error handling

All exceptions extend B4x\Ksef\Exception\KsefException.

Exception Meaning Typical reaction
ValidationException (SerializationException) Local validation failed; nothing was sent; ->violations lists all problems Fix the data
ApiException + AuthenticationException (401), AuthorizationException (403, ->reasonCode), RateLimitException (429, ->retryAfterSeconds), ServerException (5xx) KSeF answered with an error; ->httpStatus, ->ksefCode(), ->errors, ->traceId Per status; report traceId to KSeF support
InvoiceRejectedException Processing ended with a failure status (->status) Correct the invoice; for 440 look at originalKsefNumber()
SubmissionOutcomeUnknownException Network/5xx during submission and automatic reconciliation was inconclusive findSubmission() later, or re-send the identical document
TransportException / MalformedResponseException No usable HTTP answer / contract violation Retry read operations later
PollingTimeoutException Waiting budget exhausted; operation may still complete Poll again later
InvoiceNotAvailableException Accepted invoice not stored yet (HTTP 406) Wait and retry
SigningException, EncryptionException, ConfigurationException, SessionException Local cryptography, wiring or session state problems Fix configuration

Messages and exception data never contain tokens, private keys or request bodies.

Security

Report vulnerabilities as described in SECURITY.md.

Framework integration

The core has no framework dependency. Wire it in your container, for example:

Dedicated bridges can live in separate packages; the PSR interfaces are the integration points.

Architecture

See docs/PROTOCOL.md for design decisions and the protocol facts this implementation relies on.

Testing

Setting up test situations (TEST environment only; refused anywhere else): Testing\TestData covers the /testdata operations that need no login (entities with subunits, people, permissions, the attachment consent, blocked contexts), and $ksef->testData() the ones on your own context:

Live tests (opt-in) run the complete lifecycle against the public KSeF TEST environment: they create a throw-away taxpayer through the TEST-only /testdata API, authenticate with a self-signed certificate and with a freshly generated KSeF token, send an invoice, wait for acceptance, fetch the UPO, download the invoice and verify duplicate detection. No credentials are needed:

Performance

composer bench (tools/bench.php) measures the CPU and memory bound parts. Sample run (one sandbox core, PHP 8.3; numbers depend on the machine, compare runs on the same one):

Scenario Time
build and validate an invoice, 1000 lines ~4 ms
serialize + XSD validate, 1 / 100 / 1000 lines ~5 / ~7 / ~32 ms
AES-256-CBC, 10 MiB: encrypt / decrypt ~15 / ~5 ms
batch: serialize + zip 100 invoices ~0.5 s
batch: serialize + zip 1000 invoices ~6 s (peak memory ~2 MiB)

A batch is dominated by XSD validation (a few ms per invoice); memory grows by a few bytes per invoice (its hash), while zipping and encryption stream one part at a time.

Stability

The public API follows semantic versioning; what counts as public (and what is @internal) is in docs/UPGRADING.md.

Contributing

See CONTRIBUTING.md. Run composer install && composer check before opening a pull request.

License

MIT. See LICENSE. The bundled XSD schemas are published by the Polish Ministry of Finance (see resources/schemas).


All versions of ksef-php with dependencies

PHP Build Version
Package Version
Requires php Version ^8.2
ext-dom Version *
ext-json Version *
ext-libxml Version *
ext-mbstring Version *
ext-openssl Version *
phpseclib/phpseclib Version ^3.0.43
psr/clock Version ^1.0
psr/http-client Version ^1.0
psr/http-factory Version ^1.1
psr/http-message Version ^1.1 || ^2.0
psr/log Version ^2.0 || ^3.0
Composer command for our command line client (download client) This client runs in each environment. You don't need a specific PHP version etc. The first 20 API calls are free. Standard composer command

The package b44x/ksef-php contains the following files

Loading the files please wait ...