PHPackages                             invocash/verifactu-php - 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. [API Development](/categories/api)
4. /
5. invocash/verifactu-php

ActiveLibrary[API Development](/categories/api)

invocash/verifactu-php
======================

Cliente PHP para la API de Verifactu y TicketBAI (facturación electrónica AEAT), de Invocash.

v1.0.0(1mo ago)944[1 issues](https://github.com/NemonInvocash/verifactu-php/issues)MITPHPPHP ^8.1

Since Jul 9Pushed 1mo ago2 watchersCompare

[ Source](https://github.com/NemonInvocash/verifactu-php)[ Packagist](https://packagist.org/packages/invocash/verifactu-php)[ Docs](https://verifactuapi.es)[ RSS](/packages/invocash-verifactu-php/feed)WikiDiscussions main Synced 1w ago

READMEChangelogDependenciesVersions (2)Used By (0)

verifactuPHP
============

[](#verifactuphp)

Cliente PHP para la API de Verifactu, desarrollado por **Invocash**.

---

Descripción
-----------

[](#descripción)

**verifactuPHP** integra **Verifactu** —el sistema de facturación electrónica de la AEAT— en tu aplicación PHP, sin necesidad de construir a mano las llamadas a la API. Permite validar y emitir facturas electrónicas conformes a la normativa española vigente.

Para construir el JSON de una factura puedes usar el [generador de JSON](https://verifactuapi.es/generador-json).

Más información en [verifactuapi.es](https://verifactuapi.es/) e [invocash.es](https://invocash.es).

---

Instalación
-----------

[](#instalación)

### Con Composer (recomendado)

[](#con-composer-recomendado)

```
composer require invocash/verifactu-php

```

### Sin Composer

[](#sin-composer)

Si no usas Composer, descarga el repositorio y colócalo en tu proyecto (p.ej. en `libs/verifactu-php/`). Incluye el autoloader con `require_once` antes de usar cualquier clase, donde te convenga: en el bootstrap de la app o en el módulo o rama que se encargue de la facturación. Al usar `require_once` puedes incluirlo desde varios sitios sin riesgo de cargarlo dos veces.

```
require_once 'libs/verifactu-php/autoload.php';

use VerifactuPHP\VerifactuClient;

$verifactu = VerifactuClient::usuario($email, $password);
```

El autoloader registra el namespace `VerifactuPHP\` (PSR-4, equivalente al de Composer): a partir de ese `require`, todas las clases —`VerifactuClient`, `TbaiClient`, excepciones…— se cargan automáticamente al usarlas, sin incluir ningún otro fichero. La librería no tiene dependencias externas: solo requiere PHP 8.1+ y la extensión cURL.

---

Guía de uso
===========

[](#guía-de-uso)

La librería expone dos clientes según el tipo de factura: `VerifactuClient` (Verifactu / territorio común AEAT) y `TbaiClient` (TicketBAI / País Vasco). Ambos comparten los mismos endpoints comunes (estado, censo, emisores y webhooks).

---

1. Inicialización del cliente
-----------------------------

[](#1-inicialización-del-cliente)

Crea el cliente adecuado según tus credenciales, con `usuario()` o `emisor()`:

```
require 'vendor/autoload.php';

use VerifactuPHP\VerifactuClient;
use VerifactuPHP\TbaiClient;

// Autenticación como usuario (email + contraseña): acceso completo, incluida la gestión de emisores y webhooks.
$verifactu = VerifactuClient::usuario($email, $password);

// Autenticación como emisor (username + API key): limitado al NIF del emisor.
$verifactu = VerifactuClient::emisor($username, $apiKey);

// El cliente TBAI se inicializa igual.
$tbai = TbaiClient::usuario($email, $password);
$tbai = TbaiClient::emisor($username, $apiKey);
```

El cliente gestiona el login y la renovación del token automáticamente: lo obtiene en la primera petición y, si expira, lo renueva y reintenta la petición de forma transparente.

Todos los métodos devuelven la respuesta de la API decodificada como `array` asociativo. Si la petición falla, lanzan una excepción (ver la sección Excepciones), por lo que un valor de retorno siempre implica éxito.

> Los métodos marcados con 👤 requieren autenticación **como usuario**; un cliente de emisor lanza `ClientException` antes de enviar la petición.

Regístrate en  para obtener tus credenciales de acceso.

---

2. Excepciones
--------------

[](#2-excepciones)

Ante un error, los métodos lanzan una de estas excepciones. `ApiRequestRefusedException` extiende `ApiException`, por lo que capturar `ApiException` cubre ambos casos.

### ClientException

[](#clientexception)

Error local, detectado **antes** de enviar la petición.

CódigoDescripciónMensaje de error`C-0`(valor por defecto)—`C-1`El body no se pudo serializar a JSON.`No se pudo convertir el body a JSON: ``C-2`Operación reservada a usuario (👤) invocada desde un cliente de emisor.`Esta operación requiere autenticación como usuario (login con email y contraseña); no está disponible para un cliente de emisor.`### TransportException

[](#transportexception)

Fallo de red: la petición no llegó a la API. Todas comparten el mensaje `Error de transporte al llamar a : ` (salvo el fallo al inicializar cURL, siempre `T-0`).

CódigoDescripciónMensaje de error`T-0`Otro fallo de transporte, o error al inicializar cURL.`Error de transporte al llamar a : ` · `No se pudo inicializar la petición cURL para ``T-1`Se agotó el tiempo de espera (timeout).`Error de transporte al llamar a : ``T-2`Fallo de verificación o negociación SSL.`Error de transporte al llamar a : ``T-3`No se pudo conectar o resolver el host.`Error de transporte al llamar a : `### ApiException

[](#apiexception)

La API respondió, pero con un fallo **no estructurado**. Expone `getStatusCode()`.

CódigoDescripciónMensaje de error`A-0`(valor por defecto)—`A-1`Autenticación fallida (token inválido o no renovable).`Error de autenticación` · `La respuesta de login no contiene un token válido``A-2`La API respondió, pero el cuerpo no es JSON legible (respuesta vacía o malformada).`Operación aceptada/rechazada (HTTP ) pero la respuesta es ilegible.``A-3`Error de servidor.`Error del servidor (HTTP ).``` = código de estado HTTP devuelto por la API (p.ej. 500).

### ApiRequestRefusedException

[](#apirequestrefusedexception)

Extiende `ApiException`. La API procesó la petición y la **rechazó** con un error estructurado (`success: false`). Expone `getStatusCode()` y `getData()`, que devuelve el body de error completo con el detalle del rechazo (validación, factura duplicada, etc.).

CódigoDescripciónMensaje de errorRespuesta API`A-4`La API rechazó la petición (`success: false`).Mensaje devuelto por la API (o `Error desconocido de la API`)✓ `getData()`### Métodos

[](#métodos)

Además de los de `Exception` (`getMessage()`, etc.), estas excepciones añaden accesores propios:

MétodoDevuelveDisponible en`getReason()`Código de subcausa para diferenciar el motivo sin parsear el mensaje (ver la tabla de códigos de cada excepción).Todas`getStatusCode()`Código de estado HTTP asociado al error (`int`).`ApiException` y `ApiRequestRefusedException``getData()`Cuerpo completo de la respuesta de error de la API (`array`), con el detalle del rechazo.`ApiRequestRefusedException``getCode()` (nativo de PHP) no se utiliza; para el status HTTP usa `getStatusCode()`.

### Gestión de excepciones

[](#gestión-de-excepciones)

Encadena los `catch` de la **más específica a la más general**. En la práctica solo hay una regla que importa: `ApiRequestRefusedException` extiende `ApiException`, así que debe capturarse **antes**; de lo contrario `ApiException` la interceptaría primero y perderías el `getData()`.

`ClientException` y `TransportException` son independientes entre sí y de `ApiException`, así que su orden relativo da igual. Para atrapar cualquier error de la librería de golpe, basta con capturar esas dos más `ApiException`.

```
use VerifactuPHP\Exceptions\ApiRequestRefusedException;
use VerifactuPHP\Exceptions\ApiException;
use VerifactuPHP\Exceptions\TransportException;
use VerifactuPHP\Exceptions\ClientException;

try {
    $respuesta = $verifactu->altaRegistroFacturacion($factura);
} catch (ApiRequestRefusedException $e) {
    // Rechazo de negocio. Métodos: getData(), getStatusCode(), getReason(), getMessage()
    $detalle = $e->getData();       // body de error de la API
    $http    = $e->getStatusCode(); // código HTTP
    $codigo  = $e->getReason();     // A-4
} catch (ApiException $e) {
    // Error de servidor, auth o respuesta ilegible. Métodos: getStatusCode(), getReason(), getMessage()
    $http   = $e->getStatusCode(); // código HTTP
    $codigo = $e->getReason();     // A-1, A-2, A-3
} catch (TransportException $e) {
    // Fallo de red. Métodos: getReason(), getMessage()
    $codigo = $e->getReason();     // T-0, T-1, T-2, T-3
} catch (ClientException $e) {
    // Error de uso del cliente. Métodos: getReason(), getMessage()
    $codigo = $e->getReason();     // C-1, C-2
}
```

---

3. Funcionalidades
------------------

[](#3-funcionalidades)

Para usar cualquier funcionalidad, invoca el método sobre el cliente ya inicializado:

```
$respuesta = $cliente->metodo($args);
```

Las tablas siguientes agrupan los métodos por bloque. Para cada uno se indica su firma, qué hace y el enlace a su documentación.

**👤** = requiere login de usuario.

Los listados reciben una *query string* ya formada (p.ej. `'?enabled=1&limit=50'`) que se concatena a la URL.

### 3.1 Comunes

[](#31-comunes)

Disponibles tanto en `VerifactuClient` como en `TbaiClient`.

**Estado**

MétodoDescripciónDocs`status()`Comprueba que el servidor está operativo (no requiere autenticación).**Censo AEAT**

MétodoDescripciónDocs`censoAeat(array $destinatarios)`Valida uno o varios destinatarios contra el censo de la AEAT.**Emisores**

MétodoDescripciónDocs`listarEmisores(string $query = '')`Lista los emisores de la cuenta.`obtenerEmisor(string $id)`Obtiene un emisor por su id.`crearEmisor(array $datos)` 👤Crea un nuevo emisor.`actualizarEmisor(string $id, array $datos)` 👤Actualiza un emisor existente.`generarApiKey(string $id)` 👤Genera y devuelve la API key de un emisor.**Webhooks**

MétodoDescripciónDocs`listarWebhooks(string $query = '')` 👤Lista los webhooks configurados.`obtenerWebhook(string $id)` 👤Obtiene un webhook por su id.`logsWebhook(string $id)` 👤Obtiene los logs de un webhook.`crearWebhook(array $datos)` 👤Crea un nuevo webhook.`actualizarWebhook(string $id, array $datos)` 👤Actualiza un webhook existente.`eliminarWebhook(string $id)` 👤Elimina un webhook.—### 3.2 Verifactu

[](#32-verifactu)

Métodos de `VerifactuClient`.

**Alta**

MétodoDescripciónDocs`altaRegistroFacturacion(array $factura)`Registra (da de alta) una factura Verifactu.`validarRegistroFacturacion(array $factura)`Valida el formato de una factura sin registrarla.**Anulación**

MétodoDescripciónDocs`anularRegistroFacturacionPorDatos(array $datos)`Anula una factura por sus datos identificadores.`anularRegistroFacturacionPorId(string $id)`Anula un registro de facturación existente por su id.**Listado**

MétodoDescripciónDocs`listarRegistrosFacturacion(string $query = '')`Lista los registros de facturación.`obtenerRegistroFacturacion(string $id)`Obtiene un registro de facturación por su id.**Envíos AEAT**

MétodoDescripciónDocs`listarEnviosAeat(string $query = '')`Lista los envíos a la AEAT.`obtenerEnvioAeat(string $id)`Obtiene un envío a la AEAT por su id.`obtenerLineaEnvioAeat(string $lineaId)`Obtiene una línea de envío a la AEAT por su id.[https://app.verifactuapi.es/docs/#verifactu-GETapi-envios-aeat-linea--linea\_id-](https://app.verifactuapi.es/docs/#verifactu-GETapi-envios-aeat-linea--linea_id-)**Consultas**

MétodoDescripciónDocs`consultarRegistrosAeat(array $datos)`Consulta registros de facturación ya presentados en la AEAT.**Listas de códigos**

MétodoDescripciónDocs`listarListas()`Lista todas las listas de códigos disponibles.`obtenerLista(string $lista)`Obtiene los valores de una lista de códigos.`obtenerLineaLista(string $lista, string $valor)`Obtiene una línea concreta de una lista de códigos.### 3.3 TBAI

[](#33-tbai)

Métodos de `TbaiClient`.

**Alta**

MétodoDescripciónDocs`altaRegistroTbai(array $factura)`Registra (da de alta) una factura TBAI.`validarRegistroTbai(array $factura)`Valida el formato de una factura TBAI sin registrarla.`obtenerQrTbai(string $id)`Obtiene el QR de una factura TBAI por su id.`zuzenduModificarTbai(string $id, array $datos = [])`Zuzendu: modifica una factura TBAI por su id.`zuzenduSubsanarTbai(string $id, array $datos = [])`Zuzendu: subsana una factura TBAI por su id.**Anulación**

MétodoDescripciónDocs`anularRegistroTbaiPorDatos(array $datos)`Anula una factura TBAI por sus datos identificadores.`anularRegistroTbaiPorId(string $id)`Anula un registro de facturación TBAI existente por su id.**Listado**

MétodoDescripciónDocs`listarRegistrosTbai(string $query = '')`Lista los registros de facturación TBAI.`obtenerRegistroTbai(string $id)`Obtiene un registro de facturación TBAI por su id.**Envíos**

MétodoDescripciónDocs`listarEnviosTbai(string $query = '')`Lista los envíos TBAI.`obtenerEnvioTbai(string $id)`Obtiene un envío TBAI por su id.**Consultas**

MétodoDescripciónDocs`consultarRegistrosTbai(array $datos)`Consulta registros de facturación TBAI ya presentados.—`obtenerConsultaTbai(string $id)`Obtiene una consulta de registros TBAI por su id.—**Listas de códigos**

MétodoDescripciónDocs`listarListasTbai()`Lista todas las listas de códigos TBAI.`obtenerListaTbai(string $lista)`Obtiene los valores de una lista de códigos TBAI.`obtenerLineaListaTbai(string $lista, string $valor)`Obtiene una línea concreta de una lista de códigos TBAI.**Software TBAI**

MétodoDescripciónDocs`obtenerSoftwareTbai(string $type)`Obtiene los datos del software TBAI por su tipo.### 3.4 Peticiones personalizadas

[](#34-peticiones-personalizadas)

Si necesitas llamar a un endpoint que la librería todavía no envuelve, usa el método `request()`, disponible en ambos clientes. Construye la petición a partir de la ruta que le pases y reutiliza la misma lógica de autenticación, renovación de token y manejo de errores que el resto de métodos.

```
public function request(
    string $method,        // GET, POST, PUT, PATCH, DELETE
    string $path,          // ruta relativa a la base de la API, p.ej. '/mi-endpoint?x=1'
    ?array $body = null,   // body que se enviará como JSON
    bool $conAuth = true,  // si la petición requiere token (por defecto, sí)
): array
```

```
$verifactu->request('POST', '/endpoint-nuevo', ['campo' => 'valor']);
$verifactu->request('GET', '/algo?x=1');
```

Devuelve el `array` de la respuesta y lanza las mismas excepciones que el resto de la librería. A diferencia de los métodos con nombre, no valida el tipo de login: si llamas a una operación reservada a usuarios con un cliente de emisor, el error lo devolverá la API en vez de cortarse en local.

---

Licencia
--------

[](#licencia)

Este proyecto está bajo la Licencia MIT, lo que permite su uso y modificación bajo ciertas condiciones.

---

Contacto
--------

[](#contacto)

Para más información, contacta con INVOCASH SOLUTIONS SL:

- Soporte técnico:
- Consultas comerciales:

---

###  Health Score

40

—

FairBetter than 86% of packages

Maintenance88

Actively maintained with recent releases

Popularity13

Limited adoption so far

Community12

Small or concentrated contributor base

Maturity42

Maturing project, gaining track record

 Bus Factor1

Top contributor holds 88.9% 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.

###  Release Activity

Cadence

Unknown

Total

1

Last Release

48d ago

### Community

Maintainers

![](https://www.gravatar.com/avatar/86f952ab7628cf9ae44ee692e9f1dbe0200b6c1b2845c78c1f4d316fa324d5ea?d=identicon)[lluisMtz](/maintainers/lluisMtz)

---

Top Contributors

[![lluisMtz](https://avatars.githubusercontent.com/u/191105110?v=4)](https://github.com/lluisMtz "lluisMtz (8 commits)")[![ivansolenemon](https://avatars.githubusercontent.com/u/167551942?v=4)](https://github.com/ivansolenemon "ivansolenemon (1 commits)")

---

Tags

aeatapi-clientinvocashinvoicingphpspaintbaiticketbaiveri-factuverifactuapifacturacion-electronicaverifactuaeatfactura-electronicatbaiticketbaiinvocash

### Embed Badge

![Health badge](/badges/invocash-verifactu-php/health.svg)

```
[![Health](https://phpackages.com/badges/invocash-verifactu-php/health.svg)](https://phpackages.com/packages/invocash-verifactu-php)
```

###  Alternatives

[m165437/laravel-blueprint-docs

API Blueprint Renderer for Laravel

22880.1k](/packages/m165437-laravel-blueprint-docs)[libredte/libredte-api-client

Cliente para realizar la integración con los servicios web de LibreDTE desde PHP.

171.1k](/packages/libredte-libredte-api-client)

PHPackages © 2026

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