Docs / SDK PHP

SDK PHP — Documentación

Integra facturación electrónica SRI con PHP 8.3+, Guzzle y excepciones tipadas. Publicado en Packagist.

Instalación

Requisitos: PHP 8.3+, Composer, Git.

Desde Packagist (recomendado):

composer require factus-easy/factus-easy-sdk:^0.1
Opción avanzada: última rama dev-main via GitHub VCS
{
    "minimum-stability": "dev",
    "prefer-stable": true,
    "repositories": [
        { "type": "vcs", "url": "https://github.com/dj-Andres/Factus-Easy-SDK" }
    ],
    "config": { "github-protocols": ["https"] },
    "require": { "factus-easy/factus-easy-sdk": "dev-main" }
}

La URL base del API es fija: https://factuseasy.kreativesofts.com.

Autenticación

<?php
require __DIR__.'/vendor/autoload.php';

use FactusEasy\FactusEasy;

$sdk = new FactusEasy();

// Registrar nuevo usuario (opcional)
$sdk->auth()->register('Nombre', '[email protected]', 'contraseña');

// Iniciar sesión
$sdk->auth()->login('[email protected]', 'contraseña');

// Cerrar sesión
$sdk->auth()->logout();

Error: 401AuthenticationException.

Empresas

<?php
use FactusEasy\Exceptions\ValidationException;

// Listar empresas
$companies = $sdk->company()->list();

// Crear empresa
$created = $sdk->company()->create([
    'ruc' => '1234567890001',
    'business_name' => 'Mi Empresa',
    'email' => '[email protected]',
]);

// Actualizar
$updated = $sdk->company()->update('1234567890001', [
    'business_name' => 'Mi Empresa S.A.',
]);

// Subir certificado .p12
$sdk->company()->uploadCertificate('1234567890001', __DIR__.'/firma.p12', 'CONTRASENA_DEL_P12');

// Subir logo
$sdk->company()->uploadLogo('1234567890001', __DIR__.'/logo.png');

Errores: 404NotFoundException, 422ValidationException.

Documentos

IVA 15%: usar codigo 2 y codigoPorcentaje 4 en los impuestos del detalle.

Emitir factura (tipo 01)

<?php
$invoice = $sdk->document()->register([
    'ruc' => '1234567890001',
    'tipo' => '01',
    'id_externo' => 'fact-' . time(),
    'factura' => [
        'fecha' => date('d/m/Y'),
        'establecimiento' => '001',
        'puntoEmision' => '001',
        'secuencial' => '000000001',
        'descuento' => 0,
        'propina' => 0,
        'total' => 115.00,
        'cliente' => [
            'tipoIdentificacion' => '05',
            'documento' => '1712345678',
            'nombre' => 'Cliente de Prueba',
        ],
    ],
    'detalles' => [[
        'codigoPrincipal' => 'P001',
        'descripcion' => 'Producto A',
        'cantidad' => 1,
        'precioUnitario' => 100.00,
        'descuento' => 0,
        'precioTotalSinImpuesto' => 100.00,
        'impuestos' => [[
            'codigo' => '2',
            'codigoPorcentaje' => '4',
            'tarifa' => 15.00,
            'baseImponible' => 100.00,
            'valor' => 15.00,
        ]],
    ]],
    'pagos' => [
        ['formaPago' => '01', 'total' => 115.00],
    ],
    'notificaciones' => [
        'email' => null,
        'webhook_url' => null,
    ],
], $sdk->idempotency());

// Consultar estado y descargar RIDE
$accessKey = $invoice['data']['access_key'] ?? null;
if ($accessKey) {
    $status = $sdk->document()->status($accessKey);
    $sdk->document()->downloadRideTo($accessKey, '1234567890001', __DIR__.'/rides/factura.pdf');
}

Registro por lotes (registerBatch)

<?php
$batch = $sdk->document()->registerBatch([
    // arreglo de documentos (misma estructura que register)
], $sdk->idempotency());

Nota de crédito (tipo 04)

<?php
$creditNote = $sdk->document()->register([
    'ruc' => '1234567890001',
    'tipo' => '04',
    'id_externo' => 'nc-' . time(),
    'notaCredito' => [
        'fecha' => date('d/m/Y'),
        'establecimiento' => '001',
        'puntoEmision' => '001',
        'secuencial' => '000000001',
        'tipoIdentificacion' => '05',
        'documento' => '1712345678',
        'nombre' => 'Cliente de Prueba',
        'total' => 115.00,
    ],
    'detalles' => [[
        'codigoPrincipal' => 'P001',
        'descripcion' => 'Producto A',
        'cantidad' => 1,
        'precioUnitario' => 100.00,
        'descuento' => 0,
        'precioTotalSinImpuesto' => 100.00,
        'impuestos' => [[
            'codigo' => '2',
            'codigoPorcentaje' => '4',
            'tarifa' => 15.00,
            'baseImponible' => 100.00,
            'valor' => 15.00,
        ]],
    ]],
    'pagos' => [
        ['formaPago' => '01', 'total' => 115.00],
    ],
], $sdk->idempotency());

Comprobante de retención (tipo 07)

<?php
$retention = $sdk->document()->register([
    'ruc' => '1234567890001',
    'tipo' => '07',
    'id_externo' => 'ret-' . time(),
    'retencion' => [
        'fecha' => date('d/m/Y'),
        'establecimiento' => '001',
        'puntoEmision' => '001',
        'secuencial' => '000000001',
        'tipoIdentificacion' => '05',
        'documento' => '1712345678',
        'nombre' => 'Proveedor de Prueba',
        'total' => 100.00,
    ],
    'detalles' => [[
        'codigoPrincipal' => 'S001',
        'descripcion' => 'Servicio Profesional',
        'cantidad' => 1,
        'precioUnitario' => 100.00,
        'descuento' => 0,
        'precioTotalSinImpuesto' => 100.00,
        'impuestos' => [[
            'codigo' => '2',
            'codigoPorcentaje' => '4',
            'tarifa' => 15.00,
            'baseImponible' => 100.00,
            'valor' => 15.00,
        ]],
    ]],
], $sdk->idempotency());

Errores

Cada código HTTP tiene su propia excepción. Todas extienden de FactusEasyException.

Excepción Código Causa
AuthenticationException401Token inválido o expirado
NotFoundException404Recurso no encontrado
ConflictException409Idempotencia duplicada
ValidationException422Datos inválidos (getErrors())
RateLimitException429Demasiadas solicitudes

Ejemplos

El SDK incluye ejemplos listos para ejecutar en la carpeta examples/ del repositorio:

  • Auth: login.php, register.php, logout.php
  • Empresas: list.php, create.php, update.php, certificate.php, logo.php
  • Documentos: register-invoice.php, register-credit-note.php, register-retention.php, batch.php, status.php, ride.php

Recursos adicionales:

FAQ

¿Puedo usar el SDK sin Laravel?

Sí. Es PHP puro con Guzzle. Solo necesitas Composer y PHP 8.3+.

¿Cómo reintento un POST de forma segura?

Usa $sdk->idempotency(). Si obtienes 409 (ConflictException), el servidor ya procesó esa solicitud.

¿Dónde se guarda el RIDE PDF?

Usa downloadRideTo($accessKey, $ruc, $destino). El directorio debe existir y ser escribible.

¿El SDK soporta lotes?

Sí, con registerBatch().

¿Puedo cambiar la URL base del API?

No. La URL base es fija: https://factuseasy.kreativesofts.com.

Solución de problemas

"Could not find a matching version"

Usa composer require factus-easy/factus-easy-sdk:^0.1. Si usas VCS, agrega "minimum-stability": "dev".

"Failed to clone" al usar VCS

Agrega "config": { "github-protocols": ["https"] } y verifica que Git esté instalado.

PHP 8.3 requerido

Verifica con php -v. Si tienes una versión inferior, actualiza PHP.

Error 401 (AuthenticationException)

Credenciales inválidas. Si aún no tienes cuenta, regístrate aquí.

Permisos al descargar RIDE

Asegúrate de que el directorio de destino exista y tenga permisos de escritura.