PHPackages                             fakturoid/fakturoid-php - PHPackages - PHPackages  [Skip to content](#main-content)[PHPackages](/)[Directory](/)[Categories](/categories)[Trending](/trending)[Leaderboard](/leaderboard)[Changelog](/changelog)[Analyze](/analyze)[Collections](/collections)[Log in](/login)[Sign up](/register)

1. [Directory](/)
2. /
3. [API Development](/categories/api)
4. /
5. fakturoid/fakturoid-php

ActiveLibrary[API Development](/categories/api)

fakturoid/fakturoid-php
=======================

Fakturoid PHP library

v4.0.0(1y ago)36374.6k—2.3%21[1 PRs](https://github.com/fakturoid/fakturoid-php/pulls)4MITPHPPHP &gt;=8.2CI passing

Since Dec 8Pushed 3mo ago16 watchersCompare

[ Source](https://github.com/fakturoid/fakturoid-php)[ Packagist](https://packagist.org/packages/fakturoid/fakturoid-php)[ Docs](https://www.fakturoid.cz/api)[ RSS](/packages/fakturoid-fakturoid-php/feed)WikiDiscussions main Synced 1mo ago

READMEChangelogDependencies (7)Versions (18)Used By (4)

Fakturoid PHP lib
=================

[](#fakturoid-php-lib)

[![Tests](https://github.com/fakturoid/fakturoid-php/actions/workflows/main.yml/badge.svg)](https://github.com/fakturoid/fakturoid-php/actions/workflows/main.yml/badge.svg)[![](https://camo.githubusercontent.com/b3762d7d4db295b7c86e126994cbd677df945820d58a977e59f3f949ef78460a/68747470733a2f2f62616467656e2e6e65742f6769746875622f636865636b732f66616b7475726f69642f66616b7475726f69642d7068702f6d6173746572)](https://github.com/fakturoid/fakturoid-php/actions)[![](https://camo.githubusercontent.com/2db5a4f53b0291be2602f417d980af0742d35057500474677fd158fdfe3f490f/68747470733a2f2f62616467656e2e6e65742f7061636b61676973742f646d2f66616b7475726f69642f66616b7475726f69642d706870)](https://packagist.org/packages/fakturoid/fakturoid-php)[![](https://camo.githubusercontent.com/7c1e42aa7c002178db89cfee012078bdf08f6ffce7a44311fce4571da62435f8/68747470733a2f2f62616467656e2e6e65742f7061636b61676973742f762f66616b7475726f69642f66616b7475726f69642d706870)](https://packagist.org/packages/fakturoid/fakturoid-php)[![](https://camo.githubusercontent.com/3cdaffdf3c2116e63f6f26185448f2c76a6cd93877aae0ec914d1266839acf67/68747470733a2f2f62616467656e2e6e65742f7061636b61676973742f7068702f66616b7475726f69642f66616b7475726f69642d706870)](https://packagist.org/packages/fakturoid/fakturoid-php)[![](https://camo.githubusercontent.com/11d96beb23cd569c13f4b9a82522dbc253c8e7c5f596113a6e3b76557973e8d5/68747470733a2f2f62616467656e2e6e65742f6769746875622f6c6963656e73652f66616b7475726f69642f66616b7475726f69642d706870)](https://github.com/fakturoid/fakturoid-php)

PHP library for [Fakturoid.cz](https://www.fakturoid.cz/). Please see [API](https://www.fakturoid.cz/api/v3) for more documentation. New account just for testing API and using separate user (created via "Settings &gt; User account") for production usage is highly recommended.

> **⚠️ Upgrading?** See [UPGRADE.md](UPGRADE.md) for breaking changes and migration guide.

Content
-------

[](#content)

- [Versions](#versions)
- [Installation](#installation)
- [Authorization by OAuth 2.0](#authorization-by-oauth-20)

    - [Authorization Code Flow](#authorization-code-flow)
    - [Client Credentials Flow](#client-credentials-flow)
- [Usage](#usage)

    - [Set credentials to the Fakturoid manager](#set-credentials-to-the-fakturoid-manager)
    - [Switch account](#switch-account)
    - [Basic usage](#basic-usage)
    - [Downloading an invoice PDF](#downloading-an-invoice-pdf)
    - [Using `custom_id`](#using-custom_id)
    - [InventoryItem resource](#inventoryitem-resource)
    - [Recurring Generators](#recurring-generators)
- [Rate Limiting](#rate-limiting)
- [Handling errors](#handling-errors)

    - [Common problems](#common-problems)
- [Development](#development)

    - [Docker](#docker)
    - [Testing](#testing)
    - [Code-Style Check](#code-style-check)
    - [Check all requires for PR](#check-all-requires-for-pr)

Versions
--------

[](#versions)

Lib. versionFakturoid APIPHP`5.x``v3``>=8.2``4.x``v3``>=8.2``3.x``v3``>=8.2``2.x``v3``>=8.1``>1.4.x``v3``>=7.4 =5.3.0`Installation
------------

[](#installation)

The recommended way to install is through Composer:

```
composer require fakturoid/fakturoid-php

```

Library requires PHP 8.2 (or later) and `ext-json`, `nyholm/psr7` and `psr/http-client` extensions.

User agent and HTTP client
--------------------------

[](#user-agent-and-http-client)

You need to create your own client that implements [`Psr\Http\Client\ClientInterface`](https://www.php-fig.org/psr/psr-18/) or you can use `symfony/http-client`, `guzzlehttp/guzzle` or [other](https://packagist.org/providers/psr/http-client-implementation). And you also need to set a default header value for this client, where you need to [specify User-Agent](https://www.fakturoid.cz/api/v3#identification).

### Creating a client using Guzzle

[](#creating-a-client-using-guzzle)

```
new \GuzzleHttp\Client(['headers' => ['User-Agent' => 'Bar']])
```

### Create a client using Symfony

[](#create-a-client-using-symfony)

In Symfony app you can define in [configuration](https://symfony.com/doc/current/http_client.html#headers)

```
(new \Symfony\Component\HttpClient\Psr18Client())->withOptions([['headers' => ['User-Agent' => 'Bar']]))
```

Authorization by OAuth 2.0
--------------------------

[](#authorization-by-oauth-20)

### Authorization Code Flow

[](#authorization-code-flow)

Authorization using OAuth takes place in several steps. We use data obtained from the developer portal as client ID and client secret (*Settings → Connect other apps → OAuth 2 for app developers*).

First, we offer the user a URL address where he enters his login information. We obtain this using the following method:

```
$fManager = new \Fakturoid\FakturoidManager(
    \Psr\Http\Client\ClientInterface, // see User agent and HTTP client above
    '{fakturoid-client-id}',
    '{fakturoid-client-secret}',
    null,
    '{your-redirect-uri}'
);
echo 'Link';
```

After entering the login data, the user is redirected to the specified redirect URI and with the code with which we obtain his credentials. We process the code as follows:

```
$fManager->requestCredentials($_GET['code']);
```

Credentials are now established in the object instance and we can send queries to the Fakturoid api. Credentials can be obtained in 2 ways. Obtaining credentials directly from the object:

```
$credentials = $fManager->getCredentials();
echo $credentials->toJson();
```

### Client Credentials Flow

[](#client-credentials-flow)

```
$fManager = new \Fakturoid\FakturoidManager(
    \Psr\Http\Client\ClientInterface, // see User agent and HTTP client above
    '{fakturoid-client-id}',
    '{fakturoid-client-secret}'
);
$fManager->authClientCredentials();
```

Processing credentials using the credentials callback:
------------------------------------------------------

[](#processing-credentials-using-the-credentials-callback)

The way callback works is that the library calls the callback function whenever the credentials are changed. This is useful because the token is automatically refreshed after its expiration.

```
$fManager->setCredentialsCallback(new class implements \Fakturoid\Auth\CredentialCallback {
    public function __invoke(?\Fakturoid\Auth\Credentials $credentials = null): void
    {
        // Save credentials to database or another storage
    }
});
```

Usage
-----

[](#usage)

### Set credentials to the Fakturoid manager

[](#set-credentials-to-the-fakturoid-manager)

If you run a multi-tenant application or an application that processes documents in parallel, you need to set Credentials correctly. Each time a new access token is obtained, the previous one is invalidated. For these needs there is `AuthProvider::setCredentials()` and also `CredentialCallback`.

```
$fManager = new \Fakturoid\FakturoidManager(
    \Psr\Http\Client\ClientInterface, // see User agent and HTTP client above
    '{fakturoid-client-id}',
    '{fakturoid-client-secret}'
);
// restore credentials from storage
$credentials = new \Fakturoid\Auth\Credentials(
    'refreshToken',
    'accessToken',
    (new DateTimeImmutable())->modify('-2 minutes'),
    \Fakturoid\Enum\AuthTypeEnum::AUTHORIZATION_CODE_FLOW // or \Fakturoid\Enum\AuthTypeEnum:CLIENT_CREDENTIALS_CODE_FLOW
);

$fManager->getAuthProvider()->setCredentials($credentials);
$fManager->setCredentialsCallback(new class implements \Fakturoid\Auth\CredentialCallback {
    public function __invoke(?\Fakturoid\Auth\Credentials $credentials = null): void
    {
        // Save credentials to database or another storage
    }
});
```

### Switch account

[](#switch-account)

```
$fManager = new \Fakturoid\FakturoidManager(
    \Psr\Http\Client\ClientInterface, // see User agent and HTTP client above
    '{fakturoid-client-id}',
    '{fakturoid-client-secret}',
    '{fakturoid-account-slug}',
);
$fManager->authClientCredentials();
$fManager->getBankAccountsProvider()->list();

// switch account and company
$fManager->setAccountSlug('{fakturoid-account-slug-another}');
$fManager->getBankAccountsProvider()->list();
```

### Basic usage

[](#basic-usage)

```
require __DIR__ . '/vendor/autoload.php';
$fManager = new \Fakturoid\FakturoidManager(
    \Psr\Http\Client\ClientInterface, // see User agent and HTTP client above
    '{fakturoid-client-id}',
    '{fakturoid-client-secret}'
);
$fManager->authClientCredentials();

// get current user
$user = $fManager->getUsersProvider()->getCurrentUser();
$fManager->setAccountSlug($user->getBody()->accounts[0]->slug);
// or you can set account slug manually
$fManager->setAccountSlug('{fakturoid-account-slug}');

// create subject
$response = $fManager->getSubjectsProvider()->create(['name' => 'Firma s.r.o.', 'email' => 'aloha@pokus.cz']);
$subject  = $response->getBody();

// create invoice with lines
$lines    = [['name' => 'Big sale', 'quantity' => 1, 'unit_price' => 1000]];
$response = $fManager->getInvoicesProvider()->create(['subject_id' => $subject->id, 'lines' => $lines]);
$invoice  = $response->getBody();

// send by mail
$fManager->getInvoicesProvider()->createMessage($invoice->id, ['email' => 'aloha@pokus.cz']);

// to mark invoice as paid and send thank you email
$fManager->getInvoicesProvider()->createPayment($invoice->id, ['paid_on' => (new \DateTime())->format('Y-m-d'), 'send_thank_you_email' => true]);

// lock invoice (other fire actions are described in the API documentation)
$fManager->getInvoicesProvider()->fireAction($invoice->id, 'lock');
```

### Downloading an invoice PDF

[](#downloading-an-invoice-pdf)

```
$invoiceId = 123;
$response = $fManager->getInvoicesProvider()->getPdf($invoiceId);
$data = $response->getBody();
file_put_contents("{$invoiceId}.pdf", $data);
```

If you call `$fManager->getInvoicesProvider()->getPdf()` right after creating an invoice, you'll get a status code `204` (`No Content`) with empty body, this means the invoice PDF hasn't yet been generated and you should try again a second or two later.

More info in [API docs](https://www.fakturoid.cz/api/v3/invoices#download-invoice-pdf).

```
$invoiceId = 123;

// This is just an example, you may want to do this in a background job and be more defensive.
while (true) {
    $response = $fManager->getInvoicesProvider()->getPdf($invoiceId);

    if ($response->getStatusCode() == 200) {
        $data = $response->getBody();
        file_put_contents("{$invoiceId}.pdf", $data);
        break;
    }

    sleep(1);
}
```

### Using `custom_id`

[](#using-custom_id)

You can use `custom_id` attribute to store your application record ID into our record. Invoices and subjects can be filtered to find a particular record:

```
$response = $fManager->getSubjectsProvider()->list(['custom_id' => '10']);
$subjects = $response->getBody();
$subject  = null;

if (count($subjects) > 0) {
    $subject = $subjects[0];
}
```

As for subjects, Fakturoid won't let you create two records with the same `custom_id` so you don't have to worry about multiple results. Also note that the field always returns a string.

### InventoryItem resource

[](#inventoryitem-resource)

To get all inventory items:

```
$fManager->getInventoryItemsProvider()->list();
```

To filter inventory items by certain SKU code or article number:

```
$fManager->getInventoryItemsProvider()->list(['sku' => 'SKU1234']);
$fManager->getInventoryItemsProvider()->list(['article_number' => 'IAN321']);
```

To search inventory items (searches in `name`, `article_number` and `sku`):

```
$fManager->getInventoryItemsProvider()->listArchived(['query' => 'Item name']);
```

To get all archived inventory items:

```
$fManager->getInventoryItemsProvider()->listArchived();
```

To get a single inventory item:

```
$fManager->getInventoryItemsProvider()->get($inventoryItemId);
```

To create an inventory item:

```
$data = [
    'name' => 'Item name',
    'sku' => 'SKU12345',
    'track_quantity' => true,
    'quantity' => 100,
    'native_purchase_price' => 500,
    'native_retail_price' => 1000
];
$fManager->getInventoryItemsProvider()->create($data)
```

To update an inventory item:

```
$fManager->getInventoryItemsProvider()->update($inventoryItemId, ['name' => 'Another name']);
```

To archive an inventory item:

```
$fManager->getInventoryItemsProvider()->archive($inventoryItemId);
```

To unarchive an inventory item:

```
$fManager->getInventoryItemsProvider()->unArchive($inventoryItemId);
```

To delete an inventory item:

```
$fManager->getInventoryItemsProvider()->delete($inventoryItemId);
```

InventoryMove resource
----------------------

[](#inventorymove-resource)

To get get all inventory moves across all inventory items:

```
$fManager->getInventoryMovesProvider()->list()
```

To get inventory moves for a single inventory item:

```
$fManager->getInventoryMovesProvider()->list(['inventory_item_id' => $inventoryItemId]);
```

To get a single inventory move:

```
$fManager->getInventoryMovesProvider()->get($inventoryItemId, $inventoryMoveId);
```

To create a stock-in inventory move:

```
$fManager->getInventoryMovesProvider()->create(
    $inventoryItemId,
    [
        'direction' => 'in',
        'moved_on' => '2023-01-12',
        'quantity_change' => 5,
        'purchase_price' => '249.99',
        'purchase_currency' => 'CZK',
        'private_note' => 'Bought with discount'
    ]
)
```

To create a stock-out inventory move:

```
$fManager->getInventoryMovesProvider()->create(
    $inventoryItemId,
    [
        'direction' => 'out',
        'moved_on' => '2023-01-12',
        'quantity_change' => '1.5',
        'retail_price' => 50,
        'retail_currency' => 'EUR',
        'native_retail_price' => '1250'
    ]
);
```

To update an inventory move:

```
$fManager->getInventoryMovesProvider()->update($inventoryItemId, $inventoryMoveId, ['moved_on' => '2023-01-11']);
```

To delete an inventory move:

```
$fManager->getInventoryMovesProvider()->update($inventoryItemId, $inventoryMoveId);
```

### Recurring Generators

[](#recurring-generators)

To pause a recurring generator:

```
$fManager->getRecurringGeneratorsProvider()->pause($generatorId);
```

To activate a paused recurring generator:

```
$fManager->getRecurringGeneratorsProvider()->activate($generatorId);
```

To activate with a specific next occurrence date:

```
$fManager->getRecurringGeneratorsProvider()->activate($generatorId, [
    'next_occurrence_on' => '2025-02-15'
]);
```

Rate Limiting
-------------

[](#rate-limiting)

Fakturoid implements rate limiting based on RFC Draft. The library provides methods to check rate limit status from the response object:

```
try {
    $response = $fManager->getInvoicesProvider()->list();

    // Get maximum number of requests allowed in the time window
    $quota = $response->getRateLimitQuota(); // e.g., 400

    // Get time window in seconds
    $window = $response->getRateLimitWindow(); // e.g., 60

    // Get remaining number of requests
    $remaining = $response->getRateLimitRemaining(); // e.g., 398

    // Get remaining time in seconds until the rate limit resets
    $resetTime = $response->getRateLimitReset(); // e.g., 55

} catch (\Fakturoid\Exception\ClientErrorException $exception) {
    // Check if rate limit was exceeded (status code 429)
    if ($exception->isRateLimitExceeded()) {
        // Access rate limit info from the exception's response
        $response = $exception->getResponse();
        $resetTime = $response->getRateLimitReset();

        // Wait until the rate limit resets and retry
        sleep($resetTime);
        // retry the request...
    }
}
```

When the rate limit is exceeded, the server responds with status code `429 Too Many Requests` and throws a `ClientErrorException`. You can check if the exception is due to rate limiting using `isRateLimitExceeded()` method and get rate limit details from the response object.

Handling errors
---------------

[](#handling-errors)

Library raises `Fakturoid\Exception\ClientErrorException` for `4xx` and `Fakturoid\Exception\ServerErrorException` for `5xx` status. You can get response code and response body by calling `getCode()` or `getResponse()->getBody()` or `getResponse()->getBody()` or `getResponse()->getBody()`.

```
try {
    $response = $fManager->getSubjectsProvider()->create(['name' => '', 'email' => 'aloha@pokus.cz']);
    $subject  = $response->getBody();
} catch (\Fakturoid\Exception\ClientErrorException $e) {
    $e->getCode(); // 422
    $e->getMessage(); // Unprocessable entity
    $e->getResponse()->getBody(); // '{"errors":{"name":["je povinná položka","je příliš krátký/á/é (min. 2 znaků)"]}}'
} catch (\Fakturoid\Exception\ServerErrorException $e) {
    $e->getCode(); // 503
    $e->getMessage(); // Fakturoid is in read only state
}
```

### Common problems

[](#common-problems)

- In case of problem please contact our invoicing robot on .

Development
-----------

[](#development)

- To run tests, PHPUnit requires `ext-dom` extension (typically a `php-xml` package on Debian) and `ext-mbstring` extension (`php-mbstring` package).
- If you wish to generate code coverage (and have more intelligent stack traces), you will need [Xdebug](https://xdebug.org/)(`php-xdebug` package), it will hook itself into PHPUnit automatically.

### Docker

[](#docker)

```
$ docker-compose up -d
$ docker-compose exec php composer install
$ docker-compose exec php bash
```

### Testing

[](#testing)

Both commands do the same but the second version is a bit faster.

```
$ docker-compose exec php composer test:phpunit
$ docker-compose exec php composer coverage:phpunit
# or locally
$ composer test:phpunit
$ composer coverage:phpunit
```

### Code-Style Check

[](#code-style-check)

Both commands do the same but the second version seems to have a more intelligent output.

```
$ docker-compose exec php composer check:cs
# or locally
$ composer check:cs
```

### Check all requires for PR

[](#check-all-requires-for-pr)

```
$ docker-compose exec php composer check:all
# or locally
$ composer check:all
```

Or you can fix CS and Rector issues automatically:

```
$ docker-compose exec php composer fix:all
# or locally
$ composer fix:all
```

###  Health Score

61

—

FairBetter than 99% of packages

Maintenance66

Regular maintenance activity

Popularity49

Moderate usage in the ecosystem

Community31

Small or concentrated contributor base

Maturity84

Battle-tested with a long release history

 Bus Factor2

2 contributors hold 50%+ of commits

How is this calculated?**Maintenance (25%)** — Last commit recency, latest release date, and issue-to-star ratio. Uses a 2-year decay window.

**Popularity (30%)** — Total and monthly downloads, GitHub stars, and forks. Logarithmic scaling prevents top-heavy scores.

**Community (15%)** — Contributors, dependents, forks, watchers, and maintainers. Measures real ecosystem engagement.

**Maturity (30%)** — Project age, version count, PHP version support, and release stability.

###  Release Activity

Cadence

Every ~196 days

Recently: every ~87 days

Total

15

Last Release

329d ago

Major Versions

v0.1.0 → v1.0.02018-04-03

v1.3.0 → v2.0.02024-02-06

v2.1.0 → v3.0.02024-10-29

v3.0.0 → v4.0.02025-03-18

PHP version history (5 changes)v0.1.0PHP &gt;=5.2.0

v1.0.0PHP &gt;=5.3.0

v2.0.0PHP &gt;=8.1

v3.0.0PHP &gt;=8.2

v1.4.0PHP &gt;=7.4 &lt;8.2

### Community

Maintainers

![](https://www.gravatar.com/avatar/916e7a309d6a2f2dbd91bf5359e0c185432ac080dac143af9595ecf93410c76a?d=identicon)[daeltar](/maintainers/daeltar)

![](https://www.gravatar.com/avatar/a8f176a7d78ee888eff682bebe21b9c1b0304f11c667ca5fd784d1c1b63ab63d?d=identicon)[ollie](/maintainers/ollie)

---

Top Contributors

[![ollie](https://avatars.githubusercontent.com/u/53026?v=4)](https://github.com/ollie "ollie (53 commits)")[![lukaskonarovsky](https://avatars.githubusercontent.com/u/9624?v=4)](https://github.com/lukaskonarovsky "lukaskonarovsky (32 commits)")[![tomas-kulhanek](https://avatars.githubusercontent.com/u/7447745?v=4)](https://github.com/tomas-kulhanek "tomas-kulhanek (21 commits)")[![goodhoko](https://avatars.githubusercontent.com/u/16712262?v=4)](https://github.com/goodhoko "goodhoko (3 commits)")[![edariedl](https://avatars.githubusercontent.com/u/163762?v=4)](https://github.com/edariedl "edariedl (2 commits)")[![grogy](https://avatars.githubusercontent.com/u/1322983?v=4)](https://github.com/grogy "grogy (2 commits)")[![vikijel](https://avatars.githubusercontent.com/u/2683048?v=4)](https://github.com/vikijel "vikijel (1 commits)")[![radimvaculik](https://avatars.githubusercontent.com/u/461164?v=4)](https://github.com/radimvaculik "radimvaculik (1 commits)")[![RiKap](https://avatars.githubusercontent.com/u/6736715?v=4)](https://github.com/RiKap "RiKap (1 commits)")[![TakeruDavis](https://avatars.githubusercontent.com/u/1822248?v=4)](https://github.com/TakeruDavis "TakeruDavis (1 commits)")[![arthurwozniak](https://avatars.githubusercontent.com/u/1984961?v=4)](https://github.com/arthurwozniak "arthurwozniak (1 commits)")

---

Tags

api-clientapiinvoicefakturoid

###  Code Quality

TestsPHPUnit

Static AnalysisPHPStan, Rector

Code StylePHP\_CodeSniffer

Type Coverage Yes

### Embed Badge

![Health badge](/badges/fakturoid-fakturoid-php/health.svg)

```
[![Health](https://phpackages.com/badges/fakturoid-fakturoid-php/health.svg)](https://phpackages.com/packages/fakturoid-fakturoid-php)
```

###  Alternatives

[mollie/mollie-api-php

Mollie API client library for PHP. Mollie is a European Payment Service provider and offers international payment methods such as Mastercard, VISA, American Express and PayPal, and local payment methods such as iDEAL, Bancontact, SOFORT Banking, SEPA direct debit, Belfius Direct Net, KBC Payment Button and various gift cards such as Podiumcadeaukaart and fashioncheque.

60014.4M62](/packages/mollie-mollie-api-php)[theodo-group/llphant

LLPhant is a library to help you build Generative AI applications.

1.5k311.5k5](/packages/theodo-group-llphant)[wordpress/php-ai-client

A provider agnostic PHP AI client SDK to communicate with any generative AI models of various capabilities using a uniform API.

26236.6k14](/packages/wordpress-php-ai-client)[openai-php/symfony

Symfony Bundle for OpenAI

215715.5k3](/packages/openai-php-symfony)[deepseek-php/deepseek-php-client

deepseek PHP client is a robust and community-driven PHP client library for seamless integration with the Deepseek API, offering efficient access to advanced AI and data processing capabilities.

47073.9k5](/packages/deepseek-php-deepseek-php-client)[mozex/anthropic-php

Anthropic PHP is a supercharged community-maintained PHP API client that allows you to interact with Anthropic API.

46365.1k13](/packages/mozex-anthropic-php)

PHPackages © 2026

[Directory](/)[Categories](/categories)[Trending](/trending)[Changelog](/changelog)[Analyze](/analyze)
