Guía de inicio

Tres caminos al mismo motor. Los tres producen el mismo XML: el CI lo compara para cada uno de los 12 casos de fase 1.

Antes de empezar

PHP

Paquete Composer kembec/facturacion-electronica-sunat-sdk, PHP 7.4 o posterior, sin extensiones además de json. Cada llamada ejecuta el binario sunat-sdk una vez.

Próximamente. El paquete aún no está publicado en Packagist, y el binario tampoco se distribuye todavía. La instalación de abajo es como será.

composer require kembec/facturacion-electronica-sunat-sdk
# el binario sunat-sdk debe estar en una ruta ejecutable, por ejemplo /usr/local/bin/sunat-sdk
use Kembec\SunatSdk\SunatSdk;
use Kembec\SunatSdk\SigningKey;
use Kembec\SunatSdk\SolCredentials;

$sdk = new SunatSdk('/usr/local/bin/sunat-sdk', 120.0);     // binary path, timeout per call in seconds

$built  = $sdk->build($document);                             // array, object or JSON string (docs/input-model.md)
$signed = $sdk->sign($built->getXml(), new SigningKey('/secure/cert.pem', '/secure/key.pem'));
$result = $sdk->send($built->getFileName(), $signed->getXml(),
    new SolCredentials($rucAndSolUser, $solPassword), $sendBillEndpoint);

if ($result->isFault()) {
    $result->getFault()->getCode();                           // e.g. "1033", with getClass()
} else {
    $result->getCdr()->isAccepted();                          // response code, notes, class
}

$sdk->status($ruc, '01', 'F001', 123, $credentials, $statusEndpoint);
$sdk->zip($fileName, $xml);                                   // ZipResult
$sdk->cdr($cdrZipOrXmlBytes);                                 // Cdr

Las excepciones y el manejo de errores están en el README del binding, en el commit 59f651b.

JavaScript con WebAssembly

El mismo núcleo compilado a WebAssembly, con build y sign en memoria. Las entradas y salidas tienen la forma del CLI. Los errores llegan como Error de JavaScript con el mensaje del CLI.

Próximamente. El nombre previsto del paquete npm es @kembec/facturacion-electronica-sunat-sdk, alineado con el de Composer. No está publicado.

// Próximamente: el paquete npm todavía no está publicado.
import { build, sign } from '@kembec/facturacion-electronica-sunat-sdk';

const factura = JSON.parse(facturaTexto);                 // docs/input-model.md
const built = JSON.parse(build(JSON.stringify(factura))); // { file_name, xml }
const signed = JSON.parse(sign(built.xml, certPem, keyPem));
// signed: { xml, digest_value, signature_value }

El CI construye el binding con wasm-bindgen para Node 22 y firma los 12 fixtures de fase 1 con él.

Línea de comandos

El binario sunat-sdk lee JSON por la entrada estándar y escribe JSON por la salida estándar, una llamada por comando. Si algo falla, sale con código 1 y escribe {"error": "..."} en el error estándar.

1. Construir el XML

sunat-sdk build < factura.json
# {"file_name":"20000000001-01-F001-1","xml":"<?xml version=\"1.0\" encoding=\"utf-8\"?>..."}

2. Firmar

sunat-sdk sign --cert cert.pem --key key.pem < firma.json
# firma.json: {"xml": "<XML sin firmar>", "signature_id": "signatureKG"}
# salida: {"xml": "<XML firmado>", "digest_value": "...", "signature_value": "..."}

3. Enviar a la SUNAT

send recibe el mismo JSON que zip: el nombre del archivo y el XML firmado. Las credenciales se leen del entorno, no de la línea de comandos, para que no queden en el historial.

export SUNAT_ENDPOINT='<URL del servicio de beta o producción, ver Paso a producción>'
export SUNAT_SOL_USER='<RUC><usuario SOL secundario>'
export SUNAT_SOL_PASSWORD='<clave>'
sunat-sdk send < comprobante.json
# comprobante.json: {"name": "20000000001-01-F001-1", "xml": "<XML firmado>"}

La respuesta trae outcome: cdr cuando la SUNAT contesta con constancia, ofault cuando devuelve un error SOAP. El contrato completo está en la referencia.

Siguiente paso

Para ver cada salida de principio a fin, abre un ejemplo. Para pasar a la beta o a producción, lee Paso a producción.

Commit del SDK: 59f651b. CI de ese commit en la rama principal: success.