Integrar VeriFactu en PHP y Laravel

· Equipo Factuneo

Emite facturas VeriFactu desde PHP/Laravel con una llamada HTTP: alta del emisor, emisión con idempotencia y webhook de estado. Con ejemplos usando el cliente Http de Laravel.

Integra VeriFactu en tu aplicación PHP/Laravel sin construir el XML, la huella ni el SOAP con la AEAT: emites con una llamada HTTP.

1. API key

Regístrate y copia tu API key (x-api-key). Guárdala en .env (FACTUNEO_API_KEY) y expónla en config/services.php, nunca en el código.

2. Da de alta el emisor

use Illuminate\Support\Facades\Http;

Http::withHeaders(['x-api-key' => config('services.factuneo.key')])
    ->post('https://factuneo.es/api/v1/emisores', [
        'nif' => 'B12345678',
        'nombreRazon' => 'Mi Empresa SL',
        'certMode' => 'PROPIO',
    ]);

3. Emite la factura

$res = Http::withHeaders([
        'x-api-key' => config('services.factuneo.key'),
        'Idempotency-Key' => 'FAC-2026-0001',
    ])->post('https://factuneo.es/api/v1/invoices', [
        'emisorNif' => 'B12345678',
        'numeroSerie' => 'FAC-2026-0001',
        'fechaExpedicion' => '2026-06-08',
        'tipoFactura' => 'F1',
        'nombreRazonEmisor' => 'Mi Empresa SL',
        'descripcionOperacion' => 'Servicios',
        'baseImponible' => 100.00,
        'cuotaIva' => 21.00,
        'importeTotal' => 121.00,
        'destinatarios' => [['nombreRazon' => 'Cliente SA', 'nif' => 'A28000024']],
        'desglose' => [[
            'claveRegimen' => '01',
            'calificacionOperacion' => 'S1',
            'tipoImpositivo' => 21,
            'baseImponible' => 100.00,
            'cuotaRepercutida' => 21.00,
        ]],
    ]);

$factura = $res->json(); // huella, qr y estado en la respuesta

La cabecera Idempotency-Key evita duplicados si Laravel reintenta la petición.

4. Webhook de estado

Route::post('/webhooks/factuneo', function (Illuminate\Http\Request $r) {
    // verifica la firma HMAC-SHA256 con el secreto de tu cuenta antes de fiarte
    $estado = $r->input('estado'); // ACEPTADO / RECHAZADO ...
    return response()->noContent();
});

Referencia completa (autenticación, certificados, todos los campos) en la documentación. ¿Comparando opciones? Mira la comparativa.

← Volver al blog · Factuneo