datomatic/laravel-fatture-in-cloud
A Laravel integration for the Fatture in Cloud API, making it easy to manage invoices, clients, products, and related business data directly from your PHP application with a clean, fluent interface.
Install and configure
composer require datomatic/laravel-fatture-in-cloud
php artisan vendor:publish --tag="fatture-in-cloud-config"
Add credentials to .env:
FATTURE_IN_CLOUD_ACCESS_TOKEN=your-api-token
FATTURE_IN_CLOUD_COMPANY_ID=123456
Where to get the token. Log into Fatture in Cloud → Settings → API and generate a personal access token, or complete the OAuth2 flow if you're building a multi-tenant integration. The token is a bearer token; the package puts it on every request.
Look first at: the package README (it's the only real documentation — the repo is small, 10 stars, single maintainer), then config/fatture-in-cloud.php after publishing, then the src/ tree to see which API resources are actually wrapped.
First use case. The canonical "hello world" is: list the clients of your company, then create an invoice for an existing client. Roughly:
use Datomatic\FattureInCloud\Facades\FattureInCloud;
$clients = FattureInCloud::clients()->list($companyId);
$invoice = FattureInCloud::invoices()->create($companyId, [
'data' => [
'type' => 'invoice',
'entity' => ['id' => $clientId],
'date' => now()->toDateString(),
'number' => '1/2026',
'items_list' => [ /* ... */ ],
],
]);
If that round-trips, the access token, company scope, and JSON serialization are all correct — that's 90% of the integration risk gone.
Facade-first, DI-friendly. The package exposes a FattureInCloud facade which proxies resource objects (clients, invoices, products, suppliers, taxes, user, companies, etc.). Prefer constructor-injecting the underlying manager class rather than calling the facade statically, so you can swap it in tests:
public function __construct(private FattureInCloud $fic) {}
public function pushInvoice(Invoice $invoice): array
{
return $this->fic->invoices()->create($this->companyId(), $this->toPayload($invoice));
}
Wrap it in your own service. Don't scatter FattureInCloud::… calls through controllers and jobs. Put one InvoiceSyncService / ClientRepository layer on top that:
data envelope,Y-m-d,The API's payloads are verbose and Italian-fiscal-specific; you will regret letting that shape leak into your app.
Persist remote IDs. Every customer, product, and invoice you push needs the remote id stored locally. Standard pattern: fatture_in_cloud_id nullable unique column on clients, invoices, products. On create → store returned id; on update → PUT using that id; on delete → null it out. This is the single most important schema decision.
Background the writes. Fatture in Cloud is a remote HTTP service with quotas. Any user action that writes an invoice should enqueue a job:
dispatch(new PushInvoiceToFattureInCloud($invoice->id))->onQueue('fic');
Retry with $tries = 3 and a backoff; treat 4xx as non-retryable (validation — your payload is wrong) and 5xx/429 as retryable.
Sync down via webhooks + polling. For read direction, don't hammer the list endpoints on every page load. Either:
php artisan fic:sync command that pulls changes since a stored updated_at cursor.Multi-company. If you serve several companies (agency / accountant scenario), don't rely on the configured default company_id — pass it explicitly on every call and key your own models by it. The config default is a convenience for single-tenant apps.
Testing. The package has no fake/in-memory implementation as far as I'm aware, so wrap it behind your own interface and bind a stub in tests. For integration tests against the real HTTP layer, mock the underlying client (Guzzle/HTTP client depending on how the package wires the SDK) rather than trying to intercept at the facade level. Never run the suite against a live token.
Company ID is required almost everywhere. Most resource methods take the company id as the first argument. Forgetting it, or letting the config default silently apply in a multi-tenant context, is the #1 source of "wrong data returned" bugs.
Dates are Y-m-d strings, not Carbon. Serialize explicitly (->format('Y-m-d')). Passing a Carbon instance usually "works" via __toString but can produce a datetime string the API rejects.
Italian fiscal validation is strict and server-side. codice_fiscale vs partita_iva, codice_destinatario (7 chars, or 0000000), PEC for PA customers, tipo_documento / natura codes — these are validated by Fatture in Cloud, not by the package. Validate client-side where you can to avoid a round-trip just to learn a code is invalid. Budget real time for the e-invoice XML specifics; consult the official API docs, not the package source.
Numbers and amounts. The API mixes integers, floats-as-strings, and VAT percentages. Don't (float) round-trip amounts through PHP arithmetic — you'll introduce cent-level drift. Keep monetary values as strings end-to-end.
Pagination. List endpoints are paginated. A "give me all clients" helper probably doesn't exist; loop on page / per_page yourself, or accept that you should be filtering server-side. Watch out for default page sizes.
Rate limits are real. Fatture in Cloud enforces per-minute and daily quotas. A test suite or a bulk import will hit them fast. Add a throttle / RateLimiter around the sync service; on 429 respect Retry-After.
Error handling. The package wraps the official SDK, which throws typed exceptions on non-2xx. Catch the base exception class, inspect status code, and log the response body — Fatture in Cloud returns useful validation messages in the payload that get swallowed if you only log the exception message.
Access tokens. Personal API tokens don't expire but are revocable; OAuth2 tokens expire (~1h) and need refresh. If you're doing OAuth, the refresh flow is on you — the package is a thin wrapper, not a token manager. Store access_token, refresh_token, and expires_at per company and refresh in a middleware or service before calling.
Release cadence and bus factor. Last release tag is 2026-03-17, MIT, ~10 stars, single maintainer. That's fine — it's a thin wrapper — but pin the version, and be prepared to either fork or reach directly for the official fattureincloud/fatture-in-cloud-php-sdk if the package falls behind a breaking API change. Anything the facade doesn't expose, you can usually get at through the underlying SDK client; check src/ for how to reach it.
Extension points. The config file is the main knob (token, company id, possibly base URL / HTTP options). If you need custom headers, timeout, or a different HTTP client, that usually lives in the underlying SDK's configuration — the Laravel package likely exposes it via config or a custom binding in a service provider. Register your own binding in AppServiceProvider rather than editing vendor code.
Sandbox / dry-run. Verify in the API docs whether a sandbox environment exists and whether this package's config lets you point at it. If not, the safest "dry-run" is to only ever call read endpoints in development and stub writes behind your own interface.
How can I help you explore Laravel packages today?