Skip to content


Switch branches/tags

Name already in use

A tag already exists with the provided branch name. Many Git commands accept both tag and branch names, so creating this branch may cause unexpected behavior. Are you sure you want to create this branch?


Failed to load latest commit information.
Latest commit message
Commit time

Fakturoid PHP lib

PHP library for Please see API for more documentation. New account just for testing API and using separate user (created via "Nastavení > Uživatelé a oprávnění") for production usage is highly recommended.



The recommended way to install is through Composer:

composer require fakturoid/fakturoid-php

Library requires PHP 5.3.0 (or later) and ext-curl and ext-json extensions.


require_once '/path/to/lib/Fakturoid.php';
$f = new Fakturoid\Client('..slug..', '', '..api_key..', 'PHPlib <>');

// create subject
$response = $f->createSubject(array('name' => 'Firma s.r.o.', 'email' => ''));
$subject  = $response->getBody();

// create invoice with lines
$lines    = array(array('name' => 'Big sale', 'quantity' => 1, 'unit_price' => 1000));
$response = $f->createInvoice(array('subject_id' => $subject->id, 'lines' => $lines));
$invoice  = $response->getBody();

// send created invoice
$f->fireInvoice($invoice->id, 'deliver');

// to mark invoice as paid
$f->fireInvoice($invoice->id, 'pay'); // or 'pay_proforma' for paying proforma and 'pay_partial_proforma' for partial proforma

// you can also take advantage of caching (via ETag and Last-Modified headers).
$response     = $f->getInvoice(123);
$status       = $response->getStatusCode();            // 200
$invoice      = $response->getBody();                  // stdClass Object
$etag         = $response->getHeader('ETag');          // 'W/"6e0d839fb2edb9eadcd9ecda2d227c96"'
$lastModified = $response->getHeader('Last-Modified'); // "Wed, 28 Mar 2018 03:11:14 GMT"

$response     = $f->getInvoice(123, array('If-None-Match' => $etag, 'If-Modified-Since' => $lastModified));
$status       = $response->getStatusCode();            // 304 Not Modified
$invoice      = $response->getBody();                  // null

Downloading an invoice PDF

$invoiceId = 123;
$response = $f->getInvoicePdf($invoiceId);
$data = $response->getBody();
file_put_contents("{$invoiceId}.pdf", $data);

If you call $f->getInvoicePdf() 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.

$invoiceId = 123;

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

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


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 = $f->getSubjects(array('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

To get all inventory items:


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

$f->getInventoryItems(array('sku' => 'SKU1234'));
$f->getInventoryItems(array('article_number' => 'IAN321'));

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

$f->searchInventoryItems(array('query' => 'Item name'));

To get all archived inventory items:


To get a single inventory item:


To create an inventory item:

$data = array(
    'name' => 'Item name',
    'sku' => 'SKU12345',
    'track_quantity' => true,
    'quantity' => 100,
    'native_purchase_price' => 500,
    'native_retail_price' => 1000

To update an inventory item:

$f->updateInventoryItem($inventoryItemId, array('name' => 'Another name'));

To archive an inventory item:


To unarchive an inventory item:


To delete an inventory item:


InventoryMove resource

To get get all inventory moves across all inventory items:


To get inventory moves for a single inventory item:

$f->getInventoryMoves(array('inventory_item_id' => $inventoryItemId));

To get a single inventory move:

$f->getInventoryMove($inventoryItemId, $inventoryMoveId);

To create a stock-in inventory move:

        '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:

        '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:

$f->updateInventoryMove($inventoryItemId, $inventoryMoveId, array('moved_on' => '2023-01-11'));

To delete an inventory move:

$f->deleteInventoryMove($inventoryItemId, $inventoryMoveId);

Handling errors

Library raises Fakturoid\Exception if server returns code 4xx or 5xx. You can get response code and response body by calling getCode() or getMessage().

try {
    $subject = $f->createSubject(array('name' => '', 'email' => ''));
} catch (Fakturoid\Exception $e) {
    $e->getCode(); // 422
    $e->getMessage(); // '{"errors":{"name":["je povinná položka","je příliš krátký/á/é (min. 2 znaků)"]}}'

Common problems

  • Ensure you have certificates for curl present - either globaly in php.ini or call curl_setopt($ch, CURLOPT_CAINFO, "/path/to/cacert.pem").
  • In case of problem please contact our invoicing robot on


  • 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 (php-xdebug package), it will hook itself into PHPUnit automatically.


$ brew install php
$ brew install composer
$ arch -arm64 pecl install xdebug # For Apple M1 chips
# Reload terminal
$ composer install


$ sudo aptitude install php php-curl php-xml php-mbstring php-xdebug composer
$ composer install


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

$ composer test
$ vendor/bin/phpunit
$ XDEBUG_MODE=coverage composer test # Generates coverage
$ XDEBUG_MODE=coverage vendor/bin/phpunit

Code-Style Check

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

$ composer lint
$ vendor/bin/phpcs --standard=PSR2 lib