factadesarrolladores API 0.1.0-esqueleto

Empezar

Nueve pasos entre abrir la cuenta y ver su primera factura sellada en el ambiente de pruebas. Los cinco primeros ocurren en app.factadte.com; los cuatro últimos, en su editor.

Antes de escribir código

La API no crea empresas ni certificados: emite con los de una empresa que ya existe en Facta y que ya hizo su incorporación con el Ministerio. Si todavía no llegó ahí, el asistente de la app lo acompaña paso a paso, y lo de abajo lo espera al final de ese camino.

Los nueve pasos

  1. Cuenta y empresa en app.factadte.com

    Cree la cuenta, registre la empresa con su NIT y su NRC, y complete el perfil fiscal. De ahí salen el emisor, el establecimiento y el punto de venta que la API escribe en cada documento: usted no los nombra nunca en una petición, y por eso no los puede equivocar.

  2. Certificado y vault de firma

    Suba el certificado de firma que le entregó el Ministerio y guarde su contraseña en el vault de la empresa. Ese certificado nunca sale de ahí y nunca viaja a su servidor: cuando la API firma, lo abre en el momento y lo vuelve a cerrar.

  3. Acuñe la llave y elija sus alcances

    En Configuración → Llaves de la API. Al acuñarla decide tres cosas que después no se editan:

    • Los alcances. issue para las rutas que emiten, query para consultar, download para el área de retención. Dé solo los que el sistema va a usar: una llave de un punto de venta no necesita descargar nada.
    • Los tipos de DTE que esa llave puede emitir.
    • La lista de direcciones IP, si quiere una. Acepta direcciones sueltas y rangos en notación CIDR, IPv4 o IPv6. Vacía significa «desde cualquier parte».
  4. Las tres cadenas, y dónde guarda cada una

    Al acuñar la llave, Facta le entrega tres cadenas y las muestra una sola vez. No son tres formas de decir lo mismo: cada una abre algo distinto, y esa separación es lo que hace que perder una no sea perderlo todo.

    CadenaQué abre¿Viaja a Facta?
    FACTA_API_KEYNada. Identifica y autentica.Sí, en cada petición.
    FACTA_SIGN_KEY (factask_…)Su vault de firma, en el servidor de Facta, durante una petición.Sí, solo al emitir, firmar y anular.
    FACTA_UNLOCK_KEY (factauk_…)Sus credenciales de almacenamiento, en su servidor.Nunca.
    sh.env de su despliegue
    # Las tres cadenas se muestran UNA sola vez, al acuñar la llave.
    FACTA_API_KEY=facta_test_k7f3a9c21.xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
    FACTA_SIGN_KEY=factask_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
    
    # Esta tercera NO se le pasa a Facta ni al cliente: abre sus credenciales
    # de almacenamiento en SU servidor.
    FACTA_UNLOCK_KEY=factauk_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
  5. El ambiente lo decide la llave

    Una llave facta_test_ transmite a apitest.dtes.mh.gob.sv; una facta_live_, al servicio de producción. Las dos usan la misma URL base.

    Una llave de producción solo se puede acuñar para una empresa que ya pasó su propia ceremonia de paso a producción, y el servidor compara los dos ambientes antes de firmar nada. Cruzarlos es 403 environment_not_allowed: una llave de pruebas no emite un documento real, y una de producción no ensucia el ambiente de pruebas.

  6. Conecte un destino de almacenamiento

    Es un requisito para emitir, no un extra. La empresa necesita al menos un destino conectado y verificado en los últimos 30 días —Drive, S3, R2, Supabase Storage, FTP/SFTP— o la petición se detiene con 422 no_storage_destination antes de reservar correlativo.

    La razón: firmar un documento que no tiene dónde aterrizar lo dejaría sin ninguna copia salvo la de esa misma respuesta HTTP, y esa respuesta se pierde con el primer proceso que se cae.

  7. La primera petición

    Antes de emitir nada, confirme que la llave sirve y mire qué dice de sí misma: el ambiente, los alcances, si puede firmar y cuánto cupo le queda.

    curlTerminal
    curl https://hcnvknpsbadplnfcflxx.supabase.co/functions/v1/api-v1/v1/status \
      -H "X-Facta-Key: $FACTA_API_KEY"

    Si contesta 401 invalid_api_key, casi siempre falta el punto: la llave es facta_test_<id>.<secreto> entera, y la parte de después del punto se mostró una vez. Si contesta 403 ip_not_allowed, la llave tiene lista de direcciones y la suya no está en ninguna entrada.

  8. La primera factura de pruebas

    Una factura (01) a consumidor final: sin receptor, que es legal, y con el IVA incluido en el precio de la línea —así lo define el esquema oficial de ese tipo—.

    curlTerminal
    curl -X POST https://hcnvknpsbadplnfcflxx.supabase.co/functions/v1/api-v1/v1/dte \
      -H "X-Facta-Key: $FACTA_API_KEY" \
      -H "X-Facta-Sign-Key: $FACTA_SIGN_KEY" \
      -H "Idempotency-Key: mi-primera-venta-001" \
      -H "Content-Type: application/json" \
      -d '{
            "tipoDte": "01",
            "items": [
              { "descripcion": "Café", "cantidad": 2, "precioUni": 1.5 }
            ]
          }'

    Un 200 trae selloRecibido: eso es un documento sellado. Un 202 significa que quedó firmado y el Ministerio no contestó — no lo reintente, que firmaría un segundo documento. Un 422 con mh_rejected significa que Hacienda lo leyó y lo negó.

  9. Antes de pasar a producción

    La lista corta, y ninguna de las cuatro es opcional:

    • Guardar el jws de cada emisión, no el documento. Volver a serializar el JSON no reproduce los bytes cuya firma validó Hacienda.
    • Manejar el 202 como un resultado y no como un fallo.
    • Usar una Idempotency-Key estable por venta —su número de pedido, su ticket de caja— y no una aleatoria por intento.
    • Tener un camino para el 422 mh_rejected: el correlativo ya se gastó, y el §167 de la normativa permite corregir con ese mismo número.

De pruebas a producción

Cuando la empresa complete su ceremonia de paso a producción en la app, acuñe una llave nueva con prefijo facta_live_. No hay nada más que cambiar: ni la URL, ni las cabeceras, ni el código.

Las llaves de pruebas siguen sirviendo y conviene conservarlas: es donde se prueba el cambio siguiente.

Escriba para buscar Por ejemplo: idempotencia, contingencia, 422, emitir.

moverse Enter abrir Esc cerrar