PHP code example of n1ebieski / ksef-php-client

1. Go to this page and download the library: Download n1ebieski/ksef-php-client library. Choose the download type require.

2. Extract the ZIP file and open the index.php.

3. Add this code to the index.php.
    
        
<?php
require_once('vendor/autoload.php');

/* Start to develop here. Best regards https://php-download.com/ */

    

n1ebieski / ksef-php-client example snippets


use N1ebieski\KSEFClient\ClientBuilder;
use N1ebieski\KSEFClient\ValueObjects\Mode;
use N1ebieski\KSEFClient\Factories\ValinorCacheFactory;
use N1ebieski\KSEFClient\Factories\EncryptionKeyFactory;

$client = (new ClientBuilder())
    ->withMode(Mode::Production) // Choice between: Test, Demo, Production
    ->withApiUrl($_ENV['KSEF_API_URL']) // Optional, default is set by Mode selection
    ->withLatarniaApiUrl($_ENV['KSEF_LATARNIA_API_URL']) // Optional, default is set by Mode selection
    ->withHttpClient(new \GuzzleHttp\Client(...)) // Optional PSR-18 implementation, default is set by Psr18ClientDiscovery::find()
    ->withCache(new \Symfony\Component\Cache\Psr16Cache(...), $_ENV['CACHE_TTL']) // Optional PSR-16 implementation, default is null
    ->withValinorCache(ValinorCacheFactory::make()) // Optional CuyZ\Valinor\Cache\Cache implementation for caching auto-mapping DTO, default is null, more information: https://valinor-php.dev/2.3/other/performance-and-caching/
    ->withLogger(new \Monolog\Logger(...)) // Optional PSR-3 implementation, default is set by PsrDiscovery\Discover::log()
    ->withLogPath($_ENV['PATH_TO_LOG_FILE'], $_ENV['LOG_LEVEL']) // Optional, level: null disables logging
    ->withExceptionHandler(new \ExceptionHandler(...)) // Optional N1ebieski\KSEFClient\Contracts\Exception\ExceptionHandlerInterface implmentation
    ->withAccessToken($_ENV['ACCESS_TOKEN'], $_ENV['VALID_UNTIL']) // Optional, if present, auto authorization is skipped
    ->withRefreshToken($_ENV['REFRESH_TOKEN'], $_ENV['VALID_UNTIL']) // Optional, if present, auto refresh access token is enabled
    ->withKsefToken($_ENV['KSEF_TOKEN']) // Required for API Token authorization. Optional otherwise
    ->withCertificate($_ENV['CERTIFICATE'], $_ENV['CERTIFICATE_PASSPHRASE']) // Required .p12 contents for Certificate authorization. Optional otherwise
    ->withCertificatePath($_ENV['PATH_TO_CERTIFICATE'], $_ENV['CERTIFICATE_PASSPHRASE']) // Required path to .p12 file for Certificate authorization. Optional otherwise
    ->withVerifyCertificateChain(true) // Optional. Explanation https://api-test.ksef.mf.gov.pl/docs/v2/index.html#tag/Uzyskiwanie-dostepu/paths/~1auth~1xades-signature/post
    ->withEncryptionKey(EncryptionKeyFactory::makeRandom()) // Required for invoice resources. Remember to save this value!
    ->withIdentifier('NIP_NUMBER') // Required for authorization. Optional otherwise
    ->withAsyncMaxConcurrency(8) // Optional. Maximum concurrent send operations during asynchronous sending
    ->withValidateXml(true) // Optional. XML document validation based on XSD schemas
    ->withRetryTiming(10, 120) // Optional. Authorization status retry timing: backoff in seconds and max wait time in seconds
    ->build();

use N1ebieski\KSEFClient\Requests\Auth\Status\StatusRequest;
use N1ebieski\KSEFClient\Requests\ValueObjects\ReferenceNumber;

$authorisationStatusResponse = $client->auth()->status(new StatusRequest(
    referenceNumber: ReferenceNumber::from('20250508-EE-B395BBC9CD-A7DB4E6095-BD')
))->object();

$authorisationStatusResponse = $client->auth()->status([
    'referenceNumber' => '20250508-EE-B395BBC9CD-A7DB4E6095-BD'
])->object();

use N1ebieski\KSEFClient\DTOs\Requests\Sessions\Faktura;

$faktura = Faktura::fromXml('<Faktura> ... </Faktura>');

use N1ebieski\KSEFClient\ClientBuilder;
use N1ebieski\KSEFClient\Factories\ValinorCacheFactory;

$client = (new ClientBuilder())
    ->withValinorCache(ValinorCacheFactory::make()) // Or other CuyZ\Valinor\Cache\Cache implementation

use N1ebieski\KSEFClient\DTOs\Requests\Sessions\Faktura;

$faktura = Faktura::from([...], ValinorCacheFactory::make());

$deserialized = Faktura::fromXml($faktura->toXml(), ValinorCacheFactory::make());

use N1ebieski\KSEFClient\ClientBuilder;

$client = (new ClientBuilder())
    ->withKsefToken($_ENV['KSEF_KEY'])
    ->withIdentifier('NIP_NUMBER')
    ->build();

// Do something with the available resources

use N1ebieski\KSEFClient\ClientBuilder;

$client = (new ClientBuilder())
    ->withCertificatePath($_ENV['PATH_TO_CERTIFICATE'], $_ENV['CERTIFICATE_PASSPHRASE'])
    ->withIdentifier('NIP_NUMBER')
    ->build();

// Do something with the available resources

use N1ebieski\KSEFClient\ClientBuilder;

$client = (new ClientBuilder())
    ->withCertificate($_ENV['CERTIFICATE'], $_ENV['CERTIFICATE_PASSPHRASE'])
    ->withIdentifier('NIP_NUMBER')
    ->build();

// Do something with the available resources

use N1ebieski\KSEFClient\ClientBuilder;
use N1ebieski\KSEFClient\Support\Utility;
use N1ebieski\KSEFClient\Requests\Auth\DTOs\XadesSignature;
use N1ebieski\KSEFClient\Requests\Auth\XadesSignature\XadesSignatureXmlRequest;

$client = (new ClientBuilder())->build();

$nip = 'NIP_NUMBER';

$authorisationChallengeResponse = $client->auth()->challenge()->object();

$xml = XadesSignature::from([
    'challenge' => $authorisationChallengeResponse->challenge,
    'contextIdentifierGroup' => [
        'identifierGroup' => [
            'nip' => $nip
        ]
    ],
    'subjectIdentifierType' => 'certificateSubject'
])->toXml();

$signedXml = 'SIGNED_XML_DOCUMENT'; // Sign a xml document via Szafir, ePUAP etc.

$authorisationAccessResponse = $client->auth()->xadesSignature(
    new XadesSignatureXmlRequest($signedXml)
)->object();

$client = $client->withAccessToken($authorisationAccessResponse->authenticationToken->token);

$authorisationStatusResponse = Utility::retry(function () use ($client, $authorisationAccessResponse) {
    $authorisationStatusResponse = $client->auth()->status([
        'referenceNumber' => $authorisationAccessResponse->referenceNumber
    ])->object();

    if ($authorisationStatusResponse->status->code === 200) {
        return $authorisationStatusResponse;
    }

    if ($authorisationStatusResponse->status->code >= 400) {
        throw new RuntimeException(
            $authorisationStatusResponse->status->description,
            $authorisationStatusResponse->status->code
        );
    }
});

$authorisationTokenResponse = $client->auth()->token()->redeem()->object();

$client = $client
    ->withAccessToken(
        token: $authorisationTokenResponse->accessToken->token, 
        validUntil: $authorisationTokenResponse->accessToken->validUntil
    )
    ->withRefreshToken(
        token: $authorisationTokenResponse->refreshToken->token,
        validUntil: $authorisationTokenResponse->refreshToken->validUntil
    );

// Do something with the available resources

$response = $client->auth()->challenge()->object();

use N1ebieski\KSEFClient\Requests\Auth\XadesSignature\XadesSignatureRequest;

$response = $client->auth()->xadesSignature(
    new XadesSignatureRequest(...)
)->object();

use N1ebieski\KSEFClient\Requests\Auth\XadesSignature\XadesSignatureXmlRequest;

$response = $client->auth()->xadesSignature(
    new XadesSignatureXmlRequest(...)
)->object();

use N1ebieski\KSEFClient\Requests\Auth\Status\StatusRequest;

$response = $client->auth()->status(
    new StatusRequest(...)
)->object();

$response = $client->auth()->token()->redeem()->object();

$response = $client->auth()->token()->refresh()->object();

use N1ebieski\KSEFClient\Requests\Auth\Sessions\List\ListRequest;

$response = $client->auth()->sessions()->list(
    new ListRequest(...)
)->object();

$response = $client->auth()->sessions()->revokeCurrent()->status();

use N1ebieski\KSEFClient\Requests\Auth\Sessions\Revoke\RevokeRequest;

$response = $client->auth()->sessions()->revoke(
    new RevokeRequest(...)
)->status();

use N1ebieski\KSEFClient\Requests\Limits\Context\ContextRequest;

$response = $client->limits()->context(
    new ContextRequest(...)
)->object();

use N1ebieski\KSEFClient\Requests\Limits\Subject\SubjectRequest;

$response = $client->limits()->subject(
    new SubjectRequest(...)
)->object();

$response = $client->rateLimits()->object();

$response = $client->security()->publicKeyCertificates()->object();

use N1ebieski\KSEFClient\Requests\Sessions\List\ListRequest;

$response = $client->sessions()->list(
    new ListRequest(...)
)->object();

use N1ebieski\KSEFClient\Requests\Sessions\Invoices\List\ListRequest;

$response = $client->sessions()->invoices()->list(
    new ListRequest(...)
)->object();

use N1ebieski\KSEFClient\Requests\Sessions\Invoices\Failed\FailedRequest;

$response = $client->sessions()->invoices()->failed(
    new FailedRequest(...)
)->object();

use N1ebieski\KSEFClient\Requests\Sessions\Invoices\Upo\UpoRequest;

$response = $client->sessions()->invoices()->upo(
    new UpoRequest(...)
)->body();

use N1ebieski\KSEFClient\Requests\Sessions\Invoices\KsefUpo\KsefUpoRequest;

$response = $client->sessions()->invoices()->ksefUpo(
    new KsefUpoRequest(...)
)->body();

use N1ebieski\KSEFClient\Requests\Sessions\Invoices\Status\StatusRequest;

$response = $client->sessions()->invoices()->status(
    new StatusRequest(...)
)->object();

use N1ebieski\KSEFClient\Requests\Sessions\Online\Open\OpenRequest;

$response = $client->sessions()->online()->open(
    new OpenRequest(...)
)->object();

use N1ebieski\KSEFClient\Requests\Sessions\Online\Close\CloseRequest;

$response = $client->sessions()->online()->close(
    new CloseRequest(...)
)->status();

use N1ebieski\KSEFClient\Requests\Sessions\Online\Send\SendRequest;

$response = $client->sessions()->online()->send(
    new SendRequest(...)
)->object();

use N1ebieski\KSEFClient\Requests\Sessions\Online\Send\SendXmlRequest;

$response = $client->sessions()->online()->send(
    new SendXmlRequest(...)
)->object();

use N1ebieski\KSEFClient\Requests\Sessions\Batch\OpenAndSend\OpenAndSendRequest;

$response = $client->sessions()->batch()->openAndSend(
    new OpenAndSendRequest(...)
)->object();

use N1ebieski\KSEFClient\Requests\Sessions\Batch\OpenAndSend\OpenAndSendXmlRequest;

$response = $client->sessions()->batch()->openAndSend(
    new OpenAndSendXmlRequest(...)
)->object();

use N1ebieski\KSEFClient\Requests\Sessions\Batch\OpenAndSend\OpenAndSendZipRequest;

$response = $client->sessions()->batch()->openAndSend(
    new OpenAndSendZipRequest(...)
)->object();

use N1ebieski\KSEFClient\Requests\Sessions\Batch\Close\CloseRequest;

$response = $client->sessions()->batch()->close(
    new CloseRequest(...)
)->status();

use N1ebieski\KSEFClient\Requests\Sessions\Status\StatusRequest;

$response = $client->sessions()->status(
    new StatusRequest(...)
)->object();

use N1ebieski\KSEFClient\Requests\Sessions\Upo\UpoRequest;

$response = $client->sessions()->upo(
    new UpoRequest(...)
)->body();

use N1ebieski\KSEFClient\Requests\Invoices\Download\DownloadRequest;

$response = $client->invoices()->download(
    new DownloadRequest(...)
)->body();

use N1ebieski\KSEFClient\Requests\Invoices\Query\Metadata\MetadataRequest;

$response = $client->invoices()->query()->metadata(
    new MetadataRequest(...)
)->object();

use N1ebieski\KSEFClient\Requests\Invoices\Exports\Init\InitRequest;

$response = $client->invoices()->exports()->init(
    new InitRequest(...)
)->object();

use N1ebieski\KSEFClient\Requests\Invoices\Exports\Status\StatusRequest;

$response = $client->invoices()->exports()->status(
    new StatusRequest(...)
)->object();

use N1ebieski\KSEFClient\Requests\Permissions\Persons\Grants\GrantsRequest;

$response = $client->permissions()->persons()->grants(
    new GrantsRequest(...)
)->object();

use N1ebieski\KSEFClient\Requests\Permissions\Entities\Grants\GrantsRequest;

$response = $client->permissions()->entities()->grants(
    new GrantsRequest(...)
)->object();

use N1ebieski\KSEFClient\Requests\Permissions\Authorizations\Grants\GrantsRequest;

$response = $client->permissions()->authorizations()->grants(
    new GrantsRequest(...)
)->object();

use N1ebieski\KSEFClient\Requests\Permissions\Authorizations\Revoke\RevokeRequest;

$response = $client->permissions()->authorizations()->revoke(
    new RevokeRequest(...)
)->object();

use N1ebieski\KSEFClient\Requests\Permissions\Indirect\Grants\GrantsRequest;

$response = $client->permissions()->indirect()->grants(
    new GrantsRequest(...)
)->object();

use N1ebieski\KSEFClient\Requests\Permissions\Subunits\Grants\GrantsRequest;

$response = $client->permissions()->subunits()->grants(
    new GrantsRequest(...)
)->object();

use N1ebieski\KSEFClient\Requests\Permissions\EuEntities\Grants\GrantsRequest;

$response = $client->permissions()->euEntities()->grants(
    new GrantsRequest(...)
)->object();

use N1ebieski\KSEFClient\Requests\Permissions\EuEntities\Administration\Grants\GrantsRequest;

$response = $client->permissions()->euEntities()->administration()->grants(
    new GrantsRequest(...)
)->object();

use N1ebieski\KSEFClient\Requests\Permissions\Common\Revoke\RevokeRequest;

$response = $client->permissions()->common()->revoke(
    new RevokeRequest(...)
)->object();

use N1ebieski\KSEFClient\Requests\Permissions\Query\Authorizations\Grants\GrantsRequest;

$response = $client->permissions()->query()->authorizations()->grants(
    new GrantsRequest(...)
)->object();

use N1ebieski\KSEFClient\Requests\Permissions\Query\Entities\Grants\GrantsRequest;

$response = $client->permissions()->query()->entities()->grants(
    new GrantsRequest(...)
)->object();

use N1ebieski\KSEFClient\Requests\Permissions\Query\Entities\Roles\RolesRequest;

$response = $client->permissions()->query()->entities()->roles(
    new RolesRequest(...)
)->object();

use N1ebieski\KSEFClient\Requests\Permissions\Query\EuEntities\Grants\GrantsRequest;

$response = $client->permissions()->query()->euEntities()->grants(
    new GrantsRequest(...)
)->object();

use N1ebieski\KSEFClient\Requests\Permissions\Query\Personal\Grants\GrantsRequest;

$response = $client->permissions()->query()->personal()->grants(
    new GrantsRequest(...)
)->object();

use N1ebieski\KSEFClient\Requests\Permissions\Query\Persons\Grants\GrantsRequest;

$response = $client->permissions()->query()->persons()->grants(
    new GrantsRequest(...)
)->object();

use N1ebieski\KSEFClient\Requests\Permissions\Query\Subunits\Grants\GrantsRequest;

$response = $client->permissions()->query()->subunits()->grants(
    new GrantsRequest(...)
)->object();

use N1ebieski\KSEFClient\Requests\Permissions\Query\SubordinateEntities\Roles\RolesRequest;

$response = $client->permissions()->query()->subordinateEntities()->roles(
    new RolesRequest(...)
)->object();

use N1ebieski\KSEFClient\Requests\Permissions\Operations\Status\StatusRequest;

$response = $client->permissions()->operations()->status(
    new StatusRequest(...)
)->object();

use N1ebieski\KSEFClient\Requests\Permissions\Attachments\Status\StatusRequest;

$response = $client->permissions()->attachments()->status(
    new StatusRequest(...)
)->object();

$response = $client->certificates()->limits()->object();

$response = $client->certificates()->enrollments()->data()->object();

use N1ebieski\KSEFClient\Requests\Certificates\Enrollments\Send\SendRequest;

$response = $client->certificates()->enrollments()->send(
    new SendRequest(...)
)->object();

use N1ebieski\KSEFClient\Requests\Certificates\Enrollments\Status\StatusRequest;

$response = $client->certificates()->enrollments()->status(
    new StatusRequest(...)
)->object();

use N1ebieski\KSEFClient\Requests\Certificates\Retrieve\RetrieveRequest;

$response = $client->certificates()->retrieve(
    new RetrieveRequest(...)
)->object();

use N1ebieski\KSEFClient\Requests\Certificates\Revoke\RevokeRequest;

$response = $client->certificates()->revoke(
    new RevokeRequest(...)
)->status();

use N1ebieski\KSEFClient\Requests\Certificates\Query\QueryRequest;

$response = $client->certificates()->query(
    new QueryRequest(...)
)->object();

use N1ebieski\KSEFClient\Requests\Tokens\Create\CreateRequest;

$response = $client->tokens()->create(
    new CreateRequest(...)
)->object();

use N1ebieski\KSEFClient\Requests\Tokens\List\ListRequest;

$response = $client->tokens()->list(
    new ListRequest(...)
)->object();

use N1ebieski\KSEFClient\Requests\Tokens\Status\StatusRequest;

$response = $client->tokens()->list(
    new StatusRequest(...)
)->object();

use N1ebieski\KSEFClient\Requests\Tokens\Revoke\RevokeRequest;

$response = $client->tokens()->revoke(
    new RevokeRequest(...)
)->status();

use N1ebieski\KSEFClient\Requests\Peppol\Query\QueryRequest;

$response = $client->peppol()->query(
    new QueryRequest(...)
)->object();

use N1ebieski\KSEFClient\Requests\Testdata\Attachment\Grant\ApproveRequest;

$response = $client->testdata()->attachment()->approve(
    new ApproveRequest(...)
)->status();

use N1ebieski\KSEFClient\Requests\Testdata\Attachment\Revoke\RevokeRequest;

$response = $client->testdata()->attachment()->revoke(
    new RevokeRequest(...)
)->status();

use N1ebieski\KSEFClient\Requests\Testdata\Person\Create\CreateRequest;

$response = $client->testdata()->person()->create(
    new CreateRequest(...)
)->status();

use N1ebieski\KSEFClient\Requests\Testdata\Person\Remove\RemoveRequest;

$response = $client->testdata()->person()->remove(
    new RemoveRequest(...)
)->status();

use N1ebieski\KSEFClient\Requests\Testdata\Context\Block\BlockRequest;

$response = $client->testdata()->context()->block(
    new BlockRequest(...)
)->status();

use N1ebieski\KSEFClient\Requests\Testdata\Context\Unblock\UnblockRequest;

$response = $client->testdata()->context()->unblock(
    new UnblockRequest(...)
)->status();

use N1ebieski\KSEFClient\Requests\Testdata\Permissions\Grants\GrantsRequest;

$response = $client->testdata()->permissions()->grants(
    new GrantsRequest(...)
)->status();

use N1ebieski\KSEFClient\Requests\Testdata\Permissions\Revoke\RevokeRequest;

$response = $client->testdata()->permissions()->revoke(
    new RevokeRequest(...)
)->status();

use N1ebieski\KSEFClient\Requests\Testdata\Limits\Context\Session\Limits\LimitsRequest;

$response = $client->testdata()->limits()->context()->session()->limits(
    new LimitsRequest(...)
)->status();

use N1ebieski\KSEFClient\Requests\Testdata\Limits\Context\Session\Reset\ResetRequest;

$response = $client->testdata()->limits()->context()->session()->reset(
    new ResetRequest(...)
)->status();

use N1ebieski\KSEFClient\Requests\Testdata\Limits\Subject\Certificate\Limits\LimitsRequest;

$response = $client->testdata()->limits()->subject()->certificate()->limits(
    new LimitsRequest(...)
)->status();

use N1ebieski\KSEFClient\Requests\Testdata\Limits\Subject\Certificate\Reset\ResetRequest;

$response = $client->testdata()->limits()->subject()->certificate()->reset(
    new ResetRequest(...)
)->status();

use N1ebieski\KSEFClient\Requests\Testdata\RateLimits\Limits\LimitsRequest;

$response = $client->testdata()->rateLimits()->limits(
    new LimitsRequest(...)
)->status();

use N1ebieski\KSEFClient\Requests\Testdata\RateLimits\Reset\ResetRequest;

$response = $client->testdata()->rateLimits()->reset(
    new ResetRequest(...)
)->status();

use N1ebieski\KSEFClient\Requests\Testdata\RateLimits\Production\ProductionRequest;

$response = $client->testdata()->rateLimits()->production(
    new ProductionRequest(...)
)->status();

$response = $client->latarnia()->status()->object();

$response = $client->latarnia()->messages()->object();

use N1ebieski\KSEFClient\Actions\ConvertCertificateToPkcs12\ConvertCertificateToPkcs12Action;
use N1ebieski\KSEFClient\Actions\ConvertCertificateToPkcs12\ConvertCertificateToPkcs12Handler;
use N1ebieski\KSEFClient\Support\Utility;
use N1ebieski\KSEFClient\Factories\CertificateFactory;

$certificate = file_get_contents(Utility::basePath('config/certificates/certificate.crt'));

$privateKey = file_get_contents(Utility::basePath('config/certificates/privateKey.key'));

$certificateToPkcs12 = (new ConvertCertificateToPkcs12Handler())->handle(
    new ConvertCertificateToPkcs12Action(
        certificate: CertificateFactory::makeFromPkcs8($certificate, $privateKey, 'password'),
        passphrase: 'password'
    )
);

file_put_contents(Utility::basePath('config/certificates/ksef-certificate.p12'), $certificateToPkcs12);



use N1ebieski\KSEFClient\Actions\ConvertCertificateToPkcs12\ConvertCertificateToPkcs12Action;
use N1ebieski\KSEFClient\Actions\ConvertCertificateToPkcs12\ConvertCertificateToPkcs12Handler;
use N1ebieski\KSEFClient\Actions\ConvertDerToPem\ConvertDerToPemAction;
use N1ebieski\KSEFClient\Actions\ConvertDerToPem\ConvertDerToPemHandler;
use N1ebieski\KSEFClient\Actions\ConvertPemToDer\ConvertPemToDerAction;
use N1ebieski\KSEFClient\Actions\ConvertPemToDer\ConvertPemToDerHandler;
use N1ebieski\KSEFClient\ClientBuilder;
use N1ebieski\KSEFClient\DTOs\DN;
use N1ebieski\KSEFClient\Factories\CSRFactory;
use N1ebieski\KSEFClient\Support\Utility;
use N1ebieski\KSEFClient\Factories\CertificateFactory;
use N1ebieski\KSEFClient\ValueObjects\Mode;
use N1ebieski\KSEFClient\ValueObjects\PrivateKeyType;

$client = (new ClientBuilder())
    ->withMode(Mode::Test)
    ->withIdentifier('NIP_NUMBER')
    // To generate the KSEF certificate, you have to authorize the qualified certificate the first time
    ->withCertificatePath($_ENV['PATH_TO_CERTIFICATE'], $_ENV['CERTIFICATE_PASSPHRASE'])
    ->build();

$dataResponse = $client->certificates()->enrollments()->data()->json();

$dn = DN::from($dataResponse);

// You can choose beetween EC or RSA private key type
$csr = CSRFactory::make($dn, PrivateKeyType::EC);

$csrToDer = (new ConvertPemToDerHandler())->handle(new ConvertPemToDerAction($csr->raw));

$sendResponse = $client->certificates()->enrollments()->send([
    'certificateName' => 'My first certificate',
    'certificateType' => 'Authentication',
    'csr' => base64_encode($csrToDer),
])->object();

$statusResponse = Utility::retry(function () use ($client, $sendResponse) {
    $statusResponse = $client->certificates()->enrollments()->status([
        'referenceNumber' => $sendResponse->referenceNumber
    ])->object();

    if ($statusResponse->status->code === 200) {
        return $statusResponse;
    }

    if ($statusResponse->status->code >= 400) {
        throw new RuntimeException(
            $statusResponse->status->description,
            $statusResponse->status->code
        );
    }
});

$retrieveResponse = $client->certificates()->retrieve([
    'certificateSerialNumbers' => [$statusResponse->certificateSerialNumber]
])->object();

$certificate = base64_decode($retrieveResponse->certificates[0]->certificate);

$certificateToPem = (new ConvertDerToPemHandler())->handle(
    new ConvertDerToPemAction($certificate, 'CERTIFICATE')
);

$certificateToPkcs12 = (new ConvertCertificateToPkcs12Handler())->handle(
    new ConvertCertificateToPkcs12Action(
        certificate: CertificateFactory::makeFromPkcs8($certificateToPem, $csr->privateKey),
        passphrase: 'password'
    )
);

file_put_contents(Utility::basePath('config/certificates/ksef-certificate.p12'), $certificateToPkcs12);



use Endroid\QrCode\Builder\Builder as QrCodeBuilder;
use Endroid\QrCode\Label\Font\OpenSans;
use Endroid\QrCode\RoundBlockSizeMode;
use N1ebieski\KSEFClient\Actions\ConvertEcdsaDerToRaw\ConvertEcdsaDerToRawHandler;
use N1ebieski\KSEFClient\Actions\GenerateQRCodes\GenerateQRCodesAction;
use N1ebieski\KSEFClient\Actions\GenerateQRCodes\GenerateQRCodesHandler;
use N1ebieski\KSEFClient\ClientBuilder;
use N1ebieski\KSEFClient\DTOs\QRCodes;
use N1ebieski\KSEFClient\DTOs\Requests\Sessions\Faktura;
use N1ebieski\KSEFClient\Factories\EncryptionKeyFactory;
use N1ebieski\KSEFClient\Support\Utility;
use N1ebieski\KSEFClient\Testing\Fixtures\DTOs\Requests\Sessions\FakturaSprzedazyTowaruFixture;
use N1ebieski\KSEFClient\ValueObjects\Mode;
use N1ebieski\KSEFClient\ValueObjects\Requests\KsefNumber;

$encryptionKey = EncryptionKeyFactory::makeRandom();

$nip = 'NIP_NUMBER';

$client = (new ClientBuilder())
    ->withMode(Mode::Test)
    ->withIdentifier($nip)
    ->withCertificatePath($_ENV['PATH_TO_CERTIFICATE'], $_ENV['CERTIFICATE_PASSPHRASE'])
    ->withEncryptionKey($encryptionKey)
    ->build();

$openResponse = $client->sessions()->online()->open([
    'formCode' => 'FA (3)',
])->object();

$fakturaFixture = (new FakturaSprzedazyTowaruFixture())
    ->withRandomInvoiceNumber()
    ->withNip($nip)
    ->withTodayDate();

// For sending FA (3) use Sessions\Faktura
// For sending FA_RR (1) use Sessions\FakturaRR\Faktura
$faktura = Faktura::from($fakturaFixture->data);

// For sending invoice as DTO use SendRequest or array
// For sending invoice as XML use SendXmlRequest
$sendResponse = $client->sessions()->online()->send([
    'faktura' => $faktura,
    'referenceNumber' => $openResponse->referenceNumber,
])->object();

$closeResponse = $client->sessions()->online()->close([
    'referenceNumber' => $openResponse->referenceNumber
]);

$statusResponse = Utility::retry(function () use ($client, $openResponse, $sendResponse) {
    $statusResponse = $client->sessions()->invoices()->status([
        'referenceNumber' => $openResponse->referenceNumber,
        'invoiceReferenceNumber' => $sendResponse->referenceNumber
    ])->object();

    if ($statusResponse->status->code === 200) {
        return $statusResponse;
    }

    if ($statusResponse->status->code >= 400) {
        throw new RuntimeException(
            $statusResponse->status->description,
            $statusResponse->status->code
        );
    }
});

$upo = $client->sessions()->invoices()->upo([
    'referenceNumber' => $openResponse->referenceNumber,
    'invoiceReferenceNumber' => $sendResponse->referenceNumber
])->body();

$generateQRCodesHandler = new GenerateQRCodesHandler(
    qrCodeBuilder: (new QrCodeBuilder())
        ->roundBlockSizeMode(RoundBlockSizeMode::Enlarge)
        ->labelFont(new OpenSans(size: 12)),
    convertEcdsaDerToRawHandler: new ConvertEcdsaDerToRawHandler()
);

$ksefNumber = KsefNumber::from($statusResponse->ksefNumber);

// For generating QR code by document use GenerateQRCodesAction
// For generating QR code by invoice hash use GenerateQRCodesByInvoiceHashAction

/** @var QRCodes $qrCodes */
$qrCodes = $generateQRCodesHandler->handle(new GenerateQRCodesAction(
    mode: Mode::Test,
    nip: $faktura->podmiot1->daneIdentyfikacyjne->nip,
    invoiceCreatedAt: $faktura->fa->p_1->value,
    document: $faktura->toXml(),
    ksefNumber: $ksefNumber
));

// Invoice link
file_put_contents(Utility::basePath("var/qr/code1.png"), $qrCodes->code1->raw);

use N1ebieski\KSEFClient\Actions\GeneratePDF\GeneratePDFAction;
use N1ebieski\KSEFClient\Actions\GeneratePDF\GeneratePDFHandler;
use N1ebieski\KSEFClient\Support\Utility;
use N1ebieski\KSEFClient\ValueObjects\KsefFeInvoiceConverterPath;

// Send an invoice using example https://github.com/N1ebieski/ksef-php-client?tab=readme-ov-file#send-an-invoice-check-for-upo-and-generate-qr-code

// and then...

$ksefFeInvoiceConverterPath = KsefFeInvoiceConverterPath::from(Utility::basePath('../ksef-pdf-generator/dist/cli/index.js'));

$pdfs = (new GeneratePDFHandler())->handle(new GeneratePDFAction(
    ksefFeInvoiceConverterPath: $ksefFeInvoiceConverterPath,    
    invoiceDocument $faktura->toXml(),
    upoDocument: $upo,
    qrCodes: $qrCodes,
    ksefNumber: $ksefNumber
));

file_put_contents(Utility::basePath("var/pdf/{$ksefNumber->value}.pdf"), $pdfs->invoice);
file_put_contents(Utility::basePath("var/pdf/UPO-{$sendResponse->referenceNumber}.pdf"), $pdfs->upo);

use N1ebieski\KSEFClient\Actions\GeneratePDF\GeneratePDFAction;
use N1ebieski\KSEFClient\Actions\GeneratePDF\GeneratePDFHandler;
use N1ebieski\KSEFClient\Support\Utility;
use N1ebieski\KSEFClient\ValueObjects\KsefFeInvoiceConverterPath;

// Create an online invoice using example https://github.com/N1ebieski/ksef-php-client?tab=readme-ov-file#send-an-invoice-check-for-upo-and-generate-qr-code

// and then...

$ksefFeInvoiceConverterPath = KsefFeInvoiceConverterPath::from(Utility::basePath('../ksef-pdf-generator/dist/cli/index.js'));

$pdfs = (new GeneratePDFHandler())->handle(new GeneratePDFAction(
    ksefFeInvoiceConverterPath: $ksefFeInvoiceConverterPath,    
    confirmationDocument: $faktura->toXml(),
    qrCodes: $qrCodes
));

file_put_contents(Utility::basePath("var/pdf/CONFIRMATION-{$faktura->fa->p_2->value}.pdf"), $pdfs->confirmation);



use N1ebieski\KSEFClient\ClientBuilder;
use N1ebieski\KSEFClient\Factories\EncryptionKeyFactory;
use N1ebieski\KSEFClient\Support\Utility;
use N1ebieski\KSEFClient\Testing\Fixtures\DTOs\Requests\Sessions\FakturaSprzedazyTowaruFixture;
use N1ebieski\KSEFClient\ValueObjects\Mode;

$encryptionKey = EncryptionKeyFactory::makeRandom();

$nip = 'NIP_NUMBER';

$client = (new ClientBuilder())
    ->withMode(Mode::Test)
    ->withIdentifier($nip)
    ->withCertificatePath($_ENV['PATH_TO_CERTIFICATE'], $_ENV['CERTIFICATE_PASSPHRASE'])
    ->withEncryptionKey($encryptionKey)
    ->build();

$faktury = array_map(
    fn () => (new FakturaSprzedazyTowaruFixture())
        ->withTodayDate()
        ->withNip($nip)
        ->withRandomInvoiceNumber()
        ->data,
    range(1, 100)
);

// For sending invoices as DTOs use OpenAndSendRequest or array
// For sending invoices as XMLs use OpenAndSendXmlRequest
// For sending invoices as ZIP use OpenAndSendZipRequest
$openAndSendResponse = $client->sessions()->batch()->openAndSend([
    'formCode' => 'FA (3)',
    'faktury' => $faktury
]);

$openResponse = $openAndSendResponse->object();

$partUploadResponses = $openAndSendResponse->partUploadResponses;

$client->sessions()->batch()->close([
    'referenceNumber' => $openResponse->referenceNumber
]);

$statusResponse = Utility::retry(function () use ($client, $openResponse) {
    $statusResponse = $client->sessions()->status([
        'referenceNumber' => $openResponse->referenceNumber,
    ])->object();

    if ($statusResponse->status->code === 200) {
        return $statusResponse;
    }

    if ($statusResponse->status->code >= 400) {
        throw new RuntimeException(
            $statusResponse->status->description,
            $statusResponse->status->code
        );
    }
});

$upo = file_get_contents($statusResponse->upo->pages[0]->downloadUrl);



use Endroid\QrCode\Builder\Builder as QrCodeBuilder;
use Endroid\QrCode\Label\Font\OpenSans;
use Endroid\QrCode\RoundBlockSizeMode;
use N1ebieski\KSEFClient\Actions\ConvertEcdsaDerToRaw\ConvertEcdsaDerToRawHandler;
use N1ebieski\KSEFClient\Actions\GenerateQRCodes\GenerateQRCodesAction;
use N1ebieski\KSEFClient\Actions\GenerateQRCodes\GenerateQRCodesHandler;
use N1ebieski\KSEFClient\DTOs\QRCodes;
use N1ebieski\KSEFClient\DTOs\Requests\Auth\ContextIdentifierGroup;
use N1ebieski\KSEFClient\DTOs\Requests\Sessions\Faktura;
use N1ebieski\KSEFClient\Factories\CertificateFactory;
use N1ebieski\KSEFClient\Support\Utility;
use N1ebieski\KSEFClient\Testing\Fixtures\DTOs\Requests\Sessions\FakturaSprzedazyTowaruFixture;
use N1ebieski\KSEFClient\ValueObjects\CertificatePath;
use N1ebieski\KSEFClient\ValueObjects\CertificateSerialNumber;
use N1ebieski\KSEFClient\ValueObjects\Mode;
use N1ebieski\KSEFClient\ValueObjects\NIP;

$nip = 'NIP_NUMBER';

// Remember: this certificate must be "Offline" type, not "Authentication"
$certificate = CertificateFactory::makeFromCertificatePath(
    CertificatePath::from($_ENV['PATH_TO_CERTIFICATE'], $_ENV['CERTIFICATE_PASSPHRASE'])
);

$fakturaFixture = (new FakturaSprzedazyTowaruFixture())
    ->withTodayDate()
    ->withNip($nip)
    ->withRandomInvoiceNumber();

// For creating FA (3) use Sessions\Faktura
// For creating FA_RR (1) use Sessions\FakturaRR\Faktura
$faktura = Faktura::from($fakturaFixture->data);

$generateQRCodesHandler = new GenerateQRCodesHandler(
    qrCodeBuilder: (new QrCodeBuilder())
        ->roundBlockSizeMode(RoundBlockSizeMode::Enlarge)
        ->labelFont(new OpenSans(size: 12)),
    convertEcdsaDerToRawHandler: new ConvertEcdsaDerToRawHandler()
);

$contextIdentifierGroup = ContextIdentifierGroup::fromIdentifier(NIP::from($nip));

// For generating QR codes by document use GenerateQRCodesAction
// For generating QR codes by invoice hash use GenerateQRCodesByInvoiceHashAction

/** @var QRCodes $qrCodes */
$qrCodes = $generateQRCodesHandler->handle(new GenerateQRCodesAction(
    mode: Mode::Test,
    nip: $faktura->podmiot1->daneIdentyfikacyjne->nip,
    invoiceCreatedAt: $faktura->fa->p_1->value,
    document: $faktura->toXml(),
    certificate: $certificate,
    contextIdentifierGroup: $contextIdentifierGroup
));

// Invoice link
file_put_contents(Utility::basePath("var/qr/code1.png"), $qrCodes->code1->raw);

// Certificate verification link
file_put_contents(Utility::basePath("var/qr/code2.png"), $qrCodes->code2->raw);

use N1ebieski\KSEFClient\Actions\GeneratePDF\GeneratePDFAction;
use N1ebieski\KSEFClient\Actions\GeneratePDF\GeneratePDFHandler;
use N1ebieski\KSEFClient\Support\Utility;
use N1ebieski\KSEFClient\ValueObjects\KsefFeInvoiceConverterPath;

// Create an offline invoice using example https://github.com/N1ebieski/ksef-php-client?tab=readme-ov-file#create-an-offline-invoice-and-generate-both-qr-codes

// and then...

$ksefFeInvoiceConverterPath = KsefFeInvoiceConverterPath::from(Utility::basePath('../ksef-pdf-generator/dist/cli/index.js'));

$pdfs = (new GeneratePDFHandler())->handle(new GeneratePDFAction(
    ksefFeInvoiceConverterPath: $ksefFeInvoiceConverterPath,    
    invoiceDocument: $faktura->toXml(),
    qrCodes: $qrCodes
));

file_put_contents(Utility::basePath("var/pdf/{$faktura->fa->p_2->value}.pdf"), $pdfs->invoice);



use N1ebieski\KSEFClient\Actions\DecryptDocument\DecryptDocumentAction;
use N1ebieski\KSEFClient\Actions\DecryptDocument\DecryptDocumentHandler;
use N1ebieski\KSEFClient\ClientBuilder;
use N1ebieski\KSEFClient\Factories\EncryptionKeyFactory;
use N1ebieski\KSEFClient\Support\Utility;
use N1ebieski\KSEFClient\ValueObjects\Mode;
use N1ebieski\KSEFClient\DTOs\Requests\Sessions\Faktura;

$encryptionKey = EncryptionKeyFactory::makeRandom();

$client = (new ClientBuilder())
    ->withMode(Mode::Test)
    ->withIdentifier($_ENV['NIP_NUMBER'])
    ->withCertificatePath($_ENV['PATH_TO_CERTIFICATE'], $_ENV['CERTIFICATE_PASSPHRASE'])
    ->withEncryptionKey($encryptionKey)
    ->build();

$initResponse = $client->invoices()->exports()->init([
    'filters' => [
        'subjectType' => 'Subject1',
        'dateRange' => [
            'dateType' => 'Invoicing',
            'from' => new DateTimeImmutable('-1 day', new DateTimeZone('UTC')),
            'to' => new DateTimeImmutable('now', new DateTimeZone('UTC'))
        ],
    ]
])->object();

$statusResponse = Utility::retry(function () use ($client, $initResponse) {
    $statusResponse = $client->invoices()->exports()->status([
        'referenceNumber' => $initResponse->referenceNumber
    ])->object();

    if ($statusResponse->status->code === 200) {
        return $statusResponse;
    }

    if ($statusResponse->status->code >= 400) {
        throw new RuntimeException(
            $statusResponse->status->description,
            $statusResponse->status->code
        );
    }
});

$decryptDocumentHandler = new DecryptDocumentHandler();

$zipContents = '';

// Downloading...
foreach ($statusResponse->package->parts as $part) {
    $contents = file_get_contents($part->url);

    $contents = $decryptDocumentHandler->handle(new DecryptDocumentAction(
        document: $contents,
        encryptionKey: $encryptionKey
    ));

    $zipContents .= $contents;
}

file_put_contents(Utility::basePath("var/zip/invoices.zip"), $zipContents);

// Invoices can be deserialize to Faktura DTO

$faktury = [];

$zip = new ZipArchive();

$zip->open(Utility::basePath("var/zip/invoices.zip"));

for ($i = 0; $i < $zip->numFiles; $i++) {
    $filename = $zip->getNameIndex($i);

    if (str_ends_with($filename, '.xml')) {
        $content = $zip->getFromIndex($i);

        $faktury[] = Faktura::fromXml($content);
    }
}

$zip->close();
bash
composer