F29 — proposal and filing
How we compute the proposal, which code you have to supply yourself, and the guardrails that stand before anything gets filed.
The proposal
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
}Two things worth being clear about:
Facturia computes this proposal from your synced RCV — the purchase-and-sales register the SII,
Chile's tax authority, keeps for you — plus your own PPM (monthly provisional income tax) and
remanente (credit carried forward) parameters. The SII prefills its own F29, the monthly IVA return,
for its own portal, but publishes no API for it. Where the two differ, our observations normally
tell you why (unregistered purchases, pending entries, characterization gaps) — and you can always
compare against the SII's screen before you file.
The codes list is what the upload file will carry, code by code. Nothing gets filed that you
can't read here first.
The upload file
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.txtIt is the SII's fixed-format .txt, ready to upload by hand if you'd rather do it yourself.
Recompute and override codes
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"}]}'Code 048 is an external input
Trap
Facturia does not sync the payroll ledger
Code 048 (withholding of employees' impuesto único, the tax on employment income, art. 74 N°1) comes out of payroll, not out of the RCV. Facturia has no access to that information, so it cannot compute it.
If your company has employees, you supply that code yourself with overrides on recompute before
you file. An F29 filed with 048 at zero when it should carry a value is an incorrect return, and it
is not an error the API can catch for you.
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"}]}'Every override is stored with its reason, which is what matters the day someone has to explain
where a figure came from.
Filing
Trap
There is no SII web service for filing an F29
The only non-manual channel is the SII's Upload flow: a fixed-format .txt sent through an
authenticated browser session. Facturia automates exactly that — a certificate-authenticated session
driving the real upload — and models it as an async job with honest states, because that is what it
is.
If the SII changes that form, the job fails and we tell you. There is no stable API underneath to protect us.
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"
}The guardrails
confirm_total_payable is required and must equal the figure in the proposal, or you get
422 f29_amount_confirmation_mismatch. Filing a tax return is not something an API should let you do
by accident.
That field does two things at once: it forces you to read the proposal before filing, and it forces the figure to appear explicitly in your own code — which means it appears explicitly on whatever screen or message your system shows before the button gets pressed.
The job states
status | Meaning |
|---|---|
queued | Accepted; waiting for a filing worker |
preparing | Generating and validating the upload file |
uploading | Authenticated session open at the SII, sending |
submitted | Uploaded; waiting for the SII's acknowledgement |
accepted | Filed. folio and receipt_url are populated |
rejected | The SII rejected the return; errors[] explains |
failed | We couldn't complete the submission (SII down, session refused). Retriable |
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"Events: tax.f29.filing.submitted, tax.f29.filing.succeeded, tax.f29.filing.rejected,
tax.f29.filing.failed.
A filing supports neither PATCH nor DELETE. A filed F29 is corrected with a rectificatoria, an
amended return, which is out of scope for v1.
Automatic filing
auto_file_f29 ships off, like every automation.
| Setting | Default | Effect |
|---|---|---|
auto_file_f29 | false | Files the period's F29 on auto_file_f29_day |
auto_file_f29_day | 18 | The day of the month it files on |
auto_file_f29_max_payable | 0 | Only files on its own if the computed total_payable is at or below this cap |
With the cap at 0 — the factory value — only a zero or in-your-favour position files itself, and any month where you actually owe IVA waits for you. Raise the cap deliberately, empresa by empresa.
Trap
A proposal with observations never files itself
If there are observations with severity: error, automatic filing is suppressed and
tax.f29.review_required fires. Filing an F29 is a legally binding declaration: we ship the
capability because a small company that wants it shouldn't have to log into the SII on the 18th, but
it is opt-in per empresa, capped, and it publishes tax.f29.filing.succeeded / .failed so you can
supervise it.
Characterization
The write that decides whether the IVA on a purchase is recoverable, shared-use or not recoverable at all — and why doing it through an API is a real advantage.
Foreign digital services and tipo 46
The three-step cycle — enter the charge, read the suggestion, confirm — and where the charges come from if you don't have them.