Cómo emitir una factura

Esta guía muestra cómo emitir una Factura Electrónica (tipo 33) y recibir el resultado vía webhook.

Prerequisitos

  • Cuenta Folyo con una empresa configurada
  • Certificado digital subido
  • Folios tipo 33 disponibles (CAF cargado)
  • API Key creada

1. Emitir el DTE

http
POST https://api.folyo.cl/v1/dte/emitir
X-API-Key: tu_api_key
Content-Type: application/json

{
  "tipo_dte": 33,
  "receptor": {
    "rut": "76543210-K",
    "razon_social": "Cliente SpA",
    "giro": "Comercio al por menor",
    "direccion": "Calle Los Leones 456",
    "comuna": "Las Condes",
    "ciudad": "Santiago"
  },
  "detalle": [
    {
      "nombre": "Servicio de consultoría",
      "cantidad": 10,
      "precio": 50000,
      "monto": 500000
    }
  ]
}

Cada línea de detalle requiere nombre, precio (valor neto unitario) y monto (total neto de la línea, normalmente cantidad × precio). El IVA se calcula a nivel de documento; no lo incluyas en monto para una factura afecta.

Antes de aceptar el documento, la API valida el cuerpo completo contra las reglas del SII (RUT del receptor, campos obligatorios y largos máximos). Si algo no cumple, responde 400 INVALID_REQUEST en la misma llamada, con el detalle exacto, y no encola nada. Los límites están en Límites de campos del SII.

Respuesta inmediata:

json
{
  "ok": true,
  "data": {
    "job_id": "a1b2c3d4-...",
    "folio": 1001,
    "tipo_dte": 33,
    "estado": "pending"
  }
}

2. Recibir el resultado vía webhook

Configura un webhook en el dashboard apuntando a tu endpoint. Cuando el DTE se procesa, recibes:

json
{
  "evento": "dte.emitido",
  "data": {
    "job_id": "a1b2c3d4-...",
    "tipo_dte": 33,
    "folio": 1001,
    "track_id": "123456789",
    "monto_total": 595000,
    "fecha_emision": "2026-05-08"
  }
}

Verifica la firma del webhook con el header X-Folyo-Signature: sha256=<hmac>.

3. Descargar el PDF

http
GET https://api.folyo.cl/v1/dte/pdf/33/1001
X-API-Key: tu_api_key

Retorna el PDF del DTE para enviar al receptor.

En el plan gratuito la descarga del XML y del PDF expira: 4 horas después de la emisión en producción, 30 minutos en certificación. Descarga y guarda los archivos apenas el job termina; pasada la ventana estos endpoints responden 410 XML_EXPIRADO. El documento sigue emitido y vigente ante el SII, no lo vuelvas a emitir. En los planes de pago los archivos no expiran. Detalle en Manejo de errores.

Campos opcionales

CampoDescripción
descuentos_globalesArreglo de descuentos o recargos globales al documento (tipo_movimiento D/R, tipo_valor %/$, valor)
rebaja_base_imponibleRebaja de base imponible del art. 17 para arriendo de inmuebles amoblados (monto en pesos, glosa opcional). Solo tipos 33, 39, 56 y 61. Ver Arriendo de inmuebles amoblados
referenciaArreglo de documentos referenciados (ej: orden de compra, contrato, HES)
observacionGlosa libre visible en el DTE
forma_pagoForma de pago (1 contado, 2 crédito, 3 sin costo)
receptor.email_intercambioCasilla de intercambio B2B del receptor: se le envía el sobre EnvioDTE por correo tras emitir

Arriendo de inmuebles amoblados (rebaja del art. 17)

Quien arrienda un inmueble amoblado debe rebajar de la base imponible del IVA el 11% anual del avalúo fiscal, proporcional al período (art. 17 del D.L. 825). No es opcional: el IVA de la factura deja de ser el 19% del neto y llega a $0 cuando la rebaja supera el canon.

El SII instruye emitir un único documento con el valor neto del arriendo, el IVA determinado después de la rebaja, el total, y una glosa con el valor del arriendo y la deducción (Oficio N° 2356 de 2025). Folyo lo resuelve con el campo rebaja_base_imponible: tú mandas el canon en detalle como línea afecta y la rebaja ya calculada; Folyo declara el neto completo, calcula el IVA sobre la base rebajada y arma la glosa.

http
POST https://api.folyo.cl/v1/dte/emitir
X-API-Key: tu_api_key
Content-Type: application/json

{
  "tipo_dte": 33,
  "receptor": {
    "rut": "76543210-K",
    "razon_social": "Cliente SpA",
    "giro": "Centros médicos",
    "direccion": "Calle Los Leones 456",
    "comuna": "Las Condes",
    "ciudad": "Santiago"
  },
  "detalle": [
    {
      "nombre": "Arriendo inmueble amoblado septiembre 2026",
      "cantidad": 1,
      "precio": 600000,
      "monto": 600000
    }
  ],
  "rebaja_base_imponible": {
    "monto": 692570,
    "glosa": "11% del avalúo fiscal $75.553.000, proporcional a un mes."
  }
}

monto es un entero en pesos mayor a cero y puede superar el neto: la base imponible tiene piso $0. glosa es opcional, hasta 300 caracteres. El campo se acepta en los tipos 33, 39, 56 y 61; en cualquier otro tipo la API responde 400 INVALID_REQUEST. Necesita al menos una línea afecta, porque la rebaja se descuenta del monto afecto.

Así quedan los totales:

CasoTipoDetalleRebajaNetoBase imponibleIVATotal
Base $033600.000 afecto692.570600.00000600.000
Rebaja parcial331.000.000 afecto692.5701.000.000307.43058.4121.058.412
Boleta391.000.000 bruto692.570950.915258.34549.0851.000.000

En facturas y notas el neto se declara completo, el IVA es el 19% de max(0, neto - rebaja) y el total es neto + exento + IVA. En boletas los montos van con IVA incluido: el IVA sale de (bruto afecto - rebaja) × 19/119 con piso $0, el neto es el bruto menos ese IVA y el total sigue siendo lo que cobraste. El resultado de la emisión (GET /v1/dte/emision/{job_id} y el webhook dte.emitido) trae monto_neto, monto_exento, monto_iva y monto_total.

La glosa que pide el SII va en la descripción de la primera línea afecta, después del texto que tú hayas puesto: Valor del arriendo: $600.000. Rebaja base imponible art. 17 D.L. 825 (11% avalúo fiscal): $692.570. Base imponible IVA: $0. IVA (19%): $0. y a continuación tu glosa. Viaja en el XML y se imprime en el PDF. El SII responde "aceptado con reparos" por la diferencia entre el IVA y el 19% del neto; el mismo Oficio 2356 dice que esa descuadratura no tiene efectos para el contribuyente, y Folyo trata el documento como aceptado.

No marques el canon como exento para llegar al IVA $0. Una factura 33 con todas sus líneas exentas se rechaza antes de emitir, con 400 INVALID_REQUEST, porque el SII la rechazaría igual (HED-3-856, "documento afecto no debe tener solo monto exento") y el folio se perdería. Si la operación es exenta, emite una factura exenta (34); si es un arriendo amoblado con rebaja, deja la línea afecta e indica rebaja_base_imponible.

Límites de campos del SII

El esquema del SII fija un largo máximo por campo. La API los verifica antes de responder: un campo más largo devuelve 400 INVALID_REQUEST con el nombre del campo y el largo recibido, sin consumir folio ni encolar el documento. Se cuentan caracteres, no bytes (una ñ cuenta 1).

CampoMáximo
receptor.razon_social100
receptor.giro40
receptor.direccion70
receptor.comuna20
receptor.ciudad20
receptor.contacto80
detalle[].nombre80
detalle[].descripcion1000
detalle[].unidad4
detalle (líneas)60 (1000 en boletas)
referencia[].razon_ref90
referencia[].folio_ref18
referencia (cantidad)40
transporte.patente8
transporte.dir_destino70
transporte.cmna_destino, transporte.ciudad_destino20
transporte.nombre_chofer30

Ejemplo de rechazo:

json
{
  "ok": false,
  "code": "INVALID_REQUEST",
  "error": "giro del receptor excede 40 caracteres (tiene 70) — el SII rechazará el documento",
  "request_id": "..."
}

Ojo con el giro: GET /v1/contribuyente/{rut} devuelve las glosas de actividad económica completas del SII, que con frecuencia superan los 40 caracteres. Si completas receptor.giro desde ahí, recórtalo a 40 antes de emitir.

El mismo chequeo aplica a POST /v1/dte/emitir/lote: si un documento del lote no cumple, la respuesta es 400 indicando su índice y no se encola ninguno.

Referencias a otros documentos (orden de compra, HES)

El arreglo referencia vincula tu factura con los documentos que la respaldan. Cada referencia lleva un tipo_doc_ref (el tipo del documento) y un folio_ref (su número o identificador).

tipo_doc_ref acepta los códigos de la tabla del SII —como 801 para la orden de compra— o un código de texto de hasta 3 caracteres acordado con el receptor. El caso más común es HES (Hoja de Entrada de Servicios), que algunos receptores exigen por contrato (frecuente en compras públicas y grandes compradores): se informa como el texto literal HES, no como un código numérico.

json
{
  "referencia": [
    { "tipo_doc_ref": 801, "folio_ref": "OC-2026-1487", "razon_ref": "Orden de compra" },
    { "tipo_doc_ref": "HES", "folio_ref": "4500123456", "razon_ref": "Hoja de Entrada de Servicios" }
  ]
}

tipo_doc_ref admite hasta 3 caracteres; un valor más largo responde 400.

La casilla de intercambio del receptor

Cuando el receptor de tu factura usa otro software de facturación, espera recibir el XML del documento en su casilla de intercambio: el correo que declaró ante el SII para el intercambio B2B de documentos electrónicos. Si al emitir incluyes receptor.email_intercambio, Folyo le envía el sobre automáticamente después de que el SII acepta el documento.

El envío del sobre corre solo para emisiones en producción (un documento de certificación no tiene validez tributaria y no corresponde entregarlo en una casilla real) y está incluido desde el plan Pyme en Folyo Platform y desde API Start en Folyo API. En los planes que no lo incluyen, el documento se emite igual y queda marcado "No incluido" en la columna Intercambio.

Si en un documento puntual no quieres que Folyo envíe el XML por correo aunque conozcas la casilla, manda receptor.omitir_intercambio: true (o desmarca el control en el formulario de emisión). El documento queda marcado "Omitido".

¿No conoces la casilla de tu cliente? Puedes buscarla en el registro de contribuyentes autorizados del SII (requiere que tu empresa tenga su certificado digital cargado en Folyo):

http
GET https://api.folyo.cl/v1/sii/casilla/76123456-7
X-API-Key: tu_api_key
json
{
  "ok": true,
  "data": {
    "rut": "76123456-7",
    "casilla": "intercambio@miempresa.cl",
    "razon_social": "MI EMPRESA SPA",
    "fuente": "cache"
  }
}

casilla vacía no es un error: significa que el RUT no tiene casilla publicada o no está autorizado como emisor electrónico. El resultado se cachea del lado de Folyo (la casilla cambia rara vez); con ?refrescar=1 fuerzas la consulta en vivo.

Si guardas la casilla en tu libreta de clientes (desde el panel o con POST /v1/clientes), no necesitas mandarla en cada emisión: cuando el request no la trae, Folyo usa la de la libreta para ese RUT.