PHPackages                             storno/laravel-storno - 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. storno/laravel-storno

Active

storno/laravel-storno
=====================

00PHPCI passing

Pushed todayCompare

[ Source](https://github.com/stornoro/laravel-storno)[ Packagist](https://packagist.org/packages/storno/laravel-storno)[ RSS](/packages/storno-laravel-storno/feed)WikiDiscussions main Synced today

READMEChangelog (2)DependenciesVersionsUsed By (0)

laravel-storno
==============

[](#laravel-storno)

Laravel package for [Storno](https://storno.ro) — self-hosted invoicing with Romanian e-Factura (ANAF) integration.

[![Tests](https://github.com/stornoro/laravel-storno/actions/workflows/tests.yml/badge.svg)](https://github.com/stornoro/laravel-storno/actions/workflows/tests.yml)[![Latest Version](https://camo.githubusercontent.com/9f358ea0a752d43176290d586004bba34dc81fa244d6e3543e92f8ac045d8971/68747470733a2f2f696d672e736869656c64732e696f2f7061636b61676973742f762f73746f726e6f2f6c61726176656c2d73746f726e6f2e737667)](https://packagist.org/packages/storno/laravel-storno)[![License](https://camo.githubusercontent.com/18d032038f318627366a0a98480f5d35eb5ce8c206cd02c1b43f748c56197536/68747470733a2f2f696d672e736869656c64732e696f2f7061636b61676973742f6c2f73746f726e6f2f6c61726176656c2d73746f726e6f2e737667)](LICENSE)

---

Requirements
------------

[](#requirements)

- PHP 8.1+
- Laravel 10, 11, or 12

---

Installation
------------

[](#installation)

```
composer require storno/laravel-storno
```

Publish the config file:

```
php artisan vendor:publish --tag=storno-config
```

Add to your `.env`:

```
STORNO_API_URL=https://invoices.yourapp.com
STORNO_API_KEY=your-api-key
STORNO_COMPANY_ID=your-company-uuid
```

---

Quick Start
-----------

[](#quick-start)

### Create a client and invoice

[](#create-a-client-and-invoice)

```
use Storno\Laravel\Facades\Storno;
use Storno\Laravel\DTOs\Client;
use Storno\Laravel\DTOs\Invoice;
use Storno\Laravel\DTOs\InvoiceLine;

// 1. Create or find a client
$result = Storno::createClient(new Client(
    name: 'Acme SRL',
    type: 'company',
    email: 'billing@acme.ro',
    country: 'RO',
    city: 'București',
    cui: '12345678',
));

$clientId = $result['client']['id'];
$isNew = ! $result['existing'];

// 2. Create an invoice
$invoice = Storno::createInvoice(new Invoice(
    clientId: $clientId,
    currency: 'RON',
    paymentMethod: 'bank_transfer',
    orderNumber: 'ORD-2026-001',
    lines: [
        new InvoiceLine(
            description: 'Widget Pro',
            quantity: 2,
            unitPrice: 100.00,
            vatRate: 21,
        ),
        new InvoiceLine(
            description: 'Shipping',
            quantity: 1,
            unitPrice: 15.00,
            vatRate: 21,
        ),
    ],
));

$invoiceId = $invoice['invoice']['id'];

// 3. Issue the invoice (changes status from draft to issued)
if (config('storno.auto_issue')) {
    Storno::issueInvoice($invoiceId);
}

// 4. Download and store the PDF
$pdf = Storno::downloadPdf($invoiceId);
Storage::put("invoices/{$invoiceId}.pdf", $pdf);
```

### Submit to e-Factura (ANAF)

[](#submit-to-e-factura-anaf)

```
// After issuing, optionally submit to Romanian e-Factura system
Storno::submitInvoice($invoiceId);
```

### Look up a company by CUI (Romanian tax ID)

[](#look-up-a-company-by-cui-romanian-tax-id)

```
$company = Storno::anafLookup('12345678');
// Returns name, address, VAT status, etc.
```

---

Configuration Reference
-----------------------

[](#configuration-reference)

See `config/storno.php` for all options. Full docs at [docs.storno.ro](https://docs.storno.ro).

KeyDefaultDescription`api_url`—Your Storno instance URL`api_key`—API key from Storno dashboard`company_id`—Company UUID from Storno`auto_issue``true`Automatically issue invoices after creation`auto_apply_vat_rules``true`Apply VAT rules automatically`document_series_id`—Default document series UUID`invoice_language`—Invoice language (`ro`, `en`, etc.)`payment_term_days``30`Default payment term in days`default_vat_rate``21`Default VAT rate percentage`shipping_vat_rate``21`VAT rate for shipping lines`default_unit``buc`Default unit of measure`shipping_label``Shipping`Label for shipping line items`discount_label``Discount`Label for discount line items`invoice_notes`—Default notes on invoices`internal_note_format``#{order_number}`Template for internal notes`webhook_secret`—Secret for webhook signature verification`webhook_path``storno/webhook`URL path for the webhook endpoint`webhook_middleware``['api']`Middleware for the webhook route`timeout``30`HTTP request timeout (seconds)`retry.times``3`Number of retry attempts`retry.sleep``1000`Delay between retries (ms)---

API Reference
-------------

[](#api-reference)

All methods are available via the `Storno::` facade or by injecting `StornoClient`.

### Companies

[](#companies)

```
$companies = Storno::listCompanies();
```

### Clients

[](#clients)

```
// Create or find a client (idempotent by email/CUI)
$result = Storno::createClient(new Client(
    name: 'Acme SRL',
    type: 'company',       // 'company' or 'individual'
    email: 'billing@acme.ro',
    address: 'Str. Victoriei 1',
    city: 'București',
    county: 'Ilfov',
    country: 'RO',
    postalCode: '012345',
    phone: '+40700000000',
    cui: '12345678',
    vatCode: 'RO12345678',
    isVatPayer: true,
    registrationNumber: 'J40/1234/2020',
    bankName: 'BCR',
    bankAccount: 'RO49AAAA1B31007593840000',
    contactPerson: 'Ion Popescu',
    notes: 'VIP',
));
// Returns: ['client' => [...], 'existing' => bool]

// Get client by ID
$client = Storno::getClient('client-uuid');

// ANAF lookup by CUI
$company = Storno::anafLookup('12345678');
```

### Invoices

[](#invoices)

```
// Create invoice
$invoice = Storno::createInvoice(new Invoice(
    clientId: 'client-uuid',
    lines: [...],
    currency: 'RON',             // 'RON', 'EUR', 'USD', etc.
    paymentMethod: 'bank_transfer', // 'bank_transfer'|'cash'|'card'|'cheque'|'other'
    issueDate: '2026-04-04',
    dueDate: '2026-05-04',
    orderNumber: 'ORD-001',
    internalNote: '#ORD-001',
    idempotencyKey: 'unique-key-for-order',
    autoApplyVatRules: true,
    documentSeriesId: 'series-uuid',
    language: 'ro',
    notes: 'Thank you for your business.',
));

// Get invoice
$invoice = Storno::getInvoice('invoice-uuid');

// Issue invoice (draft -> issued)
Storno::issueInvoice('invoice-uuid');

// Submit to e-Factura ANAF
Storno::submitInvoice('invoice-uuid');

// Download PDF (returns raw binary)
$pdfContent = Storno::downloadPdf('invoice-uuid');
file_put_contents('/path/to/invoice.pdf', $pdfContent);
```

### Document Series

[](#document-series)

```
$series = Storno::listDocumentSeries();
// Returns array of series with id, name, prefix, nextNumber
```

### VAT Rates

[](#vat-rates)

```
$rates = Storno::listVatRates();
// Returns array of available VAT rates for this company
```

### Webhooks

[](#webhooks)

```
// Register a webhook
$webhook = Storno::createWebhook(
    url: 'https://yourapp.com/storno/webhook',
    events: ['invoice.issued', 'invoice.validated', 'invoice.rejected', 'invoice.paid'],
    description: 'My app webhook',
);
// Returns: ['uuid' => '...', 'secret' => '...']
// Save the 'secret' as STORNO_WEBHOOK_SECRET in your .env

// Delete a webhook
Storno::deleteWebhook('webhook-uuid');
```

---

Webhooks
--------

[](#webhooks-1)

### Setup

[](#setup)

Register a webhook using the Artisan command (recommended):

```
php artisan storno:webhook:register
# or with explicit URL:
php artisan storno:webhook:register --url=https://yourapp.com/storno/webhook
```

The command automatically saves the secret to your `.env` file.

The webhook endpoint is registered automatically at `POST /storno/webhook` (configurable via `STORNO_WEBHOOK_PATH`).

### Events

[](#events)

Listen for Storno events in your `EventServiceProvider` or using `#[AsListener]`:

```
use Storno\Laravel\Events\InvoiceIssued;
use Storno\Laravel\Events\InvoiceValidated;
use Storno\Laravel\Events\InvoiceRejected;
use Storno\Laravel\Events\InvoicePaid;
use Storno\Laravel\Events\WebhookReceived; // fires for every webhook

class AppServiceProvider extends ServiceProvider
{
    public function boot(): void
    {
        Event::listen(InvoiceIssued::class, function (InvoiceIssued $event) {
            $invoiceId = $event->payload->data['invoiceId'];
            // Send confirmation email, update order status, etc.
        });

        Event::listen(InvoicePaid::class, function (InvoicePaid $event) {
            // Mark order as paid
        });

        Event::listen(InvoiceRejected::class, function (InvoiceRejected $event) {
            // Handle ANAF rejection — log, notify admin, etc.
        });
    }
}
```

The `WebhookPayload` object has:

```
$event->payload->event      // e.g. 'invoice.issued'
$event->payload->id         // event UUID
$event->payload->data       // array with invoice data
$event->payload->occurredAt // ISO 8601 timestamp
$event->payload->raw        // full raw payload array
```

### Excluding the webhook route from CSRF

[](#excluding-the-webhook-route-from-csrf)

Add the webhook path to your `VerifyCsrfToken` middleware exceptions:

```
// app/Http/Middleware/VerifyCsrfToken.php
protected $except = [
    'storno/webhook',
];
```

---

Artisan Commands
----------------

[](#artisan-commands)

### Test connection

[](#test-connection)

```
php artisan storno:test
```

Verifies the API connection and lists companies on the instance.

### Register webhook

[](#register-webhook)

```
php artisan storno:webhook:register
php artisan storno:webhook:register --url=https://yourapp.com/storno/webhook
php artisan storno:webhook:register --url=... --events=invoice.issued --events=invoice.paid
php artisan storno:webhook:register --url=... --description="Production webhook"
```

### List document series

[](#list-document-series)

```
php artisan storno:series
```

Shows all available document series with their ID, prefix, and next number.

---

Error Handling
--------------

[](#error-handling)

```
use Storno\Laravel\Exceptions\StornoApiException;
use Storno\Laravel\Exceptions\StornoConnectionException;
use Storno\Laravel\Exceptions\InvalidSignatureException;

try {
    $invoice = Storno::createInvoice($dto);
} catch (StornoApiException $e) {
    // HTTP 4xx/5xx from the Storno API
    $statusCode = $e->getStatusCode();   // int
    $body = $e->getResponseBody();       // array
    Log::error('Storno API error', ['status' => $statusCode, 'body' => $body]);
} catch (StornoConnectionException $e) {
    // Network error, timeout, etc.
    Log::error('Storno connection error', ['message' => $e->getMessage()]);
}
```

---

Dependency Injection
--------------------

[](#dependency-injection)

You can inject `StornoClient` directly instead of using the facade:

```
use Storno\Laravel\StornoClient;

class InvoiceService
{
    public function __construct(private StornoClient $storno) {}

    public function createForOrder(Order $order): array
    {
        return $this->storno->createInvoice(/* ... */);
    }
}
```

---

Links
-----

[](#links)

- [Storno website](https://storno.ro)
- [Documentation](https://docs.storno.ro)
- [GitHub](https://github.com/stornoro/laravel-storno)
- [Packagist](https://packagist.org/packages/storno/laravel-storno)

---

License
-------

[](#license)

MIT — see [LICENSE](LICENSE).

###  Health Score

20

—

LowBetter than 15% of packages

Maintenance65

Regular maintenance activity

Popularity0

Limited adoption so far

Community6

Small or concentrated contributor base

Maturity8

Early-stage or recently created project

 Bus Factor1

Top contributor holds 100% of commits — single point of failure

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.

### Community

Maintainers

![](https://avatars.githubusercontent.com/u/10148108?v=4)[storno](/maintainers/storno)[@storno](https://github.com/storno)

---

Top Contributors

[![stornoro-bot](https://avatars.githubusercontent.com/u/263045070?v=4)](https://github.com/stornoro-bot "stornoro-bot (2 commits)")

### Embed Badge

![Health badge](/badges/storno-laravel-storno/health.svg)

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

PHPackages © 2026

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