Looking to hire Laravel developers? Try LaraJobs

laravel-szamlazz maintained by szabrob

Description
Laravel integration for the Számlázz.hu Számla Agent API.
Last update
2026/11/12 20:40 (dev-main)
License
Downloads
1

Comments
comments powered by Disqus

Laravel integration for the Számlázz.hu Számla Agent API.

Requirements

  • PHP 8.3 or newer
  • Laravel 12 or 13

Installation

You can install the package via Composer:

composer require szabrob/laravel-szamlazz

You may publish all of the package's resources at once:

php artisan vendor:publish --tag="laravel-szamlazz"

Or, you may publish each resource individually:

Publishing the Configuration File

php artisan vendor:publish --tag="laravel-szamlazz-config"

Configuration

Set your Számla Agent key (Számlázz.hu → Beállítások → Számla Agent kulcsok) in .env:

SZAMLAZZ_API_KEY=your-agent-key

# or a username / password pair instead of the key
# SZAMLAZZ_USERNAME=
# SZAMLAZZ_PASSWORD=

# optional
# SZAMLAZZ_E_INVOICE=true          # create e-invoices (e-számla) instead of paper ones
# SZAMLAZZ_DOWNLOAD_PDF=true       # return the generated PDF with invoice and receipt results
# SZAMLAZZ_TIMEOUT=30              # HTTP timeout in seconds
# SZAMLAZZ_AGGREGATOR=             # aggregator identifier agreed with Számlázz.hu
# SZAMLAZZ_BASE_URL=https://www.szamlazz.hu/szamla/

Usage

Every request and response is a typed spatie/laravel-data object. Build requests with the constructor or with ::from([...]), then send them through the SzamlaAgent facade (or inject Szabrob\LaravelSzamlazz\SzamlaAgent).

Create an invoice

use Szabrob\LaravelSzamlazz\Data\Invoice\Invoice;
use Szabrob\LaravelSzamlazz\Facades\SzamlaAgent;

$result = SzamlaAgent::createInvoice(Invoice::from([
    'fulfillmentDate' => '2026-11-10',
    'dueDate' => '2026-11-18',
    'paymentMethod' => 'Átutalás',
    'currency' => 'HUF',
    'orderNumber' => 'ORDER-42',
    'buyer' => [
        'name' => 'Kovács Bt.',
        'postCode' => '2030',
        'city' => 'Érd',
        'address' => 'Tárnoki út 23.',
        'email' => 'buyer@example.com',
        'sendEmail' => true,
        'taxNumber' => '12345678-1-42',
    ],
    'items' => [
        ['name' => 'Webfejlesztés', 'quantity' => 2, 'unit' => 'óra', 'netUnitPrice' => 10000, 'vatRate' => '27'],
    ],
]));

$result->invoiceNumber; // "E-ABC-2026-1"
$result->grossTotal;    // 25400.0

if ($result->hasPdf()) {
    Storage::put("invoices/{$result->invoiceNumber}.pdf", $result->pdf);
}

Line item netAmount, vatAmount and grossAmount are filled in when omitted, so net + VAT always equals gross. Missing amounts are derived from the given ones first (e.g. only grossAmount → net and VAT are calculated back from the gross), otherwise from quantity × netUnitPrice and the vatRate. The vatRate is a percentage with a dot decimal separator ('27', '5', '0', '5.5') or one of the Számla Agent VAT keys, which count as zero VAT: TAM, AAM, EU, EUK, MAA, F.AFA, K.AFA, ÁKK, TAHK, TEHK, EUT, EUKT, KBAET, KBAUK, EAM, NAM, ATK, EUFAD37, EUFADE, EUE, HO. Any other value (e.g. '27%' or '27,0'), or three given amounts that do not add up, throws an InvalidSzamlazzRequest before anything is sent.

Set type to an InvoiceType to create other documents:

use Szabrob\LaravelSzamlazz\Enums\InvoiceType;

Invoice::from([...$data, 'type' => InvoiceType::Proforma]);     // díjbekérő
Invoice::from([...$data, 'type' => InvoiceType::Prepayment]);   // előlegszámla
Invoice::from([...$data, 'type' => InvoiceType::Final]);        // végszámla
Invoice::from([...$data, 'type' => InvoiceType::Corrective, 'correctedInvoiceNumber' => 'E-ABC-2026-1']);
Invoice::from([...$data, 'type' => InvoiceType::DeliveryNote]); // szállítólevél

Invoice options

Besides the buyer and the items, an invoice accepts optional settings. Some of the most used ones:

use Szabrob\LaravelSzamlazz\Enums\InvoiceTemplate;
use Szabrob\LaravelSzamlazz\Enums\Language;

Invoice::from([
    ...$data,
    'language' => Language::English,           // invoice language, Hungarian by default
    'template' => InvoiceTemplate::Basic,      // PDF template
    'prefix' => 'WEB',                         // invoice number prefix
    'externalId' => 'order-42',                // your own id, usable in InvoiceLookup::byExternalId()
    'paid' => true,                            // mark the invoice as paid
    'preview' => true,                         // return a preview PDF only, no invoice is created
    'eInvoice' => false,                       // override SZAMLAZZ_E_INVOICE for this invoice
    'downloadPdf' => false,                    // override SZAMLAZZ_DOWNLOAD_PDF for this invoice
    'seller' => [
        'bank' => 'OTP',
        'bankAccount' => '11111111-22222222-33333333',
        'emailReplyTo' => 'billing@example.com',
        'emailSubject' => 'Your invoice',
        'emailBody' => 'Thank you for your order.',
    ],
]);

The seller block only sets the bank, email and signatory details of this invoice; the rest of the seller data comes from your Számlázz.hu account. InvoiceReversal accepts the eInvoice and downloadPdf overrides too. Receipts and receipt lookups accept downloadPdf.

Other invoice operations

use Szabrob\LaravelSzamlazz\Data\Invoice\InvoiceLookup;
use Szabrob\LaravelSzamlazz\Data\Invoice\InvoiceReversal;
use Szabrob\LaravelSzamlazz\Data\Invoice\PaymentRegistration;

// Storno
$reversal = SzamlaAgent::reverseInvoice(new InvoiceReversal(invoiceNumber: 'E-ABC-2026-1'));

// Register payments (jóváírás), at most 5 per call
SzamlaAgent::registerPayment(PaymentRegistration::from([
    'invoiceNumber' => 'E-ABC-2026-1',
    'payments' => [
        ['date' => '2026-11-12', 'method' => 'átutalás', 'amount' => 25400],
    ],
]));

// Download the PDF (raw bytes)
$pdf = SzamlaAgent::invoicePdf(InvoiceLookup::byInvoiceNumber('E-ABC-2026-1'));

// Query invoice data (InvoiceDetails, the raw XML is available in ->xml)
$details = SzamlaAgent::invoice(InvoiceLookup::byOrderNumber('ORDER-42'), withPdf: false);

// Delete a proforma (by invoice number or order number; an external id is ignored)
SzamlaAgent::deleteProforma(InvoiceLookup::byInvoiceNumber('D-ABC-2026-1'));

Receipts (nyugta)

use Szabrob\LaravelSzamlazz\Data\Receipt\Receipt;
use Szabrob\LaravelSzamlazz\Data\Receipt\ReceiptEmail;
use Szabrob\LaravelSzamlazz\Data\Receipt\ReceiptLookup;
use Szabrob\LaravelSzamlazz\Data\Receipt\ReceiptReversal;

$receipt = SzamlaAgent::createReceipt(Receipt::from([
    'prefix' => 'NYGT',
    'callId' => 'order-42', // idempotency key
    'paymentMethod' => 'készpénz',
    'items' => [
        ['name' => 'Kávé', 'quantity' => 2, 'unit' => 'db', 'netUnitPrice' => 500, 'vatRate' => '27'],
    ],
]));

SzamlaAgent::receipt(ReceiptLookup::byReceiptNumber($receipt->receiptNumber));
SzamlaAgent::sendReceipt(new ReceiptEmail($receipt->receiptNumber, 'buyer@example.com'));
SzamlaAgent::reverseReceipt(new ReceiptReversal($receipt->receiptNumber));

Multiple accounts

The client reads the package config on every facade call and every container resolution, so changing laravel-szamlazz.* at runtime (tenancy middleware, Octane requests, queue jobs) applies to the next call. To pick an account explicitly, pass credentials per call:

use Szabrob\LaravelSzamlazz\Data\Credentials;

SzamlaAgent::withCredentials(Credentials::fromApiKey($tenant->szamlazz_key))
    ->createInvoice($invoice);

An instance injected into a long-lived object (for example a singleton's constructor) keeps the config it was created with. Resolve the client where you use it, or use withCredentials().

Error handling

Invalid requests throw Szabrob\LaravelSzamlazz\Exceptions\InvalidSzamlazzRequest before anything is sent, so no document is created. Examples: a malformed VAT rate, line item amounts that do not add up, an invoice or receipt without line items, more than 5 payments, or a lookup without any identifier. It extends InvalidArgumentException.

Számla Agent errors and connection failures (timeouts, DNS or network errors) throw Szabrob\LaravelSzamlazz\Exceptions\SzamlazzException. The Számla Agent error code is available in $exception->errorCode, the HTTP status in $exception->httpStatus, and the original exception of a connection failure in $exception->getPrevious().

On a timeout the document may still have been created, so look it up (for example by order number or receipt call id) before retrying.

use Szabrob\LaravelSzamlazz\Exceptions\InvalidSzamlazzRequest;
use Szabrob\LaravelSzamlazz\Exceptions\SzamlazzException;

try {
    SzamlaAgent::createInvoice($invoice);
} catch (InvalidSzamlazzRequest $exception) {
    // fix the request data; nothing was sent
} catch (SzamlazzException $exception) {
    report($exception);
}

Testing

The package uses the Laravel HTTP client, so Http::fake() works in your application tests:

Http::fake([
    'www.szamlazz.hu/*' => Http::response('<?xml version="1.0" encoding="UTF-8"?>
        <xmlszamlavalasz xmlns="http://www.szamlazz.hu/xmlszamlavalasz">
            <sikeres>true</sikeres>
            <szamlaszam>E-TEST-2026-1</szamlaszam>
        </xmlszamlavalasz>'),
]);

Changelog

Please see CHANGELOG for more information on what has changed recently.

Contributing

Thank you for considering contributing to Laravel Szamlazz! Please review our contributing guide to get started.

Security Vulnerabilities

Please review our security policy on how to report security vulnerabilities.

Credits

License

Laravel Szamlazz is open-sourced software licensed under the MIT license.