Notta Docs

API: Folios (CAF)

Carga, inventario y eliminación de los archivos CAF que autorizan tus rangos de folios por tipo de DTE, con alerta de folios bajos

El recurso /caf administra los CAF (Código de Autorización de Folios) de tu organización: el XML que el SII te entrega con un rango de folios autorizado por tipo de DTE. Notta consume folios secuencialmente de cada CAF al emitir y avisa cuando quedan pocos (low_folios).

Base URL: https://app.notta.cl/api/v1. El CAF se guarda cifrado con la misma envelope encryption de los certificados.

Autenticación: API key Bearer o sesión del dashboard

Los cinco endpoints de /caf aceptan las dos credenciales: Authorization: Bearer ntt_cert_… para consumidores externos (API, CLI, MCP) o la cookie de sesión del dashboard. Las cuatro mutaciones (POST /caf/request, POST /caf, DELETE /caf/:id y PUT /caf/auto) exigen además el scope caf:write en la key y un rol escritor en la organización: una key con solo dte:write, o un viewer, reciben 403 forbidden. Sin organización responden 412 org.required.

Endpoints

POST /caf/request

Le pide al SII un rango nuevo de folios para un tipo, sin que tengas que pasar por el timbraje electrónico del portal. Es el camino programático cuando todavía no tienes ningún CAF: Notta abre la sesión mutual-TLS con tu certificado, completa el wizard de timbraje y guarda el XML cifrado, listo para emitir.

El grant es irreversible

El SII otorga folios reales que no se devuelven ni se anulan, en cert y en producción. Pide la cantidad que vayas a usar. Hay un cooldown anti doble-grant: una segunda llamada mientras la primera sigue en vuelo responde 409 caf.request_in_flight con retry_in_seconds y no vuelve a pegarle al SII.

Campo (JSON)TipoRequeridoDescripción
tipointTipo de DTE a timbrar. Uno de 33, 34, 46, 52, 56, 61, 110, 112. Las boletas 39/41 tienen pipeline propio y responden 400.
cantidadintnoCuántos folios pedir (1–1000). Sin él, Notta usa el default por tipo.

Los folios de exportación (110 y 112) se timbran por esta misma vía, y desde el 19 de agosto de 2026 también se emiten por la API: POST /dtes con tipo_dte: 110 acepta el documento. Lleva su propio cuerpo —moneda, ind_servicio y bloque aduana—; está descrito en Emitir un DTE. Tu organización necesita el tipo autorizado por el SII: sin eso la respuesta es 403.

curl -X POST https://app.notta.cl/api/v1/caf/request \
  -H "Authorization: Bearer $NOTTA_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"tipo": 33, "cantidad": 20}'

El ambiente sale de la API key: una ntt_cert_ pide folios en maullin (cert) y una ntt_prod_ en palena. Con sesión del dashboard sale del ambiente activo de tu organización.

Respuesta 201 Created — se solicitó un rango nuevo:

{
  "data": {
    "requested": true,
    "cafs": [{ "tipo": 33, "estado": "requested", "cafId": "01977f6e-5f90-7000-8000-000000000005" }]
  }
}

Si ya tienes folios vigentes para ese tipo, la respuesta es 200 OK con requested: false y reason: "no_cafs_missing": no se pidió nada.

Errores posibles:

CódigoHTTPQué hacer
caf.invalid_request (tipo no soportado, cantidad fuera de 1–1000)400
forbidden (la key no tiene caf:write, o el rol es viewer)403Crea la key con ese scope en /app/api-keys
caf.request_in_flight (cooldown; trae retry_in_seconds)409Reintenta después de ese plazo
caf.type_not_prod_certified409El SII habilita el tipo en producción al aprobar la postulación
cert.missing412Sube un certificado vigente primero
org.required412
caf.cert_not_authorized (el certificado no está autorizado a timbrar)502Autoriza el certificado en el portal del SII
caf.grant_rejected (el SII rechazó el grant, con su mensaje)502
caf.request_failed (falló la sesión con el SII)502
db.unavailable · caf.kms_unavailable503

POST /caf

Sube un archivo CAF (multipart/form-data): parsea el XML (RE, TD, D, H), valida el tipo esperado y registra el rango de folios.

Campo (form)TipoRequeridoDescripción
filearchivoEl XML CAF descargado del SII.
tipo_esperadointnoTipo de DTE que esperas (33, 34, 39, 41, 56, 61); si el XML trae otro, responde 422 caf.wrong_tipo antes de insertar.
certificate_iduuidnoCertificado asociado; default: el primer certificado vigente de la org (sin ninguno → 422 caf.no_certificate).
curl -X POST https://app.notta.cl/api/v1/caf \
  -H "Authorization: Bearer $NOTTA_API_KEY" \
  -H "Idempotency-Key: $(uuidgen)" \
  -F "file=@CAF-33-1000-1500.xml" \
  -F "tipo_esperado=33"

A diferencia de /caf/request, el CAF subido queda etiquetado con el ambiente activo de tu organización (cert o prod), no con el de la API key. Si subes un CAF de palena con la organización en cert, la emisión no lo va a encontrar.

Respuesta 201 Created:

{
  "data": {
    "id": "01977f6e-5f90-7000-8000-000000000005",
    "tipo_dte": 33,
    "folio_desde": 1000,
    "folio_hasta": 1500,
    "remaining": 501,
    "low_folios": false
  }
}

La deduplicación es por rango: re-subir el mismo (rut, tipo, folio_desde) responde 409 caf.duplicate.

Errores posibles:

CódigoHTTPnext_action
caf.invalid_request (falta file)400
caf.duplicate409
org.required412
caf.parse_error (XML sin RE/TD/D/H)422
caf.wrong_tipo422
caf.no_certificate422
caf.insert_failed500
db.unavailable · caf.kms_unavailable503

GET /caf

Lista los CAF de tu organización con el consumo de folios de cada rango.

curl https://app.notta.cl/api/v1/caf \
  -H "Authorization: Bearer $NOTTA_API_KEY"

Respuesta 200 OK:

{
  "data": [
    {
      "id": "01977f6e-5f90-7000-8000-000000000005",
      "rut_emisor": "76123456-0",
      "tipo_dte": 33,
      "folio_desde": 1000,
      "folio_hasta": 1500,
      "next_folio": 1235,
      "remaining": 266,
      "low_folios": false,
      "not_after": "2026-12-09T00:00:00.000Z",
      "exhausted": false,
      "created_at": "2026-06-09T18:20:00.000Z"
    }
  ]
}

remaining = folio_hasta - next_folio + 1; low_folios se prende con 10 o menos. Errores posibles: 412 org.required, 503 db.unavailable.

DELETE /caf/:id

Elimina un CAF (hard delete, permite re-subir el mismo rango) junto con los DTE del rango que el SII no aceptó; está bloqueado si algún DTE del CAF fue aceptado.

curl -X DELETE https://app.notta.cl/api/v1/caf/01977f6e-5f90-7000-8000-000000000005 \
  -H "Authorization: Bearer $NOTTA_API_KEY"

Respuesta 200 OK:

{ "data": { "id": "01977f6e-5f90-7000-8000-000000000005", "deleted": true, "dtes_deleted": 2 } }

Retención legal de 6 años

Si algún DTE del CAF fue aceptado por el SII (EPR, RPR, DOK, aceptado con reparos), el borrado responde 409 caf.has_accepted_dtes: esos folios quedaron registrados en el SII y los documentos se conservan por obligación legal de 6 años. Lo mismo si un DTE del rango fue cedido vía RPETC (409 caf.has_ceded_dtes).

Errores posibles:

CódigoHTTPnext_action
caf.not_found404
caf.has_accepted_dtes409
caf.has_ceded_dtes409
org.required412
db.unavailable503

PUT /caf/auto

Enciende o apaga el timbraje automático: con él prendido, Notta le pide al SII un rango nuevo de folios cuando a un tipo de documento le quedan 10 o menos, sin que tengas que pedirlo. Es el mismo grant irreversible de POST /caf/request, disparado por un barrido diario en vez de por tu llamada.

curl -X PUT https://app.notta.cl/api/v1/caf/auto \
  -H "Authorization: Bearer $NOTTA_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "enabled": true }'

Respuesta 200 OK:

{ "data": { "enabled": true, "umbral": 10 } }

umbral es la cantidad de folios restantes que dispara la solicitud: el mismo número que prende low_folios en GET /caf.

Solo en producción, y cada recarga es irreversible. Mientras tu empresa está en certificación el toggle responde 409 caf.auto_requires_production: ahí el proceso lo conduce el asistente de Puesta en Marcha, que además autoriza gestiones que no se deshacen. En producción, cada recarga automática le pide folios reales al SII y el SII no los devuelve: prenderlo es autorizar por adelantado esas solicitudes en tu nombre.

Errores posibles:

CódigoHTTPnext_action
caf.invalid_request400
forbidden403
caf.auto_requires_production409
org.required412
db.unavailable503

Próximos pasos

Última actualización

En esta página