Tema
Empezar en 10 minutos
Al final de esta página habrás emitido una factura de prueba y visto su sello.
Lo que necesitas
- Una API key. La crea el contribuyente desde su panel, en Configuración → API keys, o se pide a quien administre la instalación. Se muestra una sola vez: en la base solo queda su SHA-256, así que si se pierde hay que crear otra.
- Que el contribuyente tenga cargados su certificado de firma y sus credenciales de Hacienda. Sin eso, emitir responde
409 configuracion-incompleta.
bash
export API=http://localhost:8090 # en producción, https://api.factura.sv
export CLAVE=sk_test_xxxxxxxx_yyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyEl prefijo dice en qué ambiente estás: sk_test_ es el ambiente de pruebas de Hacienda, sk_live_ es producción. Lo que emitas con una llave sk_live_ tiene valor fiscal y hay que declararlo.
1. Comprueba la credencial
bash
curl -s "$API/api/v1/dte/tipos-documento" -H "Authorization: Bearer $CLAVE"Si responde un JSON con tipos, la llave sirve. Si responde 401, revisa que copiaste la llave entera —son 70 caracteres— y que va detrás de Bearer .
Esta llamada además es el sitio por el que conviene empezar de verdad: devuelve las reglas de cada tipo de documento, y son las mismas con las que valida el servidor. Léelas en vez de codificarlas.
2. Emite una Factura
Una factura a consumidor final, que es el caso más simple: no hace falta identificar al receptor.
bash
curl -s -X POST "$API/api/v1/dte/documentos" \
-H "Authorization: Bearer $CLAVE" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: $(uuidgen)" \
-d '{
"tipoDte": "01",
"items": [
{
"descripcion": "Almuerzo ejecutivo",
"cantidad": 2,
"uniMedida": 59,
"precioUni": 8.50,
"tipoItem": 2
}
],
"condicionOperacion": 1,
"formaPago": "01"
}'Respuesta:
json
{
"codigoGeneracion": "2F380579-2A15-42E8-9ADF-4EA97AE4DA3A",
"numeroControl": "DTE-01-M001P001-000000000000042",
"tipoDte": "01",
"estado": "TRANSMITIENDO",
"url": "/api/v1/dte/documentos/2F380579-2A15-42E8-9ADF-4EA97AE4DA3A"
}HTTP 202, no 201. El documento está firmado y en camino a Hacienda; el sello todavía no llegó.
Tres cosas del cuerpo que enviaste:
uniMedida: 59es «unidad» en el catálogo CAT-014. Sirve para casi todo.tipoItem: 2es «servicio»;1es un bien.precioUni: 8.50lleva el IVA incluido, porque es una Factura. En un CCF ese mismo campo iría sin IVA. Es el error más común al integrar.
3. Mira el sello
bash
CG=2F380579-2A15-42E8-9ADF-4EA97AE4DA3A
curl -s "$API/api/v1/dte/documentos/$CG" -H "Authorization: Bearer $CLAVE"Unos segundos después:
json
{
"codigoGeneracion": "2F380579-2A15-42E8-9ADF-4EA97AE4DA3A",
"numeroControl": "DTE-01-M001P001-000000000000042",
"estado": "SELLADO",
"selloRecibido": "20266B573AF9DE4543A7942C0CD0891B0EBA3KWJ",
"codigoMsg": "001"
}SELLADO es el único estado en el que el documento existe para Hacienda.
4. Descarga el PDF y el JSON
bash
curl -s "$API/api/v1/dte/documentos/$CG/pdf" -H "Authorization: Bearer $CLAVE" -o factura.pdf
curl -s "$API/api/v1/dte/documentos/$CG/json" -H "Authorization: Bearer $CLAVE" -o factura.jsonEl PDF trae el código QR con el que cualquiera verifica el documento en el portal de Hacienda. El JSON es el archivo tal como se le entrega al receptor.
5. No sondees en producción: registra un webhook
Sondear está bien para probar. Para un sistema real, pide que te avisen:
bash
curl -s -X POST "$API/api/v1/dte/webhooks" \
-H "Authorization: Bearer $CLAVE" \
-H "Content-Type: application/json" \
-d '{"url":"https://tu-sistema.com/hooks/dte","eventos":["documento.sellado","documento.rechazado"]}'La respuesta trae un secreto que no se vuelve a mostrar: con él se verifica la firma de cada entrega. → Webhooks
Si estás en una caja y necesitas imprimir ya
Un restaurante no puede decirle al cliente «espera, te aviso por webhook». Para eso está esperar:
bash
curl -s -X POST "$API/api/v1/dte/documentos?esperar=8s" \
-H "Authorization: Bearer $CLAVE" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: $(uuidgen)" \
-d '{ ... }'La petición se queda esperando hasta 8 segundos a que llegue el sello. Si llega, la respuesta ya trae estado: SELLADO y puedes imprimir. Si no llega, el documento sigue su curso igual y te responde con el estado que tenga: no se pierde nada, solo no alcanzaste a esperarlo.
El máximo es 20 segundos. Por encima de eso la petición ocupa un worker del API más de lo que ninguna caja está dispuesta a esperar de pie.
Qué leer ahora
- Si vas a facturar a empresas: Tipos de documento, por el Comprobante de Crédito Fiscal.
- Si vas a manejar devoluciones: la misma página, sección de notas de crédito.
- Si es un restaurante: Recetas.
- Antes de salir a producción: Idempotencia y Errores.