tudorr89/fgo-php-api-sdk

PHP client for the FGO Invoicing/Billing API v7.0 — create invoices, manage articles, query nomenclatures, and more. Ships with Laravel auto-discovery.

Maintainers

Package info

github.com/tudorr89/fgo-php-api-sdk

pkg:composer/tudorr89/fgo-php-api-sdk

Statistics

Installs: 11

Dependents: 0

Suggesters: 0

Stars: 0

Open Issues: 0

v1.0.4 2026-05-16 17:26 UTC

This package is auto-updated.

Last update: 2026-05-16 17:27:04 UTC


README

PHP Version License Packagist

A fully-typed PHP client for the FGO Invoicing/Billing API v7.0.
Create and manage invoices, query nomenclatures, list articles, and more — with clean DTOs and Guzzle under the hood.

Requirements

  • PHP 8.1 or higher
  • Composer
  • A FGO account with an API user (Private Key)

Installation

composer require tudorr89/fgo-php-api-sdk

Quick Start

use FgoApi\Client;
use FgoApi\Enums\Environment;
use FgoApi\Types\AddressClient;
use FgoApi\Types\InvoiceLine;

$client = new Client(
    codUnic:     'YOUR_CUI',
    privateKey:  'YOUR_PRIVATE_KEY',
    platformUrl: 'https://your-app.com',
    environment: Environment::Test,
);

// Create an invoice
$invoice = $client->invoices()->create(
    series:      'BV',
    currency:    'RON',
    invoiceType: 'Factura',
    clientData:  new AddressClient(
        name:    'Ionescu Popescu',
        country: 'RO',
        county:  'Bucuresti',
        type:    'PF',
    ),
    lines: [
        new InvoiceLine(
            name:      'Servicii Consultanta',
            quantity:   2,
            unit:      'ORE',
            vatRate:   19,
            unitPrice: 150.00,
        ),
    ],
);

echo "Invoice: {$invoice->series}{$invoice->number}\n";
echo "PDF: {$invoice->pdfLink}\n";

Laravel

The package ships with auto-discovered service provider and facade — no manual registration needed.

Configure

php artisan vendor:publish --tag=fgo-config

Add to .env:

FGO_COD_UNIC=YOUR_CUI
FGO_PRIVATE_KEY=YOUR_PRIVATE_KEY
FGO_PLATFORM_URL=https://your-app.com
FGO_ENVIRONMENT=test          # or "production"
FGO_TIMEOUT=20

Use it

use FgoApi\Laravel\Fgo;
use FgoApi\Types\AddressClient;
use FgoApi\Types\InvoiceLine;

$invoice = Fgo::invoices()->create(
    series:      'BV',
    currency:    'RON',
    invoiceType: 'Factura',
    clientData:  new AddressClient(name: 'Acme SRL'),
    lines:       [new InvoiceLine(name: 'Service', quantity: 1, unit: 'BUC', vatRate: 19, unitPrice: 100)],
);

Or via DI:

use FgoApi\Client;

public function __construct(private readonly Client $fgo) {}

Multi-tenant / credentials from the database

When each tenant (or merchant, or user) has their own FGO credentials, point the package at a resolver instead of reading from .env. Implement FgoApi\Laravel\Contracts\CredentialsResolver:

namespace App\Fgo;

use App\Models\Tenant;
use FgoApi\Laravel\Contracts\CredentialsResolver;

class TenantCredentialsResolver implements CredentialsResolver
{
    public function resolve(?string $key = null): array
    {
        $tenant = $key
            ? Tenant::findOrFail($key)
            : Tenant::current();

        return [
            'cod_unic'     => $tenant->fgo_cod_unic,
            'private_key'  => decrypt($tenant->fgo_private_key),
            'platform_url' => $tenant->platform_url,
            'environment'  => $tenant->fgo_environment, // "test" or "production"
        ];
    }
}

Register it in config/fgo.php:

'resolver' => \App\Fgo\TenantCredentialsResolver::class,

Then:

use FgoApi\Laravel\Fgo;

// Current tenant — resolver is called with null
Fgo::invoices()->create(...);

// Specific tenant — resolver is called with the key, result cached for the request
Fgo::for($tenantId)->invoices()->create(...);

// Ad-hoc credentials (e.g. testing, one-off jobs)
Fgo::make([
    'cod_unic'     => '...',
    'private_key'  => '...',
    'platform_url' => 'https://my-app.test',
    'environment'  => 'test',
])->invoices()->getStatus('001', 'BV');

// After rotating credentials
Fgo::forget($tenantId);

A closure is also accepted if you don't want a dedicated class:

// in a service provider
config(['fgo.resolver' => fn (?string $key) => Tenant::resolve($key)->fgoConfig()]);

Authentication

All requests are signed with an SHA-1 hash. The Hash helper provides the correct calculation for each endpoint category:

use FgoApi\Hash;

// Invoice creation — includes client name
Hash::forInvoiceCreate('CUI', 'PRIVATE_KEY', 'Client Name');

// Invoice operations (print, cancel, etc.) — includes invoice number
Hash::forInvoiceOperation('CUI', 'PRIVATE_KEY', '001');

// Articles, nomenclatures, warehouses — no extra data
Hash::forArticle('CUI', 'PRIVATE_KEY');

The Client handles hashing automatically — you never need to call these directly.

API Reference

Invoices

Method Endpoint Description
invoices()->create(...) POST /factura/emitere Create and emit a new invoice
invoices()->print($num, $serie) POST /factura/print Generate PDF download link
invoices()->getStatus($num, $serie) POST /factura/getstatus Get invoice value and paid amount
invoices()->cancel($num, $serie) POST /factura/anulare Cancel (keeps in history)
invoices()->delete($num, $serie) POST /factura/stergere Permanently delete
invoices()->reverse($num, $serie) POST /factura/stornare Reverse / credit note
invoices()->addPayment(...) POST /factura/incasare Record a payment (Premium+)
invoices()->deletePayment($num, $serie) POST /factura/stergereincasare Delete a payment
invoices()->addTrackingNumber(...) POST /factura/awb Attach courier AWB
invoices()->listAssociated($num, $serie) POST /factura/listfacturiasociate List linked invoices (Enterprise)
// Full create example
$result = $client->invoices()->create(
    series:          'BV',
    currency:        'RON',
    invoiceType:     'Factura',
    clientData:      new AddressClient(
        name:       'SC Example SRL',
        fiscalCode: 'RO12345678',
        email:      'contact@example.com',
        phone:      '0712345678',
        country:    'RO',
        county:     'Cluj',
        locality:   'Cluj-Napoca',
        address:    'Str. Principala, Nr. 10',
        type:       'PJ',
    ),
    lines: [
        new InvoiceLine(
            name:        'Dezvoltare Software',
            quantity:    1,
            unit:        'BUC',
            vatRate:     19,
            unitPrice:   5000.00,
            description: 'Modul facturare — luna aprilie',
        ),
    ],
    number:          null,
    issueDate:       date('Y-m-d'),
    dueDate:         null,
    checkDuplicate:  false,
    vatOnCollection: false,
);

// $result->number, $result->series, $result->pdfLink, $result->paymentLink, $result->stockInfo[]

Nomenclatures

Method Returns
nomenclatures()->countries() All countries
nomenclatures()->counties() All counties
nomenclatures()->vatRates() VAT rates
nomenclatures()->banks() Banks
nomenclatures()->paymentTypes() Payment types
nomenclatures()->invoiceTypes() Invoice types
nomenclatures()->clientTypes() Client types (PF/PJ)
nomenclatures()->localities('Bucuresti') Localities by county code
$types = $client->nomenclatures()->invoiceTypes();
// [ { name: "Normal", value: "Factura" }, { name: "Simplified", value: "FacturaSimplificata" } ]

Articles

Method Description
articles()->list($page, $perPage) Paginated article list (Enterprise)
articles()->get($code) Single article by account code
articles()->getList(array $codes) Multiple articles, max 30 — deprecated
articles()->modifiedArticles($hoursBack, $hoursTo) Articles modified in time window (Enterprise)
$result = $client->articles()->list(page: 1, perPage: 50);
// $result->total, $result->articles[] — each Article has name, unitPrice, stock, barcode, etc.

Warehouses

$warehouses = $client->warehouses()->list();
// { code: "WH001", name: "Main Warehouse" }

Environments

use FgoApi\Enums\Environment;

// Test (UAT)
new Client(..., environment: Environment::Test);

// Production
new Client(..., environment: Environment::Production);

// Custom URL
new Client(..., environment: 'https://custom-fgo.example.com/v1');

Exception Handling

All exceptions extend FgoApi\Exceptions\FgoApiException:

Exception Trigger
FgoApiException Generic API error (non-success response)
AuthenticationException HTTP 401 — invalid credentials
RateLimitException HTTP 429 — rate limit hit
NotFoundException HTTP 404 — resource not found
HttpException Other HTTP errors (includes status code + body)
ValidationException Validation errors
try {
    $invoice = $client->invoices()->create(...);
} catch (ValidationException $e) {
    // 400 / `Errors` map from API
    print_r($e->getErrors());
} catch (AuthenticationException $e) {
    // 401 / 403 — wrong CUI or private key
} catch (RateLimitException $e) {
    sleep(max(1, $e->getRetryAfter()));
    // ...retry
} catch (FgoApiException $e) {
    // All other API errors
}

Rate Limits

The API enforces per-endpoint rate limits. The client does not automatically retry — implement your own retry logic as needed:

Endpoint Limit
Invoice create / payment 1 req/sec, 15s timeout
Articles 1 req/5 sec
Standard endpoints No explicit limit

Development

git clone https://github.com/tudorr89/fgo-php-api-sdk
cd fgo-php-api-sdk
composer install

# Static analysis
composer analyse

# Run tests
composer test

License

MIT. See LICENSE.

Resources