SDK oficial para integrar la API de Factus Easy — Facturación Electrónica SRI Ecuador.
Consulta la documentación completa de la API en factuseasy.kreativesofts.com/docs
- PHP ^8.3
- GuzzleHttp ^7.0
- Extensión
json - Extensión
mbstring
composer require factus-easy/factus-easy-sdk:^0.1Copia el archivo de ejemplo:
cp .env.test .envEdita .env con tus credenciales:
FACTUS_EASY_EMAIL=tu-email@ejemplo.com
FACTUS_EASY_PASSWORD=tu-contraseña
FACTUS_EASY_DOWNLOAD_DIR=examples/downloadsLa URL base de la API ya está preconfigurada en el SDK. No necesita configurarse.
<?php
require 'vendor/autoload.php';
use FactusEasy\Sdk\FactusEasy;
use FactusEasy\Sdk\Exceptions\ValidationException;
$factus = new FactusEasy();
$factus->auth()->login('email@ejemplo.com', 'password');
// Listar empresas
$companies = $factus->company()->list();
// Emitir factura
$idempotencyKey = $factus->idempotency();
$response = $factus->document()->register($payload, $idempotencyKey);
// Consultar estado de un documento
$status = $factus->document()->status([
'ruc' => '1234567890001',
'external_id' => 'mi-id-externo',
]);src/
├── FactusEasy.php ← Punto de entrada
├── Config.php ← Configuración
├── HttpClient.php ← Cliente HTTP (Guzzle)
├── Resources/ ← Recursos de la API
│ ├── Auth.php → autenticación
│ ├── Company.php → empresas
│ ├── Document.php → documentos electrónicos
│ └── ReceivedDocument.php → documentos recibidos
├── Exceptions/ ← Excepciones
│ ├── FactusEasyException.php (base)
│ ├── AuthenticationException.php (401)
│ ├── ValidationException.php (422)
│ ├── NotFoundException.php (404)
│ ├── ConflictException.php (409)
│ └── RateLimitException.php (429)
├── Resources/ ← Recursos de la API
│ ├── Tax.php → catálogo de impuestos SRI
│ ├── RetentionConfig.php → catálogo de retenciones SRI
│ └── PaymentMethod.php → catálogo de formas de pago SRI
└── Support/ ← Utilidades
├── Idempotency.php → generación de UUID v4
├── TaxCodes.php → códigos de impuestos SRI
├── PercentageCodes.php → códigos de porcentajes SRI
└── PaymentMethods.php → formas de pago SRI
$token = $factus->auth()->login('email@ejemplo.com', 'password');
// → string: token Sanctum (se guarda automáticamente para siguientes requests)$result = $factus->auth()->register(
name: 'Usuario SDK',
email: 'sdk@ejemplo.com',
password: 'MiPassword123',
passwordConfirmation: 'MiPassword123',
);
// → array: ['user' => [...], 'token' => '...']$result = $factus->auth()->logout();
// → bool: true/false$factus->setToken('token-existente');
// Útil si ya tienes un token guardado en sesión o BD$response = $factus->company()->list();
// response['data'] → array de empresas$response = $factus->company()->create([
'ruc' => '1234567890001',
'name' => 'Mi Empresa',
'business_name' => 'Mi Empresa Cía. Ltda.',
'address' => 'Av. Principal 123',
'phone' => '0999999999',
'accounting_required' => 'SI',
'special_taxpayer' => 'NO',
'major_taxpayer' => 'NO',
'email' => 'empresa@ejemplo.com',
]);$response = $factus->company()->update('1234567890001', [
'name' => 'Nombre Actualizado',
// mismos campos que create
]);$response = $factus->company()->uploadCertificate(
ruc: '1234567890001',
filePath: '/ruta/certificado.p12',
password: 'clave-del-certificado',
);$response = $factus->company()->uploadLogo(
ruc: '1234567890001',
filePath: '/ruta/logo.png',
);use FactusEasy\Sdk\Support\TaxCodes;
use FactusEasy\Sdk\Support\PercentageCodes;
use FactusEasy\Sdk\Support\PaymentMethods;
$payload = [
'ruc' => '1234567890001',
'tipo' => '01',
'id_externo' => 'fact-001',
'factura' => [
'fecha' => date('d/m/Y'),
'establecimiento' => '001',
'puntoEmision' => '001',
'secuencial' => '000000001',
'descuento' => 0,
'propina' => 0,
'total' => 11.50,
'cliente' => [
'tipoIdentificacion' => '05',
'documento' => '1712345678',
'nombre' => 'Cliente de Prueba',
'correo' => 'cliente@ejemplo.com',
],
],
'detalles' => [
[
'codigoPrincipal' => 'P001',
'descripcion' => 'Producto A',
'cantidad' => 1,
'precioUnitario' => 10.00,
'descuento' => 0,
'precioTotalSinImpuesto' => 10.00,
'impuestos' => [
[
'codigo' => TaxCodes::IVA,
'codigoPorcentaje' => PercentageCodes::IVA_15,
'tarifa' => 15.00,
'baseImponible' => 10.00,
'valor' => 1.50,
],
],
],
],
'pagos' => [
['formaPago' => PaymentMethods::EFECTIVO, 'total' => 11.50],
],
'notificaciones' => [
'email' => null,
'webhook_url' => null,
],
];
$response = $factus->document()->register($payload, $factus->idempotency());$payload = [
'ruc' => '1234567890001',
'tipo' => '04',
'id_externo' => 'nc-001',
'nota' => [
'fecha' => date('d/m/Y'),
'establecimiento' => '001',
'puntoEmision' => '001',
'secuencial' => '000000001',
'tipo' => '1',
'docModificado' => [
'tipo' => '01',
'numero' => '001-001-000000001',
'fechaEmision' => date('d/m/Y'),
'claveAutorizacion' => '49 dígitos de la factura original',
],
],
'detalles' => [[
'codigoPrincipal' => 'P001',
'descripcion' => 'Producto A - Nota de crédito',
'cantidad' => 1,
'precioUnitario' => 10.00,
'descuento' => 0,
'precioTotalSinImpuesto' => 10.00,
'impuestos' => [[
'codigo' => TaxCodes::IVA,
'codigoPorcentaje' => PercentageCodes::IVA_15,
'tarifa' => 15.00,
'baseImponible' => 10.00,
'valor' => 1.50,
]],
]],
'notificaciones' => ['email' => null, 'webhook_url' => null],
];
$response = $factus->document()->register($payload, $factus->idempotency());$payload = [
'ruc' => '1234567890001',
'tipo' => '07',
'id_externo' => 'ret-001',
'retencion' => [
'fecha' => date('d/m/Y'),
'establecimiento' => '001',
'puntoEmision' => '001',
'secuencial' => '000000001',
'periodoFiscal' => date('m/Y'),
'sujetoRetenido' => [
'tipoIdentificacion' => '04',
'documento' => '1790012345001',
'nombre' => 'Proveedor de Prueba',
],
'total' => 100.00,
],
'detalles' => [[
'codigo' => 1,
'codigoRetencion' => 303,
'baseImponible' => 100.00,
'porcentajeRetener' => 1.00,
'valorRetenido' => 1.00,
'codDocSustento' => '01',
'numDocSustento' => '001-001-000000001',
'fechaEmisionSustento' => date('d/m/Y'),
]],
'notificaciones' => ['email' => null, 'webhook_url' => null],
];
$response = $factus->document()->register($payload, $factus->idempotency());$payload = [
'ruc' => '1234567890001',
'tipo' => '06',
'id_externo' => 'gui-001',
'guia' => [
'fecha' => date('d/m/Y'),
'establecimiento' => '001',
'puntoEmision' => '001',
'secuencial' => '000000001',
'dirEstablecimiento' => 'Av. Siempre Viva',
'dirPartida' => 'Av. Principal 123',
'razonSocialTransportista' => 'Transportes S.A.',
'tipoIdentificacionTransportista' => '04',
'rucTransportista' => '1796875790001',
'rise' => null,
'placa' => 'MCL0827',
'fechaIniTransporte' => date('d/m/Y'),
'fechaFinTransporte' => date('d/m/Y'),
],
'destinatarios' => [[
'identificacionDestinatario' => '1716849140001',
'razonSocialDestinatario' => 'Destinatario de Prueba',
'dirDestinatario' => 'Av. Simon Bolivar S/N',
'motivoTraslado' => 'Venta de mercancía',
'codDocSustento' => '01',
'numDocSustento' => '001-001-000000001',
'fechaEmisionDocSustento' => date('d/m/Y'),
'detalles' => [[
'codigoInterno' => 'P001',
'descripcion' => 'Producto de prueba',
'cantidad' => 10.00,
]],
]],
'notificaciones' => ['email' => null, 'webhook_url' => null],
];
$response = $factus->document()->register($payload, $factus->idempotency());$payload = [
'ruc' => '1234567890001',
'tipo' => '01',
'documentos' => [[
'id_externo' => 'batch-001',
'factura' => [...],
'detalles' => [...],
'pagos' => [...],
'notificaciones' => [...],
]],
];
$response = $factus->document()->registerBatch($payload, $factus->idempotency());// Por external_id
$response = $factus->document()->status([
'ruc' => '1234567890001',
'external_id' => 'fact-001',
]);
// Con filtros y paginación
$response = $factus->document()->status([
'ruc' => '1234567890001',
'status' => 'AUTHORIZED',
'date_from' => '2026-01-01',
'date_to' => '2026-12-31',
'page' => 1,
'per_page' => 20,
]);// En memoria
$pdfContent = $factus->document()->downloadRide($accessKey, $ruc);
file_put_contents('factura.pdf', $pdfContent);
// Directo a disco (streaming, sin cargar en RAM)
$factus->document()->downloadRideTo($accessKey, $ruc, '/ruta/factura.pdf');Los documentos recibidos son comprobantes electrónicos emitidos por tus proveedores hacia tu empresa. Se importan subiendo un archivo TXT (formato SRI) y la plataforma obtiene el XML de cada comprobante desde el SRI de forma automática.
$response = $factus->receivedDocument()->upload(
ruc: '1234567890001',
filePath: '/ruta/documentos-recibidos.txt',
);
// response['data']['id'] → ID del upload (para seguimiento)
// El archivo se procesa en segundo plano (parseo de filas + sincronización XML)$response = $factus->receivedDocument()->list([
'ruc' => '1234567890001',
'sri_document_code' => '01', // optional: 01, 04, 06, 07
'issuer_ruc' => '1790012345001', // optional: RUC del emisor
'access_key' => '49 dígitos', // optional
'upload_id' => 12, // optional: filtrar por upload
'issued_from' => '2026-01-01', // optional
'issued_to' => '2026-12-31', // optional
'has_xml' => true, // optional: true/false
'per_page' => 20, // optional (default 20, max 100)
'page' => 1, // optional
]);
// response['data']['documents'] → lista de documentos
// response['data']['pagination'] → { current_page, per_page, total, last_page }$response = $factus->receivedDocument()->show(
accessKey: '2906202601079184443300110010010000000016775908313',
ruc: '1234567890001',
);// En memoria
$xml = $factus->receivedDocument()->downloadXml($accessKey, $ruc);
file_put_contents('recibido.xml', $xml);// En memoria
$pdf = $factus->receivedDocument()->downloadRide($accessKey, $ruc);
file_put_contents('recibido.pdf', $pdf);
// Directo a disco (streaming, sin cargar en RAM)
$factus->receivedDocument()->downloadRideTo($accessKey, $ruc, '/ruta/recibido.pdf');Estos endpoints son públicos (no requieren autenticación) y retornan los catálogos oficiales del SRI mantenidos por la plataforma. Úsalos para validar códigos antes de emitir documentos o para construir formularios dinámicos.
$response = $factus->tax()->list();
// response['data'] → array de impuestos activos (IVA, ICE, IRBPNR)
// [
// { tax_type: 'IVA', name: '13%', percentage: 13.0, sri_code: '2', sri_percentage_code: '2' },
// { tax_type: 'ICE', name: 'Bebidas Alcohólicas', percentage: 0.0, sri_code: '3', sri_percentage_code: '3031' },
// ...
// ]$response = $factus->retentionConfig()->list();
// response['data'] → array de retenciones activas (IR e IVA)
// [
// { name: 'IRPAT 1.0%', type: 1, code_sri: '340', percentage: 1.0 },
// { name: 'IVA 10%', type: 2, code_sri: '9', percentage: 10.0 },
// ...
// ]
// type: 1 = Impuesto a la Renta (IR) | 2 = IVA$response = $factus->paymentMethod()->list();
// response['data'] → array de formas de pago activas
// [
// { code: '01', name: 'SIN UTILIZACION DEL SISTEMA FINANCIERO', description: null },
// { code: '19', name: 'TARJETA DE CREDITO', description: null },
// ...
// ]use FactusEasy\Sdk\Exceptions\ValidationException;
use FactusEasy\Sdk\Exceptions\AuthenticationException;
use FactusEasy\Sdk\Exceptions\NotFoundException;
use FactusEasy\Sdk\Exceptions\ConflictException;
use FactusEasy\Sdk\Exceptions\RateLimitException;
use FactusEasy\Sdk\Exceptions\FactusEasyException;
try {
$factus->company()->create([...]);
} catch (ValidationException $e) {
echo $e->getMessage();
print_r($e->getErrors()); // errores por campo
} catch (AuthenticationException $e) {
echo 'Token inválido: ' . $e->getMessage();
} catch (NotFoundException $e) {
echo 'Recurso no encontrado: ' . $e->getMessage();
} catch (ConflictException $e) {
echo 'Conflicto de idempotencia: ' . $e->getMessage();
} catch (RateLimitException $e) {
echo 'Demasiadas solicitudes. Reintentar en ' . ($e->getRetryAfter() ?? '?') . 's';
} catch (FactusEasyException $e) {
echo 'Error: ' . $e->getMessage();
print_r($e->getContext());
}| Excepción | Código HTTP | Cuándo ocurre |
|---|---|---|
AuthenticationException |
401 | Token inválido o expirado |
NotFoundException |
404 | Recurso no encontrado |
ConflictException |
409 | Idempotencia duplicada o conflicto |
ValidationException |
422 | Datos inválidos (getErrors() por campo) |
RateLimitException |
429 | Demasiadas solicitudes (getRetryAfter()) |
FactusEasyException |
4xx/5xx | Otros errores (getContext() con detalles) |
- El token tiene validez de 24h. Vuelve a llamar a
auth()->login()o renueva consetToken(). - Verifica que email y password en
.envsean correctos.
- Revisa
$e->getErrors()que devuelve un array con los errores por campo. - Causas comunes: fecha debe ser hoy (
d/m/Y), impuesto/porcentaje no existe en catálogo, secuencial duplicado, RUC sin certificado.
- El
Idempotency-Keyya fue usado con otro payload o la misma solicitud ya está en proceso. - Genera una nueva key con
$factus->idempotency()o espera a que finalice el proceso anterior.
- Has superado el límite de solicitudes por minuto. Revisa
$e->getRetryAfter()para saber cuándo reintentar.
- Verifica que el RUC exista, la empresa esté activa y el access key sea correcto de 49 dígitos.
Genera claves de idempotencia para proteger contra duplicados:
$key = $factus->idempotency(); // vía helper
$key = Idempotency::new(); // vía clase estática
// Ejemplo: "5973bb92-826c-40e9-8fab-adb0de003364"$factus->setRequestId('mi-correlativo-001');
// Envía header X-Request-Id a la API para correlacionar logsEvita magic strings en los payloads:
use FactusEasy\Sdk\Support\DocumentTypes;
use FactusEasy\Sdk\Support\TaxCodes;
use FactusEasy\Sdk\Support\PercentageCodes;
use FactusEasy\Sdk\Support\PaymentMethods;
DocumentTypes::FACTURA // '01'
DocumentTypes::NOTA_CREDITO // '04'
DocumentTypes::GUIA_REMISION // '06'
DocumentTypes::RETENCION // '07'
TaxCodes::IVA // '2'
TaxCodes::ICE // '3'
TaxCodes::IRBPNR // '5'
PercentageCodes::IVA_0 // '0'
PercentageCodes::IVA_12 // '2'
PercentageCodes::IVA_14 // '3'
PercentageCodes::IVA_15 // '4'
PaymentMethods::EFECTIVO // '01'
PaymentMethods::TRANSFERENCIA // '24'
PaymentMethods::TARJETA_CREDITO // '19'| Método SDK | Endpoint | Auth |
|---|---|---|
auth()->register() |
POST /api/register |
No |
auth()->login() |
POST /api/login |
No |
auth()->logout() |
POST /api/logout |
Sí |
company()->list() |
GET /api/companie/list |
Sí |
company()->create() |
POST /api/companie/register |
Sí |
company()->update() |
PUT /api/companie/update/{ruc} |
Sí |
company()->uploadCertificate() |
POST /api/companie/certificate |
Sí |
company()->uploadLogo() |
POST /api/companie/upload/logo |
Sí |
document()->register() |
POST /api/document/register |
Sí |
document()->registerBatch() |
POST /api/document/batch/register |
Sí |
document()->status() |
GET /api/document/status |
Sí |
document()->downloadRide() |
GET /api/document/{accessKey}/ride |
Sí |
document()->downloadRideTo() |
GET /api/document/{accessKey}/ride |
Sí |
receivedDocument()->upload() |
POST /api/document/received/upload |
Sí |
receivedDocument()->list() |
GET /api/document/received |
Sí |
receivedDocument()->show() |
GET /api/document/received/{accessKey} |
Sí |
receivedDocument()->downloadXml() |
GET /api/document/received/{accessKey}/xml |
Sí |
receivedDocument()->downloadRide() |
GET /api/document/received/{accessKey}/ride |
Sí |
receivedDocument()->downloadRideTo() |
GET /api/document/received/{accessKey}/ride |
Sí |
tax()->list() |
GET /api/sri-taxes/list |
No |
retentionConfig()->list() |
GET /api/retention-configs/list |
No |
paymentMethod()->list() |
GET /api/payment-methods/list |
No |
| Variable | Obligatorio | Default | Descripción |
|---|---|---|---|
FACTUS_EASY_EMAIL |
Sí | — | Email para autenticación |
FACTUS_EASY_PASSWORD |
Sí | — | Contraseña para autenticación |
FACTUS_EASY_DOWNLOAD_DIR |
No | examples/ |
Carpeta donde se guardan los RIDE PDF |
composer example:login # php examples/auth/login.php
composer example:register # php examples/auth/register.php
composer example:companies # php examples/companies/list.php
composer example:invoice # php examples/documents/register-invoice.php
composer example:guia # php examples/documents/register-guia.php
composer example:status # php examples/documents/status.php
composer example:ride # php examples/documents/ride.php
composer example:certificate # php examples/companies/certificate.php
composer example:taxes # php examples/taxes/list.php
composer example:retention-configs # php examples/retention-configs/list.php
composer example:payment-methods # php examples/payment-methods/list.php
composer example:received-upload # php examples/received-documents/upload.php
composer example:received-list # php examples/received-documents/list.php
composer example:received-xml # php examples/received-documents/xml.php# Auth
php examples/auth/login.php
php examples/auth/register.php
php examples/auth/logout.php
# Empresas
php examples/companies/list.php
php examples/companies/create.php
php examples/companies/update.php
php examples/companies/certificate.php
php examples/companies/logo.php
# Documentos
php examples/documents/register-invoice.php
php examples/documents/register-credit-note.php
php examples/documents/register-retention.php
php examples/documents/register-guia.php
php examples/documents/batch.php
php examples/documents/status.php
php examples/documents/ride.php
# Documentos recibidos
php examples/received-documents/upload.php
php examples/received-documents/list.php
php examples/received-documents/xml.php
# Catalogos SRI
php examples/taxes/list.php
php examples/retention-configs/list.php
php examples/payment-methods/list.phpgit clone https://github.com/dj-Andres/Factus-Easy-SDK.git
cd factus-easy-sdk
composer install
cp .env.test .env
# Editar .env con credenciales reales
php examples/companies/list.phpMIT