PHPackages                             ebethus/laravel-ticketbai - 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. [Utility &amp; Helpers](/categories/utility)
4. /
5. ebethus/laravel-ticketbai

ActiveLibrary[Utility &amp; Helpers](/categories/utility)

ebethus/laravel-ticketbai
=========================

TicketBai Library for Laravel

13.2k2PHP

Since Mar 30Pushed 2mo ago1 watchersCompare

[ Source](https://github.com/bethuxs/LaravelTicketBai)[ Packagist](https://packagist.org/packages/ebethus/laravel-ticketbai)[ RSS](/packages/ebethus-laravel-ticketbai/feed)WikiDiscussions main Synced 1mo ago

READMEChangelogDependenciesVersions (1)Used By (0)

Laravel TicketBAI
=================

[](#laravel-ticketbai)

[![License](https://camo.githubusercontent.com/7013272bd27ece47364536a221edb554cd69683b68a46fc0ee96881174c4214c/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f6c6963656e73652d4d49542d626c75652e737667)](LICENSE)[![PHP Version](https://camo.githubusercontent.com/c5e8da782b1a0673c08b4f474108036d2cc973470eed2d5d89d48e8c8475eee6/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f7068702d253345253344382e322d626c75652e737667)](https://www.php.net/)

A Laravel package for generating and submitting TicketBAI (Ticket BAI) invoices for the Basque Country (Euskadi), Spain. This package provides a flexible and configurable solution for integrating TicketBAI compliance into your Laravel application.

Table of Contents
-----------------

[](#table-of-contents)

- [Features](#features)
- [Requirements](#requirements)
- [Installation](#installation)
- [Configuration](#configuration)
- [Usage](#usage)
- [Database Configuration](#database-configuration)
- [API Reference](#api-reference)
- [Examples](#examples)
- [Testing](#testing)
- [Contributing](#contributing)
- [License](#license)

Features
--------

[](#features)

- ✅ Generate TicketBAI-compliant invoices
- ✅ Automatic invoice signing with X.509 certificates
- ✅ Queue-based invoice submission to TicketBAI API
- ✅ Flexible database table and column configuration
- ✅ Support for custom table structures
- ✅ Optional columns (signature, data, territory) for maximum flexibility
- ✅ **Encadenamiento**: firma y territorio siempre en columna JSON `data` bajo clave configurable (por defecto `ticketbai`)
- ✅ QR code generation for invoices
- ✅ Support for multiple territories (Araba, Bizkaia, Gipuzkoa)
- ✅ Automatic fingerprint calculation from previous invoices
- ✅ Artisan command to resend failed/pending invoices (`ticketbai:resend`)

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

[](#requirements)

- PHP &gt;= 8.2
- Laravel &gt;= 8.0 (tested with Laravel 10.x and 11.x)
- [barnetik/ticketbai](https://github.com/barnetik/ticketbai) package
- X.509 certificate (.p12 file) for signing invoices
- TicketBAI license and credentials

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

[](#installation)

Install the package via Composer:

```
composer require ebethus/laravel-ticketbai
```

### Publish Configuration

[](#publish-configuration)

Publish the configuration file:

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

This will create `config/ticketbai.php` where you can configure table and column mappings.

### Run Migrations

[](#run-migrations)

If you want to use the default invoice table structure:

```
php artisan migrate
```

**Note:** You can also use your own table structure by configuring column mappings (see [Database Configuration](#database-configuration)).

Configuration
-------------

[](#configuration)

### Service Configuration

[](#service-configuration)

Add your TicketBAI credentials to `config/services.php`:

```
'ticketbai' => [
    'license' => env('TICKETBAI_LICENSE', ''),
    'nif' => env('TICKETBAI_NIF', ''),
    'appName' => env('TICKETBAI_APP_NAME', ''),
    'appVersion' => env('TICKETBAI_APP_VERSION', ''),
    'certPassword' => env('TICKETBAI_CERT_PASSWORD', ''),
    'disk' => env('TICKETBAI_DISK', 'local'),
],
```

### Environment Variables

[](#environment-variables)

Add these to your `.env` file:

```
TICKETBAI_LICENSE=TB12345678
TICKETBAI_NIF=B1111111
TICKETBAI_APP_NAME=My Application
TICKETBAI_APP_VERSION=1.0
TICKETBAI_CERT_PASSWORD=your_certificate_password
TICKETBAI_DISK=local
TICKETBAI_CERT_PATH=certificado.p12
```

Use `TICKETBAI_CERT_PATH` to override the certificate path. It can be a path relative to `storage_path()` (e.g. `certificado.p12` for `storage/certificado.p12`) or an absolute path (e.g. `/etc/certs/ticketbai.p12` on Linux).

### Certificate Setup

[](#certificate-setup)

By default the package looks for the X.509 certificate (`.p12`) at `storage/certificado.p12`. Set `TICKETBAI_CERT_PATH` in your `.env` to use a different path (relative to `storage_path()` or absolute). The certificate is used to sign invoices before submission.

Usage
-----

[](#usage)

### Basic Example

[](#basic-example)

```
use EBethus\LaravelTicketBAI\TicketBAI;

// Get TicketBAI instance (configured via service provider)
$ticketbai = app('ticketbai');

// Or use the facade
use TicketBAI;

// Set issuer information
$ticketbai->issuer(
    nif: 'B12345678',
    name: 'Company Name',
    idIssuer: 1,
    serie: '' // Optional
);

// Set VAT percentage
$ticketbai->setVat(21); // 21% VAT

// Add invoice items
$ticketbai->add(
    desc: 'Product description',
    unitPrice: 100.00,
    q: 2,
    discount: 0 // Optional
);

// Generate and sign invoice
$qrUrl = $ticketbai->invoice(
    territory: 'BIZKAIA', // or 'ARABA', 'GIPUZKOA'
    description: 'Invoice description'
);

// The invoice is automatically saved and queued for submission
// $qrUrl contains the QR code URL for the invoice
```

### Using Dependency Injection

[](#using-dependency-injection)

```
use EBethus\LaravelTicketBAI\TicketBAI;

class InvoiceController extends Controller
{
    public function __construct(
        protected TicketBAI $ticketbai
    ) {}

    public function create(Request $request)
    {
        $this->ticketbai->issuer(
            nif: $request->nif,
            name: $request->company_name,
            idIssuer: $request->issuer_id
        );

        $this->ticketbai->setVat(21);

        foreach ($request->items as $item) {
            $this->ticketbai->add(
                desc: $item['description'],
                unitPrice: $item['price'],
                q: $item['quantity'],
                discount: $item['discount'] ?? 0
            );
        }

        $qrUrl = $this->ticketbai->invoice(
            territory: 'BIZKAIA',
            description: $request->description
        );

        return response()->json(['qr_url' => $qrUrl]);
    }
}
```

### Adding Extra Data

[](#adding-extra-data)

You can attach additional JSON data to invoices:

```
$ticketbai->data([
    'order_id' => 12345,
    'customer_id' => 67890,
    'custom_field' => 'value'
]);
```

This data will be stored in the `data` column if configured (see [Database Configuration](#database-configuration)).

Database Configuration
----------------------

[](#database-configuration)

The library supports flexible table and column configuration, allowing you to use your existing database structure.

### Default Table Structure

[](#default-table-structure)

The default migration creates an `invoices` table with columns `issuer`, `provider_reference`, `path`, `data`, `sent`, and timestamps. TicketBAI stores signature and territory in the `data` JSON column under the key `ticketbai`.

### Custom Table Configuration

[](#custom-table-configuration)

If you use **your own table** with different column names (e.g. `transaction_id` instead of `issuer`), override the mappings via environment variables. Example: `TICKETBAI_COLUMN_ISSUER=transaction_id`, `TICKETBAI_COLUMN_NUMBER=invoice_number`, `TICKETBAI_COLUMN_SENT=attempted_at`.

Configure column mappings in `config/ticketbai.php`:

```
'table' => [
    'name' => env('TICKETBAI_TABLE_NAME', 'invoices'),
    'columns' => [
        // Defaults match the default migration. For your own table use env, e.g.:
        // TICKETBAI_COLUMN_ISSUER=transaction_id, TICKETBAI_COLUMN_NUMBER=invoice_number
        'issuer' => env('TICKETBAI_COLUMN_ISSUER', 'issuer'),
        'number' => env('TICKETBAI_COLUMN_NUMBER', 'provider_reference'),
        'territory' => env('TICKETBAI_COLUMN_TERRITORY', 'territory'),
        'signature' => env('TICKETBAI_COLUMN_SIGNATURE', 'signature'),
        'path' => env('TICKETBAI_COLUMN_PATH', 'path'),
        'data' => env('TICKETBAI_COLUMN_DATA', 'data'),
        'sent' => env('TICKETBAI_COLUMN_SENT', 'sent'),
        'created_at' => env('TICKETBAI_COLUMN_CREATED_AT', 'created_at'),
        'updated_at' => env('TICKETBAI_COLUMN_UPDATED_AT', 'updated_at'),
    ],
],
```

### Environment Variables for Column Mapping

[](#environment-variables-for-column-mapping)

Use these only when you have a **custom table** with different column names:

```
TICKETBAI_TABLE_NAME=invoices
TICKETBAI_COLUMN_ISSUER=transaction_id
TICKETBAI_COLUMN_NUMBER=provider_reference
TICKETBAI_COLUMN_TERRITORY=territory
TICKETBAI_COLUMN_SIGNATURE=signature
TICKETBAI_COLUMN_PATH=path
TICKETBAI_COLUMN_DATA=data
TICKETBAI_COLUMN_SENT=attempted_at
TICKETBAI_COLUMN_CREATED_AT=created_at
TICKETBAI_COLUMN_UPDATED_AT=updated_at
```

### TicketBAI payload in `data` (required for chaining)

[](#ticketbai-payload-in-data-required-for-chaining)

Signature and territory are **always** stored in the JSON `data` column under a configurable key so that encadenamiento (signature chaining) works. Default key: `ticketbai`. Set in `.env` or config:

```
TICKETBAI_DATA_KEY=ticketbai
```

The package stores and reads `signature` (first 100 chars) and `territory` under `data->ticketbai`. Path stays in the `path` column. Example:

```
{
  "ticketbai": {
    "signature": "first 100 chars of chain signature",
    "territory": "02"
  },
  "order_id": 12345
}
```

Your table needs: `id`, `issuer`, `number`, **`path`** (file path), **`data`** (JSON), `sent`, `created_at`, `updated_at`. Other providers can use other keys in `data` (e.g. `data->other_provider`).

### Optional column name override

[](#optional-column-name-override)

- **`data`**: Set to `null` or empty to use the default column name `'data'`.

### Required Columns

[](#required-columns)

- **`path`**: Required - stores the signed XML file path (filesystem).
- **`data`**: Required - JSON column where TicketBAI stores signature and territory under `TICKETBAI_DATA_KEY`.

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

[](#api-reference)

### TicketBAI Class

[](#ticketbai-class)

#### `issuer(string $nif, string $name, int $idIssuer, string $serie = '')`

[](#issuerstring-nif-string-name-int-idissuer-string-serie--)

Set the issuer information for the invoice.

- `$nif`: Tax identification number (NIF/CIF)
- `$name`: Company name
- `$idIssuer`: Internal issuer ID (used for database storage)
- `$serie`: Optional invoice series

#### `setVat(float $vatPerc)`

[](#setvatfloat-vatperc)

Set the VAT percentage for invoice items.

- `$vatPerc`: VAT percentage (e.g., 21 for 21%)

#### `add(string $desc, float $unitPrice, float $q, float $discount = null)`

[](#addstring-desc-float-unitprice-float-q-float-discount--null)

Add an item to the invoice.

- `$desc`: Item description
- `$unitPrice`: Unit price (including VAT)
- `$q`: Quantity
- `$discount`: Optional discount amount

#### `data(mixed $data)`

[](#datamixed-data)

Attach additional JSON data to the invoice.

- `$data`: Array or object to be stored as JSON

#### `invoice(string $territory, string $description)`

[](#invoicestring-territory-string-description)

Generate, sign, and save the invoice. Returns the QR code URL.

- `$territory`: Territory code: `'ARABA'`, `'BIZKAIA'`, or `'GIPUZKOA'` (or numeric codes `'01'`, `'02'`, `'03'`)
- `$description`: Invoice description

**Returns:** `string` - QR code URL

#### `getModel()`

[](#getmodel)

Get the Eloquent model instance for the saved invoice.

**Returns:** `Invoice`

#### `getTBAI()`

[](#gettbai)

Get the underlying TicketBAI object from the barnetik/ticketbai package.

**Returns:** `\Barnetik\Tbai\TicketBai`

Examples
--------

[](#examples)

### Complete Invoice Example

[](#complete-invoice-example)

```
use EBethus\LaravelTicketBAI\TicketBAI;

$ticketbai = app('ticketbai');

// Configure issuer
$ticketbai->issuer(
    nif: 'B12345678',
    name: 'My Company S.L.',
    idIssuer: 1
);

// Set VAT
$ticketbai->setVat(21);

// Add items
$ticketbai->add('Product A', 50.00, 2, 0);
$ticketbai->add('Product B', 30.00, 1, 5.00);

// Add extra data
$ticketbai->data([
    'order_id' => 12345,
    'customer_email' => 'customer@example.com'
]);

// Generate invoice
$qrUrl = $ticketbai->invoice(
    territory: 'BIZKAIA',
    description: 'Order #12345'
);

echo "QR Code: $qrUrl";
```

### Using with Custom Table

[](#using-with-custom-table)

```
// In config/ticketbai.php or .env
// TICKETBAI_TABLE_NAME=my_invoices
// TICKETBAI_COLUMN_ISSUER=user_id
// TICKETBAI_COLUMN_NUMBER=invoice_ref
// TICKETBAI_COLUMN_SIGNATURE=  (empty, disabled)
// TICKETBAI_COLUMN_DATA=  (empty, disabled)

$ticketbai = app('ticketbai');
$ticketbai->issuer('B12345678', 'Company', 1);
$ticketbai->setVat(21);
$ticketbai->add('Item', 100, 1);
$qrUrl = $ticketbai->invoice('BIZKAIA', 'Invoice');
```

### Accessing Saved Invoice

[](#accessing-saved-invoice)

```
$ticketbai = app('ticketbai');
// ... configure and generate invoice ...

$model = $ticketbai->getModel();
echo $model->provider_reference; // Invoice number (default column name)
echo $model->path;               // XML file path
```

Testing
-------

[](#testing)

Run the test suite:

```
composer test
```

Or with PHPUnit directly:

```
./vendor/bin/phpunit
```

Optional: run static analysis (PHPStan) and code style (Laravel Pint):

```
composer analyse   # PHPStan
composer format   # Pint (fixes style)
```

Queue Configuration
-------------------

[](#queue-configuration)

Invoice submission is **asynchronous**: after generating and signing an invoice, the package dispatches an `InvoiceSend` job to the Laravel queue. You must have at least one queue worker running for invoices to be sent to the TicketBAI API:

```
php artisan queue:work
```

- **Production:** Use a process manager (e.g. Supervisor) to keep `queue:work` running.
- **Testing / sync:** If you use `QUEUE_CONNECTION=sync`, jobs run immediately in the same process (no worker needed, but slower and no retries).

The `InvoiceSend` job submits the invoice to the TicketBAI API and updates the `sent` timestamp on success.

Resending Failed or Pending Invoices
------------------------------------

[](#resending-failed-or-pending-invoices)

Invoices that were not sent (e.g. API error or worker down) have `sent = null`. To re-queue them for sending:

```
# List and resend all pending invoices
php artisan ticketbai:resend --all

# Resend a single invoice by ID
php artisan ticketbai:resend --id=123

# Dry run: only list what would be resent
php artisan ticketbai:resend --all --dry-run
```

Resend requires **territory** and **path**: territory is read from `data[ticketbai_data_key]` (default `data->ticketbai`), path from the path column.

Troubleshooting
---------------

[](#troubleshooting)

### Certificate Errors

[](#certificate-errors)

- Ensure `storage/certificado.p12` exists and is readable
- Verify the certificate password is correct
- Check file permissions

### Database Column Errors

[](#database-column-errors)

- Verify column mappings in `config/ticketbai.php`
- Ensure required columns exist in your table
- Set optional columns to `null` if not needed

### Queue Issues

[](#queue-issues)

- Ensure queue worker is running
- Check queue connection configuration
- Review failed jobs: `php artisan queue:failed`

Contributing
------------

[](#contributing)

Contributions are welcome! Please feel free to submit a Pull Request.

1. Fork the repository
2. Create your feature branch (`git checkout -b feature/amazing-feature`)
3. Commit your changes (`git commit -m 'Add some amazing feature'`)
4. Push to the branch (`git push origin feature/amazing-feature`)
5. Open a Pull Request

License
-------

[](#license)

This package is open-sourced software licensed under the [MIT license](LICENSE).

Credits
-------

[](#credits)

- Built on top of [barnetik/ticketbai](https://github.com/barnetik/ticketbai)
- Developed by [EBethus](https://github.com/ebethus)

Support
-------

[](#support)

For issues and feature requests, please use the [GitHub issue tracker](https://github.com/ebethus/laravel-ticketbai/issues).

###  Health Score

26

—

LowBetter than 43% of packages

Maintenance57

Moderate activity, may be stable

Popularity25

Limited adoption so far

Community9

Small or concentrated contributor base

Maturity11

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://www.gravatar.com/avatar/25f561a3fd260935cc3ea5dc049b4ff598c37408dfdbbc129d091221de6c2954?d=identicon)[alb\_be](/maintainers/alb_be)

---

Top Contributors

[![bethuxs](https://avatars.githubusercontent.com/u/191869?v=4)](https://github.com/bethuxs "bethuxs (44 commits)")

### Embed Badge

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

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

###  Alternatives

[alibabacloud/sdk

Alibaba Cloud SDK for PHP - Easier to Use Alibaba Cloud in your PHP project

5282.1M45](/packages/alibabacloud-sdk)

PHPackages © 2026

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