1. Go to this page and download the library: Download schoolaid/fel library. Choose the download type require.
2. Extract the ZIP file and open the index.php.
3. Add this code to the index.php.
<?php
require_once('vendor/autoload.php');
/* Start to develop here. Best regards https://php-download.com/ */
schoolaid / fel example snippets
return [
'provider' => env('FEL_PROVIDER', 'infile'),
'username' => env('FEL_USERNAME'),
'api_key' => env('FEL_LLAVE_FIRMA', env('FEL_KEY')), // llave del firmador (viaja como llaveFirma)
'signature_key' => env('FEL_LLAVE_API', env('FEL_PASSWORD')), // llave del API REST (viaja como llaveApi)
'provider_config' => [
'base_url' => env('FEL_BASE_URL', 'https://certificador.feel.com.gt/fel/procesounificado/transaccion/v2/xml'),
'certify_url' => env('FEL_CERTIFY_URL'),
'status_url' => env('FEL_STATUS_URL'),
'cancel_url' => env('FEL_CANCEL_URL'),
'timeout' => env('FEL_TIMEOUT', 30),
'verify_ssl' => env('FEL_VERIFY_SSL', true),
'identifier' => env('FEL_IDENTIFIER'), // id único por transacción — mejor setIdentifier() por documento
],
];
use Schoolaid\Fel\Config\FelConfig;
// Opción 3A (recomendada): constructor con nombres veraces
$config = FelConfig::forInfile(
username: 'tu_usuario_infile',
llaveFirma: 'tu_llave_de_firma', // llave del firmador
llaveApi: 'tu_llave_api', // llave del API REST
providerConfig: [
'base_url' => 'https://certificador.feel.com.gt/fel/procesounificado/transaccion/v2/xml',
'certify_url' => 'https://certificador.feel.com.gt/fel/procesounificado/transaccion/v2/xml',
'cancel_url' => 'https://certificador.feel.com.gt/fel/procesounificado/transaccion/v2/xml',
'identifier' => 'orden-0001' // id único por transacción (opcional)
]
);
// Constructor histórico (nombres invertidos, ver nota de credenciales)
$config = new FelConfig(
provider: 'infile',
username: 'tu_usuario_infile',
apiKey: 'tu_llave_de_firma', // viaja como llaveFirma
signatureKey: 'tu_llave_api', // viaja como llaveApi
providerConfig: [
'base_url' => 'https://certificador.feel.com.gt/fel/procesounificado/transaccion/v2/xml',
'certify_url' => 'https://certificador.feel.com.gt/fel/procesounificado/transaccion/v2/xml',
'cancel_url' => 'https://certificador.feel.com.gt/fel/procesounificado/transaccion/v2/xml',
'timeout' => 30,
'verify_ssl' => true,
'identifier' => 'orden-0001' // id único por transacción (opcional)
]
);
// Opción 3B: Desde un array
$credenciales = [
'provider' => 'infile',
'username' => 'tu_usuario_infile',
'api_key' => 'tu_llave_de_firma', // viaja como llaveFirma
'signature_key' => 'tu_llave_api', // viaja como llaveApi
'provider_config' => [
'base_url' => 'https://certificador.feel.com.gt/fel/procesounificado/transaccion/v2/xml',
'certify_url' => 'https://certificador.feel.com.gt/fel/procesounificado/transaccion/v2/xml',
'cancel_url' => 'https://certificador.feel.com.gt/fel/procesounificado/transaccion/v2/xml',
'timeout' => 30,
'verify_ssl' => true,
'identifier' => 'orden-0001' // id único por transacción
]
];
$config = FelConfig::fromArray($credenciales);
// Opción 3C: Con setters (útil para modificar configuración existente)
$config = new FelConfig();
$config->setProvider('infile')
->setUsername('tu_usuario_infile')
->setLlaveFirma('tu_llave_de_firma') // llave del firmador
->setLlaveApi('tu_llave_api') // llave del API REST
->setIdentifier('orden-0001') // id único por transacción (control de duplicidad)
->setProviderConfig([
'base_url' => 'https://certificador.feel.com.gt/fel/procesounificado/transaccion/v2/xml',
'certify_url' => 'https://certificador.feel.com.gt/fel/procesounificado/transaccion/v2/xml',
'cancel_url' => 'https://certificador.feel.com.gt/fel/procesounificado/transaccion/v2/xml',
'timeout' => 30,
'verify_ssl' => true,
]);
use Schoolaid\Fel\Config\FelConfig;
// Obtener credenciales de la base de datos
$empresa = Empresa::find($empresaId);
$config = new FelConfig(
provider: 'infile',
username: $empresa->fel_username,
apiKey: $empresa->fel_api_key,
signatureKey: $empresa->fel_signature_key,
providerConfig: [
'base_url' => 'https://certificador.feel.com.gt/fel/procesounificado/transaccion/v2/xml',
'certify_url' => 'https://certificador.feel.com.gt/fel/procesounificado/transaccion/v2/xml',
'cancel_url' => 'https://certificador.feel.com.gt/fel/procesounificado/transaccion/v2/xml',
'timeout' => 30,
'verify_ssl' => true,
'identifier' => 'orden-' . $ordenId // id único por transacción, uno distinto por documento
]
);
// Usar la configuración para certificar
$certify = new FelCertify($invoice, $config);
$response = $certify->execute();
use Schoolaid\Fel\Config\FelConfig;
class FelService
{
public function certifyForCompany(Invoice $invoice, Company $company)
{
// Crear configuración específica para esta empresa
$config = new FelConfig(
provider: 'infile',
username: $company->fel_credentials['username'],
apiKey: $company->fel_credentials['api_key'],
signatureKey: $company->fel_credentials['signature_key'],
providerConfig: [
'base_url' => 'https://certificador.feel.com.gt/fel/procesounificado/transaccion/v2/xml',
'certify_url' => 'https://certificador.feel.com.gt/fel/procesounificado/transaccion/v2/xml',
'cancel_url' => 'https://certificador.feel.com.gt/fel/procesounificado/transaccion/v2/xml',
'timeout' => 30,
'verify_ssl' => true,
'identifier' => 'orden-' . $orderId // id único por transacción, uno distinto por documento
]
);
$certify = new FelCertify($invoice, $config);
return $certify->execute();
}
}
// Uso
$felService = new FelService();
$response = $felService->certifyForCompany($invoice, $empresa);
use Schoolaid\Fel\Config\FelConfig;
use Schoolaid\Fel\Certification\FelCertificationService;
try {
// Desde .env
$config = FelConfig::fromConfig();
// O directamente
$config = new FelConfig(
provider: 'infile',
username: 'tu_usuario',
apiKey: 'tu_api_key',
signatureKey: 'tu_signature_key',
providerConfig: [
'base_url' => 'https://certificador.feel.com.gt/fel/procesounificado/transaccion/v2/xml',
'timeout' => 30,
'verify_ssl' => true
]
);
$service = new FelCertificationService($config);
// Si no hay excepciones, la configuración es válida
echo "Configuración correcta";
} catch (\Exception $e) {
echo "Error de configuración: " . $e->getMessage();
}
use Schoolaid\Fel\Config\FelConfig;
use Schoolaid\Fel\Actions\FelCertify;
use Schoolaid\Fel\Models\Invoice;
use Schoolaid\Fel\Models\FelIssuer;
use Schoolaid\Fel\Models\FelReceiver;
use Schoolaid\Fel\Models\FelAddress;
use Schoolaid\Fel\Models\FelItems;
use Schoolaid\Fel\Models\FelItem;
use Schoolaid\Fel\Models\FelPhrases;
use Schoolaid\Fel\Models\FelPhrase;
use Schoolaid\Fel\Models\FelTotals;
use Schoolaid\Fel\Enums\DocumentTypeEnum;
use Schoolaid\Fel\Enums\CurrencyEnum;
use Schoolaid\Fel\Enums\IVAAffiliationTypeEnum;
// 1. Configurar credenciales directamente (sin .env)
$config = new FelConfig(
provider: 'infile',
username: 'mi_usuario_infile',
apiKey: 'mi_api_key',
signatureKey: 'mi_signature_key',
providerConfig: [
'base_url' => 'https://certificador.feel.com.gt/fel/procesounificado/transaccion/v2/xml',
'certify_url' => 'https://certificador.feel.com.gt/fel/procesounificado/transaccion/v2/xml',
'cancel_url' => 'https://certificador.feel.com.gt/fel/procesounificado/transaccion/v2/xml',
'timeout' => 30,
'verify_ssl' => true,
'identifier' => 'orden-0001' // id único por transacción
]
);
// 2. Crear la factura
$issuer = new FelIssuer(
'[email protected]',
'1',
'12345678',
'Mi Empresa S.A.',
IVAAffiliationTypeEnum::General,
'Mi Empresa',
new FelAddress('Avenida Reforma 1-1 Zona 10', '01010', 'Guatemala', 'Guatemala', 'GT')
);
$receiver = new FelReceiver(
'CF',
null,
'Consumidor Final',
new FelAddress('Ciudad', '01001', 'Guatemala', 'Guatemala', 'GT')
);
$items = new FelItems([
new FelItem(1, 'B', 100.0, 'UND', 'Producto de prueba', 100.0, 1, 0.0, [], 100.0)
]);
$invoice = new Invoice(
DocumentTypeEnum::LOCAL_INVOICE,
now()->format('Y-m-d\TH:i:s'),
CurrencyEnum::QUETZAL,
$issuer,
$receiver,
new FelPhrases([new FelPhrase(1, 1)]),
$items,
new FelTotals(grandTotal: 100.0)
);
// 3. Certificar usando la configuración directa
$certify = new FelCertify($invoice, $config);
$response = $certify->execute();
// 4. Procesar respuesta
if ($response->isSuccessful()) {
echo "Factura certificada: " . $response->getUuid();
} else {
echo "Error: " . implode(', ', $response->getErrors());
}
use Schoolaid\Fel\Enums\CurrencyEnum;
use Schoolaid\Fel\Enums\DocumentTypeEnum;
use Schoolaid\Fel\Enums\IVAAffiliationTypeEnum;
use Schoolaid\Fel\Models\FelAddenda;
use Schoolaid\Fel\Models\FelAddress;
use Schoolaid\Fel\Models\FelIssuer;
use Schoolaid\Fel\Models\FelItem;
use Schoolaid\Fel\Models\FelItems;
use Schoolaid\Fel\Models\FelPhrase;
use Schoolaid\Fel\Models\FelPhrases;
use Schoolaid\Fel\Models\FelReceiver;
use Schoolaid\Fel\Models\FelTotals;
use Schoolaid\Fel\Models\Invoice;
use Schoolaid\Fel\Actions\FelGenerate;
use Schoolaid\Fel\Actions\FelCertify;
use Schoolaid\Fel\Config\FelConfig;
// Configurar datos básicos
$issuerAddress = new FelAddress(
'Avenida Reforma 15-85 Zona 10, Edificio Torre Internacional Nivel 11',
'01001',
'Guatemala',
'Guatemala',
'GT'
);
$issuer = new FelIssuer(
'[email protected]',
'1',
'12345678', // NIT del emisor
'Empresa, S.A.',
IVAAffiliationTypeEnum::General,
'Mi Empresa',
$issuerAddress
);
$receiverAddress = new FelAddress(
'Avenida Las Américas 7-62 Zona 13',
'01013',
'Guatemala',
'Guatemala',
'GT'
);
$receiver = new FelReceiver(
'87654321', // NIT del receptor (o CF para Consumidor Final)
'[email protected]',
'Cliente Frecuente, S.A.',
$receiverAddress
);
// Frases requeridas para FACT
$phrases = new FelPhrases([
new FelPhrase(1, 1) // Frase 1 y Escenario 1 - Afecta IVA
]);
// Productos/servicios
$items = new FelItems([
new FelItem(
1, // Número de línea
'B', // Bien (B) o Servicio (S)
500.0, // Precio unitario sin IVA
'UND', // Unidad de medida
'Computadora portátil HP Probook 450 G8', // Descripción
500.0, // Precio (sin impuestos)
1, // Cantidad
0.0, // Descuento
[], // Los impuestos se calcularán automáticamente
500.0 // Total de línea
),
new FelItem(
2, // Número de línea
'S', // Bien (B) o Servicio (S)
200.0, // Precio unitario sin IVA
'UND', // Unidad de medida
'Servicio de instalación y configuración', // Descripción
200.0, // Precio (sin impuestos)
1, // Cantidad
0.0, // Descuento
[], // Los impuestos se calcularán automáticamente
200.0 // Total de línea
)
]);
// Totales con IVA
$totals = new FelTotals(
grandTotal: 700.0 // Total incluyendo impuestos (los demás valores se calcularán automáticamente)
);
// Addendas (información adicional)
$addendas = [
new FelAddenda(
'http://www.sat.gob.gt/face2/ComplementoFacturaEspecial/0.1.0',
'ReferenciaInterna',
'Orden #FT-2023-1234'
),
new FelAddenda(
'http://www.sat.gob.gt/face2/ComplementoFacturaEspecial/0.1.0',
'DatosCliente',
'Proyecto: Implementación ERP'
)
];
// Crear la factura (FACT)
$invoice = new Invoice(
DocumentTypeEnum::LOCAL_INVOICE, // FACT - Factura local
now()->format('Y-m-d\TH:i:s'),
CurrencyEnum::QUETZAL,
$issuer,
$receiver,
$phrases,
$items,
$totals,
$addendas
);
// Certificar
$config = FelConfig::fromConfig();
$certify = new FelCertify($invoice, $config);
$response = $certify->execute();
// Procesar respuesta
if ($response->isSuccessful()) {
$uuid = $response->getUuid();
$serie = $response->getSerial();
$numero = $response->getNumber();
$fecha = $response->getCertificationDate();
$xmlCertificado = $response->getCertifiedXml();
// Guardar los datos en tu base de datos
echo "Factura certificada exitosamente: {$serie}-{$numero}";
} else {
$errores = $response->getErrors();
echo "Error al certificar: " . implode(', ', $errores);
}
// El receptor debe tener 'CF' como ID
$receiver = new FelReceiver(
'CF', // Consumidor Final
null, // Email opcional
'Consumidor Final',
$receiverAddress
);
// El resto es igual a una factura normal
$invoice = new Invoice(
DocumentTypeEnum::LOCAL_INVOICE,
now()->format('Y-m-d\TH:i:s'),
CurrencyEnum::QUETZAL,
$issuer,
$receiver,
$phrases,
$items,
$totals
);
use Schoolaid\Fel\Enums\DocumentTypeEnum;
// Receptor en el extranjero
$receiver = new FelReceiver(
'EXPORTACION', // ID para exportaciones
'[email protected]',
'Cliente Internacional Inc.',
$receiverAddress
);
// Frases para exportación (sin IVA)
$phrases = new FelPhrases([
new FelPhrase(2, 1) // Frase 2 - Exento de IVA
]);
// Items (el precio es el total, no se calcula IVA)
$items = new FelItems([
new FelItem(
1,
'B',
1000.0, // Precio = Total (sin IVA)
'UND',
'Producto para exportación',
1000.0,
1,
0.0,
[],
1000.0
)
]);
$totals = new FelTotals(grandTotal: 1000.0);
// Crear factura de exportación
$invoice = new Invoice(
DocumentTypeEnum::EXPORT_INVOICE, // FEXP
now()->format('Y-m-d\TH:i:s'),
CurrencyEnum::DOLLAR, // Puede ser USD para exportaciones
$issuer,
$receiver,
$phrases,
$items,
$totals
);
use Schoolaid\Fel\Enums\DocumentTypeEnum;
use Schoolaid\Fel\Models\FelReferenceNote;
// Referencia a la factura original (obligatoria). Los cinco datos vienen del
// CertificationResponse con que se certificó el DTE origen: getUuid(),
// getSeries() y getNumber() (serie y número NO se derivan del UUID; el
// sandbox de INFILE, por ejemplo, emite la serie "**PRUEBAS**").
$reference = new FelReferenceNote(
'12345678-1234-1234-1234-123456789012', // UUID (autorización) del DTE origen
'2025-03-15', // Fecha de emisión del DTE origen
'Devolución de mercadería', // Motivo del ajuste
'A1B2C3D4', // Serie del DTE origen (getSeries)
'1234567890' // Número del DTE origen (getNumber)
);
$invoice = new Invoice(
DocumentTypeEnum::CREDIT_NOTE, // NCRE (para NDEB usa DEBIT_NOTE)
now()->format('Y-m-d\TH:i:s'),
CurrencyEnum::QUETZAL, // Debe ser la misma moneda del DTE origen
$issuer, // Mismo NIT emisor que el DTE origen
$receiver, // Mismo receptor que el DTE origen
$phrases,
$items, // Items a acreditar (montos positivos)
$totals
);
$invoice->setReferenceNote($reference);
$reference = new FelReferenceNote(
'1364585227', // Número de resolución de autorización
'2018-05-20',
'Anulación parcial',
'5AAE0F7A', // Serie del documento origen
'1364585227', // Número del documento origen
oldRegime: true // Emite RegimenAntiguo="Antiguo"
);
use Schoolaid\Fel\Enums\DocumentTypeEnum;
use Schoolaid\Fel\Enums\IVAAffiliationTypeEnum;
// Emisor pequeño contribuyente
$issuer = new FelIssuer(
'[email protected]',
'1',
'12345678',
'Pequeño Negocio',
IVAAffiliationTypeEnum::PEQ, // Pequeño contribuyente
'Mi Pequeño Negocio',
$issuerAddress
);
// Frases para pequeño contribuyente
$phrases = new FelPhrases([
new FelPhrase(4, 1) // Frase específica para pequeños contribuyentes
]);
$invoice = new Invoice(
DocumentTypeEnum::SMALL_TAXPAYER_INVOICE, // FPEQ
now()->format('Y-m-d\TH:i:s'),
CurrencyEnum::QUETZAL,
$issuer,
$receiver,
$phrases,
$items,
$totals
);
use Schoolaid\Fel\Enums\DocumentTypeEnum;
$phrases = new FelPhrases([
new FelPhrase(3, 1) // Frase para donaciones
]);
$invoice = new Invoice(
DocumentTypeEnum::DONATION_RECEIPT, // RDON
now()->format('Y-m-d\TH:i:s'),
CurrencyEnum::QUETZAL,
$issuer,
$receiver,
$phrases,
$items,
$totals
);
use Schoolaid\Fel\Actions\FelCancel;
use Schoolaid\Fel\Models\Cancellation;
$cancellation = new Cancellation(
uuid: '12345678-1234-1234-1234-123456789012', // UUID de la factura a cancelar
nitIssuer: '12345678', // NIT del emisor
idReceiver: '87654321', // NIT o CF del receptor
reason: 'Anulación por devolución de mercadería',
dateTime: now()->format('Y-m-d\TH:i:s')
);
$config = FelConfig::fromConfig();
$cancelAction = new FelCancel($cancellation, $config);
$response = $cancelAction->execute();
if ($response->isSuccessful()) {
echo "Factura cancelada exitosamente";
} else {
echo "Error: " . implode(', ', $response->getErrors());
}
use Schoolaid\Fel\Actions\FelGenerate;
$generate = new FelGenerate($invoice);
$xml = $generate->generateXml();
// Guardar el XML o procesarlo según necesites
file_put_contents('factura.xml', $xml);
use Schoolaid\Fel\Certification\Exceptions\CertificationException;
use Schoolaid\Fel\Certification\Exceptions\AuthenticationException;
try {
$certify = new FelCertify($invoice, $config);
$response = $certify->execute();
if ($response->isSuccessful()) {
// Éxito
$uuid = $response->getUuid();
} else {
// Errores de validación de INFILE
foreach ($response->getErrors() as $error) {
\Log::error("Error FEL: {$error}");
}
}
} catch (AuthenticationException $e) {
// Error de autenticación con INFILE
\Log::error("Error de autenticación: " . $e->getMessage());
} catch (CertificationException $e) {
// Otros errores de certificación
\Log::error("Error de certificación: " . $e->getMessage());
} catch (\Exception $e) {
// Errores generales
\Log::error("Error general: " . $e->getMessage());
}
// Frase 1: Sujeto a pagos trimestrales de IVA
new FelPhrase(1, 1)
// Frase 2: Exento de IVA (exportaciones)
new FelPhrase(2, 1)
// Frase 3: Donaciones
new FelPhrase(3, 1)
// Frase 4: Pequeño contribuyente
new FelPhrase(4, 1)