F29 — propuesta y declaración
Cómo calculamos la propuesta, qué código tienes que aportar tú, y las barreras que existen antes de que se declare algo.
La propuesta
curl https://api.facturia.cl/v1/tax/f29/proposals/2026-07 \
-H "Authorization: Bearer $FACTURIA_KEY" -H "Facturia-Empresa: $EMPRESA"{
"id": "f29_01K2RC4T8V2M",
"object": "f29_proposal",
"period": "2026-07",
"status": "ready",
"computed_at": "2026-08-14T06:15:00Z",
"based_on": { "rcv_synced_at": "2026-08-14T06:12:03Z", "purchases": 42, "sales": 118 },
"summary": {
"iva_debito": 3210000,
"iva_credito": 1985000,
"iva_retenido": 190000,
"remanente_anterior": 0,
"ppm": 148000,
"total_payable": 1373000,
"due_date": "2026-08-20"
},
"codes": [
{ "code": 538, "label": "Total débitos", "value": 3210000 },
{ "code": 537, "label": "Total créditos", "value": 1985000 },
{ "code": 39, "label": "IVA total retenido (facturas de compra)","value": 190000 },
{ "code": 519, "label": "Crédito IVA por facturas de compra", "value": 190000 },
{ "code": 520, "label": "Crédito IVA — documentos electrónicos", "value": 1795000 },
{ "code": 77, "label": "Remanente crédito fiscal período siguiente", "value": 0 },
{ "code": 62, "label": "PPM neto determinado", "value": 148000 },
{ "code": 91, "label": "Total a pagar dentro del plazo", "value": 1373000 }
],
"observations": [
{ "code": "rcv_pendientes", "severity": "warning", "message": "3 documentos de compra están en estado PENDIENTE y no fueron considerados.", "entry_ids": ["rcv_...", "rcv_...", "rcv_..."] }
],
"upload_file_url": "https://api.facturia.cl/v1/tax/f29/proposals/2026-07/upload_file",
"filing_id": null
}Dos cosas que conviene tener claras:
Esta propuesta la calcula Facturia desde tu RCV sincronizado más tus parámetros de PPM y
remanente. El SII prellena su propio F29 para su propio portal, pero no publica una API para eso.
Donde ambos difieran, nuestras observations normalmente te dicen por qué (compras no registradas,
pendientes, huecos de caracterización) — y siempre puedes comparar contra la pantalla del SII antes
de declarar.
La lista codes es lo que va a llevar el archivo de carga, código por código. No se declara nada
que no puedas leer aquí primero.
El archivo de carga
curl -L https://api.facturia.cl/v1/tax/f29/proposals/2026-07/upload_file \
-H "Authorization: Bearer $FACTURIA_KEY" -H "Facturia-Empresa: $EMPRESA" -o f29-202607.txtEs el .txt de formato fijo del SII, listo para subir a mano si prefieres hacerlo tú.
Recalcular y sobrescribir códigos
curl -X POST https://api.facturia.cl/v1/tax/f29/proposals/2026-07/recompute \
-H "Authorization: Bearer $FACTURIA_KEY" -H "Facturia-Empresa: $EMPRESA" \
-H "Content-Type: application/json" \
-d '{"overrides":[{"code":62,"value":150000,"reason":"PPM ajustado por tasa variable"}]}'El código 048 es una entrada externa
Trampa
Facturia no sincroniza el libro de remuneraciones
El código 048 (retención de impuesto único a los trabajadores, art. 74 N°1) sale de la nómina, no del RCV. Facturia no tiene acceso a esa información, así que no la puede calcular.
Si tu empresa tiene trabajadores, ese código lo aportas tú con overrides en recompute antes de
declarar. Un F29 declarado con 048 en cero cuando debería tener valor es una declaración incorrecta,
y no es un error que la API pueda detectar por ti.
curl -X POST https://api.facturia.cl/v1/tax/f29/proposals/2026-07/recompute \
-H "Authorization: Bearer $FACTURIA_KEY" -H "Facturia-Empresa: $EMPRESA" \
-H "Content-Type: application/json" \
-d '{"overrides":[{"code":48,"value":656814,"reason":"Retención art. 74 N°1 — libro de remuneraciones julio"}]}'Todo override queda con su reason guardado, lo que importa si alguna vez hay que explicar de
dónde salió una cifra.
Declarar
Trampa
No existe webservice del SII para declarar un F29
El único canal no manual es el flujo Upload del SII: un .txt de formato fijo enviado a través de
una sesión autenticada en navegador. Facturia automatiza exactamente eso — una sesión autenticada con
certificado manejando la carga real — y lo modela como un job asíncrono con estados honestos, porque
eso es lo que es.
Si el SII cambia ese formulario, el job falla y te lo decimos. No hay una API estable debajo que nos proteja.
curl -sS https://api.facturia.cl/v1/tax/f29/filings \
-H "Authorization: Bearer $FACTURIA_KEY" -H "Facturia-Empresa: $EMPRESA" \
-H "Idempotency-Key: $(uuidgen)" -H "Content-Type: application/json" \
-d '{"period":"2026-07","proposal_id":"f29_01K2RC4T8V2M","confirm_total_payable":1373000}'{
"id": "f29fil_01K2RD9K3M8T",
"object": "f29_filing",
"period": "2026-07",
"status": "queued",
"declared": { "total_payable": 1373000 },
"attempts": 0,
"folio": null,
"receipt_url": null,
"created_at": "2026-08-14T14:30:02Z"
}Las barreras
confirm_total_payable es obligatorio y debe ser igual a la cifra de la propuesta, o recibes
422 f29_amount_confirmation_mismatch. Declarar un formulario tributario no es algo que una API deba
dejarte hacer por accidente.
Ese campo hace dos cosas a la vez: te obliga a leer la propuesta antes de declarar, y te obliga a que la cifra aparezca explícita en tu propio código — con lo cual aparece explícita en cualquier pantalla o mensaje que tu sistema muestre antes de apretar el botón.
Los estados del job
status | Significado |
|---|---|
queued | Aceptado; esperando un worker de declaración |
preparing | Generando y validando el archivo de carga |
uploading | Sesión autenticada abierta en el SII, enviando |
submitted | Subido; esperando el acuse del SII |
accepted | Declarado. folio y receipt_url quedan poblados |
rejected | El SII rechazó la declaración; errors[] explica |
failed | No pudimos completar el envío (SII caído, sesión rechazada). Reintentable |
curl https://api.facturia.cl/v1/tax/f29/filings/f29fil_01K2RD9K3M8T \
-H "Authorization: Bearer $FACTURIA_KEY" -H "Facturia-Empresa: $EMPRESA"
curl -G https://api.facturia.cl/v1/tax/f29/filings \
-H "Authorization: Bearer $FACTURIA_KEY" -H "Facturia-Empresa: $EMPRESA" -d "period[gte]=2026-01"Eventos: tax.f29.filing.submitted, tax.f29.filing.succeeded, tax.f29.filing.rejected,
tax.f29.filing.failed.
Una declaración no soporta PATCH ni DELETE. Un F29 declarado se corrige con una rectificatoria,
que está fuera del alcance de la v1.
Declaración automática
auto_file_f29 viene apagada, como toda automatización.
| Ajuste | Por defecto | Efecto |
|---|---|---|
auto_file_f29 | false | Declara el F29 del período en auto_file_f29_day |
auto_file_f29_day | 18 | El día del mes en que se declara |
auto_file_f29_max_payable | 0 | Solo declara sola si el total_payable calculado es menor o igual a este tope |
Con el tope en 0 —el valor de fábrica— solo una posición cero o a favor se declara sola, y cualquier mes en que efectivamente debas IVA espera por ti. Sube el tope deliberadamente, empresa por empresa.
Trampa
Una propuesta con observaciones nunca se declara sola
Si hay observations con severity: error, la declaración automática se suprime y se dispara
tax.f29.review_required. Declarar un F29 es una declaración jurídicamente vinculante: publicamos la
capacidad porque una empresa chica que la quiera no debería tener que entrar al SII el día 18, pero
es opt-in por empresa, con tope, y publica tax.f29.filing.succeeded / .failed para que puedas
supervisarla.
Caracterización
La escritura que decide si el IVA de una compra es recuperable, de uso común o no recuperable — y por qué hacerla por API es una ventaja real.
Servicios digitales extranjeros y el tipo 46
El ciclo de tres pasos — ingresar cargos, leer sugerencias, confirmar — y de dónde salen los cargos si no los tienes.