Notta Docs

RCV y F29

Sincroniza el registro de compras y ventas del SII y obtén tu declaración mensual de IVA propuesta, lista para verificar antes de presentar.

Qué es el RCV

El Registro de Compras y Ventas es la nómina oficial del SII con todos los DTEs que tu empresa recibió (compras → crédito IVA) y emitió (ventas → débito IVA) en un período. Notta lo sincroniza desde el SII con el certificado digital que ya cargaste para firmar tus DTEs (no necesitas clave tributaria) y lo guarda como snapshot consultable por período. El RCV puede tardar en reflejar documentos recientes; si falta algo que esperabas ver, fuerza un sync con force: true.

El RCV reemplazó a los Libros Electrónicos de Compra y Venta (IECV) a partir del período agosto de 2017 (Res. Ex. SII N°61 y N°68 de 2017): si eres emisor electrónico autorizado, ya no envías libros mensuales al SII. La carta de autorización del SII todavía incluye un párrafo que los exige: es texto heredado de una plantilla anterior a 2017.

Qué es el F29

El Formulario 29 es la Declaración Mensual de IVA. Notta va a calcular el F29 propuesto del período a partir de los snapshots RCV, todavía no está disponible, ver el estado más abajo:

LíneaCálculo
Débito fiscalSuma del IVA de las ventas afectas del período (las exentas 34/41 no aportan)
Crédito fiscalSuma del IVA de las compras afectas
RetencionesRetenciones de BHE percibidas en el período
Neto a pagar (Línea 89)max(0, débito − crédito − retenciones)
Crédito remanente (Línea 77)El excedente, cuando el saldo queda a tu favor

El F29 de Notta es read-only: lo verificas contra la propuesta del SII y presentas la declaración en el portal del SII.

Endpoints

CanalOperaciónPara qué
APIPOST /api/v1/rcvSincroniza el snapshot de un período: body { rut, periodo, type?, force? }
APIGET /api/v1/rcv?periodo=YYYY-MMLista los snapshots del período (filtros rut y type, orden sort/dir)
APIGET /api/v1/rcv/documents?type=issuedEl registro documento por documento, tipado y paginado
API / MCP listRecepcionGET /api/v1/recepcion?cedida=trueCompras cedidas, con filtro y total antes de paginar

type acepta received, issued o both (default both). Sync de ejemplo:

curl -X POST https://app.notta.cl/api/v1/rcv \
  -H "Authorization: Bearer ntt_cert_..." \
  -H "Idempotency-Key: $(uuidgen)" \
  -H "Content-Type: application/json" \
  -d '{ "rut": "76123456-0", "periodo": "2026-04", "type": "both" }'

La respuesta es { "snapshot_id": "…", "from_cache": false, "incompleto": false, "faltantes": [] }. Con incompleto: true, al período le faltan documentos que el SII declaró y no entregó: faltantes dice cuáles (ver incompleto más abajo).

Leer el registro documento por documento

GET /rcv devuelve el snapshot: el parsed_json con las filas tal como las manda el SII. Sirve para auditar, pero trabajar contra él significa parsear nombres de campo del Servicio que ni siquiera son estables. GET /rcv/documents es la lectura tipada, una fila por documento, con el vocabulario de Notta:

curl "https://app.notta.cl/api/v1/rcv/documents?type=issued&periodo=2026-04&limit=100" \
  -H "Authorization: Bearer ntt_prod_..."
Query paramRequeridoDescripción
typesíissued (ventas) o received (compras)
periodonoYYYY-MM. Omitirlo devuelve todos los períodos
estadonoSección del registro. Default registro; all trae las cuatro
limitnoDefault 100, máx 500
cursornoEl next_cursor de la página anterior

La respuesta es { data, total, next_cursor, synced_at, cobertura_periodos, resumen_no_detallado, incompleto, faltantes }, y los dos últimos solo vienen cuando filtras un periodo. total es el universo que matchea el filtro, no el tamaño de la página: recorres mientras next_cursor no sea null y verificas que lo leído calce con total. La paginación es keyset sobre el id, que es estable entre re-sincronizaciones: un sync nuestro a mitad de tu recorrido no te reordena lo ya visto.

synced_at antes de interpretar total. Es la última vez que bajamos el registro del SII para ese filtro, o null si nunca se sincronizó. Sin mirarlo, total: 0 tiene dos lecturas opuestas («este período no tuvo documentos» y «todavía no tenemos los datos») y para quien concilia una cierra el mes y la otra es una alarma.

cobertura_periodos antes de concluir que un documento no existe. Trae { periodo_min, periodo_max, periodos }: qué períodos del registro están sincronizados. Dentro de ese rango la respuesta es evidencia; fuera de él no afirma nada, y que un documento no aparezca solo significa que todavía no bajamos ese período. Mira el rango antes de dar por inexistente algo que no encontraste: sin este campo, la única salida es inferir la cobertura mirando los períodos de las filas que sí llegaron, y con cero filas no hay de dónde inferirla.

Ignora el filtro periodo a propósito, y respeta type: pedir ?periodo=2026-06 no encoge el rango, porque describe lo que hay sincronizado y no lo que filtraste. periodo_min y periodo_max en null con periodos: 0 significa que nunca se sincronizó nada de ese lado del registro, que es distinto de un rango presente con total: 0 («miramos esos períodos y no había documentos»). Si lo que buscas cae afuera, sincroniza ese período con POST /api/v1/rcv y vuelve a consultar. El servidor MCP no puede: su catálogo lee el registro y no lo baja, así que un agente conectado por ahí tiene que pedirle la sincronización a la persona que opera la cuenta.

resumen_no_detallado es plata que no está en data. Para once tipos de documento (boletas 35/38/39/41, vale 47, comprobante de pago 48, boleta liquidación 105 y los resúmenes 919/920/922/924) el SII no entrega el detalle, entrega un total del período: esas filas no tienen folio, ni contraparte, ni fecha de emisión, así que no pueden vivir en data. Si vas a sumar, suma data[].monto_total más resumen_no_detallado[].monto_total, con el mismo filtro de tipo, período y estado. Sumar solo data da de menos y no de poco: en una empresa medida en producción el 97% de las ventas del período vivía ahí. Un arreglo vacío es el caso normal, y no hay forma de pedir el detalle porque el SII no lo tiene.

incompleto antes de totalizar un mes. Cuando filtras un solo periodo, la respuesta dice si a ese período le faltan documentos. incompleto: true significa que en la última sincronización el SII declaró documentos en su resumen y no entregó su detalle: como el registro nunca se purga, esos documentos pueden faltar del todo, faltar en parte o ya estar en data si una sincronización anterior sí los trajo, así que ni data ni total garantizan estar completos: no totalices el período con esas filas ni lo reportes como cerrado. faltantes dice cuáles, con la operacion, la sección (estado), el tipo_doc y cuántos declarados no llegaron en esa sincronización, acotados a tu type y a tu estado igual que data. Cuando el SII exige pedir ese detalle como archivo (descarga diferida) y Notta no alcanzó a bajarlo, motivo dice por qué (presupuesto o tope = se acabó el tiempo, y la sincronización diaria lo vuelve a intentar); motivo: null = no se intentó. Los demás valores (recaptcha, codigo_<n>, otra_empresa, filas_no_calzan, entre otros) describen lo que devolvió el SII o el archivo, y la lista puede crecer: no la trates como cerrada. incompleto: false quiere decir que no falta el detalle de ningún tipo completo. incompleto: null (con faltantes: null) es un período que se sincronizó antes de que Notta midiera si el SII entregó todo el detalle: no se sabe si está completo, así que tampoco lo totalices como si lo estuviera, y vuelve a sincronizarlo para medirlo. Sin periodo, o si el período nunca se sincronizó, los dos campos no vienen, y esa ausencia no es un false. Un período incompleto no se sirve desde la caché: volver a sincronizarlo con POST /api/v1/rcv le vuelve a preguntar al SII, que puede seguir sin entregarlo. El servidor MCP no puede sincronizar, así que un agente conectado por ahí se lo pide a la persona que opera la cuenta.

Para recorrer un período completo, usa `estado=all`

El registro del SII tiene cuatro secciones: registro (lo asentado), pendiente, no_incluir y reclamado. El default devuelve solo la primera.

Y hay una segunda razón, menos obvia: estado es mutable. Un documento migra de sección y nuestro sync lo refresca en la misma fila, conservando su id. Si recorres con estado=registro y un sync corre a mitad de tu recorrido, un documento que estaba en pendiente puede pasar a registro detrás de tu cursor: nunca te lo servimos, pero total, que se recalcula en cada página, sí lo cuenta. Terminas con filas_leídas = total - 1 y sin saber cuál falta.

Recorre con ?estado=all, que es un filtro invariante, y clasifica por el campo estado de cada fila. Si solo necesitas una foto y no un recorrido verificable, el default está bien.

Una última cosa sobre lo que filas_leídas === total garantiza: que leíste todo lo que nosotros tenemos, no todo lo que el SII tiene hoy. Un documento que desaparece del registro del SII conserva aquí su último estado conocido: no lo borramos.

Cuatro campos que no están en el snapshot crudo y resuelven casos concretos:

  • evento_receptor: el código con que el SII reporta lo que hizo la contraparte, no solo su glosa. Llegan cuatro, todos de una letra: R (reclamado por el receptor), C (recibo otorgado), A (no reclamado en plazo, que aparece solo en compras) y P, que no es un evento del receptor: significa que el emisor declaró la operación al contado, y sobre esas el SII no registra acuse ni reclamo. Ramificar por el código y no por la glosa, que es texto libre, es lo que separa un reclamo de una forma de pago. Cuando el SII entrega el detalle como archivo (lo exige desde unos 1.000 documentos), el archivo trae solo las fechas y el código sale de ellas: R si hay reclamado_at y C si hay acuse_at. Lee el código junto con las fechas: un documento está reclamado si trae R o reclamado_at, tiene acuse si trae C o acuse_at, y el reclamo manda sobre el acuse. Un null no prueba que no haya habido evento: en un documento que llegó como archivo y sin fechas, no distingue A ni P. Para entender qué significa un reclamo sobre una venta tuya, el plazo que corre y por qué no se puede revertir: Reclamo del receptor.
  • referencia_tipo / referencia_folio: el documento al que esa fila hace referencia. No equivale a «este documento corrige a otro»: una factura también referencia, y de hecho lo hace (facturas 33 que apuntan a la guía 52 que consolidan, o a documentos de papel). Para saber si es una corrección mira document_type: solo las notas corrigen (56 y 61, y 111 y 112 en exportación). Y no asumas que el referenciado es una factura afecta: hay referencias reales a exentas (34), boletas (39) y a otras notas de crédito (61); enlazar solo por folio, sin el tipo, cruza secuencias distintas.
  • dte_id / documento_disponible: si el documento también existe en Notta y se puede bajar con /dtes/{dte_id}/pdf, /xml, /pdf-url o /xml-url. dte_id en null significa que la fila vive solo en el registro del SII, que guarda el asiento y no el documento.
  • cedida / rpetc_aceptada_at: la factura está registrada como cedida a un tercero en el RPETC (Ley 19.983), y rpetc_aceptada_at es la fecha desde la que corren los 8 días tras los cuales la aceptación es irrevocable. Míralo antes de emitir una nota de crédito: sobre una factura cedida con la aceptación firme, la nota es inoponible al cesionario (doctrina Corte Suprema 2025) y POST /dtes la bloquea. El campo se omite cuando no es true, y esa ausencia no afirma que no esté cedida: solo las ventas (type=issued) tienen quién escriba ese dato, porque nadie consulta el RPETC de tu proveedor. Nunca viaja como false.

Los montos son enteros y total_amount es el total del documento según el SII. En documentos con retención o impuestos adicionales (por ejemplo una Factura de Compra 46) net_amount + exempt_amount + vat_amount no suma total_amount: esos tributos no tienen columna propia aquí, así que el total es el número con el que se cuadra.

Estado actual

El sync y la consulta del RCV (/api/v1/rcv) funcionan hoy con tu API key, y el servidor MCP puede leer tu registro (listRcv y listRcvDocuments, dos de las 31 operaciones de su catálogo).

El F29 todavía no está disponible en ninguna superficie: no tiene endpoint en /api/v1, no está en el dashboard y el MCP no lo cubre. La tabla de arriba describe el cálculo que Notta va a exponer, no algo que puedas consultar hoy. Mientras tanto, el F29 propuesto lo ves en el portal del SII, y la presentación siempre es manual.

Próximos pasos

  • Referencia de la API: el resto de los endpoints de /api/v1 con sus shapes.
  • BHE: las boletas de honorarios cuyas retenciones alimentan el F29.
  • Notta para agentes: llms.txt, OpenAPI y MCP para operar Notta desde un LLM.
  • Pasa a producción: el camino para que estos números tengan valor tributario real.

Cesiones de tus compras

El listado GET /api/v1/recepcion incluye cesion por compra, también cuando solo existe en el RCV. estado puede ser cedida, no_cedida o indeterminado. Una cesión vigente incluye cesionario (rut, razonSocial), fechaCesion, montoCedido y vencimiento. consultadoAl informa la última consulta del barrido, o null si todavía no ocurrió.

no_cedida requiere cobertura consultable, un barrido completo con mes inicial conocido y una factura emitida desde el día 1 de ese mes. La ausencia de una fila en el registro no basta. Una evidencia vigente conserva cedida aunque la cobertura actual sea incompleta.

Para indeterminado, motivo.codigo explica el límite: certificado_no_vigente, empresa_en_certificacion, otro_ambiente, primer_barrido_pendiente, barrido_incompleto, anterior_a_cobertura, fecha_emision_desconocida o estado_sii_desconocido. fecha_emision_desconocida indica que falta una emisión válida: la fecha de recepción mostrada como alternativa no acredita cobertura desde la emisión. estado_sii_desconocido conserva el texto del SII en motivo.glosa. En estos estados, los datos de cesionario, fecha, monto y vencimiento son null.

curl "https://app.notta.cl/api/v1/recepcion?cedida=true&page=1&pageSize=100" \
  -H "Authorization: Bearer ntt_prod_..."

La respuesta conserva { documentos, total }. cedida solo admite el literal true: false u otro valor responde 400 recepcion.query_invalid. El filtro se aplica a todas tus compras deduplicadas antes de paginar, y total cuenta ese mismo universo filtrado. La operación MCP existente listRecepcion ofrece el mismo contrato. El ambiente corresponde a tu credencial.

Última actualización

En esta página