# Tax (/en/docs/referencia/impuestos)

Base: `https://api.facturia.cl/v1`. Every endpoint in this chapter authenticates with `Authorization: Bearer` unless stated otherwise, and the error envelope is the one in [Errors](/en/docs/errores).

| Method   | Path                                                                                                | What it does                                                 |
| -------- | --------------------------------------------------------------------------------------------------- | ------------------------------------------------------------ |
| `GET`    | [`/tax/purchases`](#get-tax-purchases)                                                              | RCV — registro de compras                                    |
| `GET`    | [`/tax/sales`](#get-tax-sales)                                                                      | RCV — registro de ventas                                     |
| `GET`    | [`/tax/summary`](#get-tax-summary)                                                                  | Aggregated RCV totals for a period (the F29 inputs)          |
| `POST`   | [`/tax/sync`](#post-tax-sync)                                                                       | Force an RCV resync (async)                                  |
| `POST`   | [`/tax/purchases/characterize`](#post-tax-purchases-characterize)                                   | Caracterizar up to 500 purchase entries in one call          |
| `POST`   | [`/tax/purchases/{entry_id}/characterize`](#post-tax-purchases-entry-id-characterize)               | Caracterizar one purchase entry (writes to the SII registry) |
| `POST`   | [`/tax/purchases/{entry_id}/characterize/revert`](#post-tax-purchases-entry-id-characterize-revert) | Undo the last settled caracterización on a purchase          |
| `POST`   | [`/tax/purchases/{entry_id}/estado_contable`](#post-tax-purchases-entry-id-estado-contable)         | Move an entry between REGISTRO / PENDIENTE / NO\_INCLUIR     |
| `GET`    | [`/tax/f29/proposals`](#get-tax-f29-proposals)                                                      | List the periods that have a computed propuesta              |
| `GET`    | [`/tax/f29/proposals/{period}`](#get-tax-f29-proposals-period)                                      | Computed F29 propuesta for a period                          |
| `GET`    | [`/tax/f29/proposals/{period}/upload_file`](#get-tax-f29-proposals-period-upload-file)              | Download the SII-format upload .txt for this proposal        |
| `POST`   | [`/tax/f29/proposals/{period}/public_links`](#post-tax-f29-proposals-period-public-links)           | Mint a no-auth link to the propuesta's upload .txt           |
| `DELETE` | [`/tax/f29/proposals/{period}/public_links`](#delete-tax-f29-proposals-period-public-links)         | Revoke every public link for this propuesta                  |
| `POST`   | [`/tax/f29/proposals/{period}/recompute`](#post-tax-f29-proposals-period-recompute)                 | Recompute the proposal, optionally overriding codes          |
| `GET`    | [`/tax/f29/filings`](#get-tax-f29-filings)                                                          | List F29 filings                                             |
| `POST`   | [`/tax/f29/filings`](#post-tax-f29-filings)                                                         | File the F29 for a period (async job)                        |
| `GET`    | [`/tax/f29/filings/{filing_id}`](#get-tax-f29-filings-filing-id)                                    | Retrieve a filing                                            |
| `GET`    | [`/tax/expenses`](#get-tax-expenses)                                                                | List ingested foreign-currency charges                       |
| `POST`   | [`/tax/expenses`](#post-tax-expenses)                                                               | Ingest a charge that may require a tipo-46 factura de compra |
| `GET`    | [`/tax/suggestions`](#get-tax-suggestions)                                                          | List tax suggestions                                         |
| `GET`    | [`/tax/suggestions/{suggestion_id}`](#get-tax-suggestions-suggestion-id)                            | Retrieve a suggestion                                        |
| `POST`   | [`/tax/suggestions/{suggestion_id}/confirm`](#post-tax-suggestions-suggestion-id-confirm)           | Act on a suggestion (for `emit_46`, emits the document)      |
| `POST`   | [`/tax/suggestions/{suggestion_id}/dismiss`](#post-tax-suggestions-suggestion-id-dismiss)           | Dismiss a suggestion                                         |

## `GET /tax/purchases` [#get-tax-purchases]

**RCV — registro de compras**

The purchases ledger (Registro de Compras) synced from the SII, filterable by period, with each entry's `estado_contable` and any `characterize` outcome.

```bash
curl -sS https://api.facturia.cl/v1/tax/purchases \
  -H "Authorization: Bearer $FACTURIA_KEY" \
  -H "Facturia-Empresa: $EMPRESA"
```

**Parameters**

| Parameter          | In     | Required | Type                                                  | Notes                                                                                                                                                                                                                                                                                                                                                       |
| ------------------ | ------ | -------- | ----------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `Facturia-Empresa` | header | —        | string                                                | Target empresa: canonical RUT (`77928532-4`) or empresa id (`emp_…`). Required on every empresa-scoped call unless the key is an empresa token. This header is the ONLY mechanism: there is no `?empresa=` query parameter and no `empresa` body field. Omitted where required → `400 empresa_required`; outside the allowlist → `403 empresa_not_allowed`. |
| `limit`            | query  | —        | integer                                               |                                                                                                                                                                                                                                                                                                                                                             |
| `cursor`           | query  | —        | string                                                | Opaque cursor from a previous response's `next_cursor`.                                                                                                                                                                                                                                                                                                     |
| `period`           | query  | —        | Period                                                | Tax period, `YYYY-MM`, America/Santiago.                                                                                                                                                                                                                                                                                                                    |
| `estado_contable`  | query  | —        | `REGISTRO` · `PENDIENTE` · `NO_INCLUIR` · `RECLAMADO` |                                                                                                                                                                                                                                                                                                                                                             |
| `tipo_dte`         | query  | —        | `33` · `34` · `39` · `41` · `46` · `52` · `56` · `61` |                                                                                                                                                                                                                                                                                                                                                             |
| `counterparty_rut` | query  | —        | Rut                                                   |                                                                                                                                                                                                                                                                                                                                                             |

**Responses**

| Code      | Meaning                                                                                                                                                                                                                                                                                                 | Body          |
| --------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------- |
| `200`     | RCV purchase entries, with sync freshness metadata.                                                                                                                                                                                                                                                     | RcvEntryList  |
| `401`     | Missing, malformed or revoked key.                                                                                                                                                                                                                                                                      | ErrorResponse |
| `403`     | Valid key, not permitted — scope, empresa allowlist, or mode.                                                                                                                                                                                                                                           | ErrorResponse |
| `429`     | Too many requests.                                                                                                                                                                                                                                                                                      | ErrorResponse |
| `default` | An error not otherwise enumerated for this operation, in the same §5.5 envelope as every other refusal. Branch on `error.code`, never on the HTTP status alone or on `error.message` — a code this operation has not been seen to throw yet is still safer to route on than a string meant for a human. | ErrorResponse |

## `GET /tax/sales` [#get-tax-sales]

**RCV — registro de ventas**

The sales ledger (Registro de Ventas) synced from the SII, filterable by period.

```bash
curl -sS https://api.facturia.cl/v1/tax/sales \
  -H "Authorization: Bearer $FACTURIA_KEY" \
  -H "Facturia-Empresa: $EMPRESA"
```

**Parameters**

| Parameter          | In     | Required | Type                                                  | Notes                                                                                                                                                                                                                                                                                                                                                       |
| ------------------ | ------ | -------- | ----------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `Facturia-Empresa` | header | —        | string                                                | Target empresa: canonical RUT (`77928532-4`) or empresa id (`emp_…`). Required on every empresa-scoped call unless the key is an empresa token. This header is the ONLY mechanism: there is no `?empresa=` query parameter and no `empresa` body field. Omitted where required → `400 empresa_required`; outside the allowlist → `403 empresa_not_allowed`. |
| `limit`            | query  | —        | integer                                               |                                                                                                                                                                                                                                                                                                                                                             |
| `cursor`           | query  | —        | string                                                | Opaque cursor from a previous response's `next_cursor`.                                                                                                                                                                                                                                                                                                     |
| `period`           | query  | —        | Period                                                | Tax period, `YYYY-MM`, America/Santiago.                                                                                                                                                                                                                                                                                                                    |
| `tipo_dte`         | query  | —        | `33` · `34` · `39` · `41` · `46` · `52` · `56` · `61` |                                                                                                                                                                                                                                                                                                                                                             |
| `counterparty_rut` | query  | —        | Rut                                                   |                                                                                                                                                                                                                                                                                                                                                             |

**Responses**

| Code      | Meaning                                                                                                                                                                                                                                                                                                 | Body          |
| --------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------- |
| `200`     | RCV sales entries.                                                                                                                                                                                                                                                                                      | RcvEntryList  |
| `401`     | Missing, malformed or revoked key.                                                                                                                                                                                                                                                                      | ErrorResponse |
| `403`     | Valid key, not permitted — scope, empresa allowlist, or mode.                                                                                                                                                                                                                                           | ErrorResponse |
| `429`     | Too many requests.                                                                                                                                                                                                                                                                                      | ErrorResponse |
| `default` | An error not otherwise enumerated for this operation, in the same §5.5 envelope as every other refusal. Branch on `error.code`, never on the HTTP status alone or on `error.message` — a code this operation has not been seen to throw yet is still safer to route on than a string meant for a human. | ErrorResponse |

## `GET /tax/summary` [#get-tax-summary]

**Aggregated RCV totals for a period (the F29 inputs)**

Period totals across purchases and sales — the numbers an F29 proposal is built from, before any characterization is applied.

```bash
curl -sS https://api.facturia.cl/v1/tax/summary \
  -H "Authorization: Bearer $FACTURIA_KEY" \
  -H "Facturia-Empresa: $EMPRESA"
```

**Parameters**

| Parameter          | In     | Required | Type   | Notes                                                                                                                                                                                                                                                                                                                                                       |
| ------------------ | ------ | -------- | ------ | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `Facturia-Empresa` | header | —        | string | Target empresa: canonical RUT (`77928532-4`) or empresa id (`emp_…`). Required on every empresa-scoped call unless the key is an empresa token. This header is the ONLY mechanism: there is no `?empresa=` query parameter and no `empresa` body field. Omitted where required → `400 empresa_required`; outside the allowlist → `403 empresa_not_allowed`. |
| `period`           | query  | yes      | Period |                                                                                                                                                                                                                                                                                                                                                             |

**Responses**

| Code      | Meaning                                                                                                                                                                                                                                                                                                 | Body          |
| --------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------- |
| `200`     | Aggregation by direction and doc type.                                                                                                                                                                                                                                                                  | TaxSummary    |
| `401`     | Missing, malformed or revoked key.                                                                                                                                                                                                                                                                      | ErrorResponse |
| `403`     | Valid key, not permitted — scope, empresa allowlist, or mode.                                                                                                                                                                                                                                           | ErrorResponse |
| `429`     | Too many requests.                                                                                                                                                                                                                                                                                      | ErrorResponse |
| `default` | An error not otherwise enumerated for this operation, in the same §5.5 envelope as every other refusal. Branch on `error.code`, never on the HTTP status alone or on `error.message` — a code this operation has not been seen to throw yet is still safer to route on than a string meant for a human. | ErrorResponse |

## `POST /tax/sync` [#post-tax-sync]

**Force an RCV resync (async)**

Trigger a fresh pull of the purchases and sales ledgers from the SII for the empresa, for ONE
period. Returns a `job` (`type: rcv_sync`) to poll on `GET /jobs/\{job_id\}`; the ledger updates
only once it succeeds, and `result` then carries what was read.

**`period` defaults to the previous month** (America/Santiago), and the job always reports the
period it read in `result.period`. The daily sync reads the last three months, and the first
sweep after an empresa's first successful sync backfills the twelve months before that; anything
older has NEVER been read unless somebody asked for it here — a `sync.last_synced_at` of `null`
on `GET /tax/sales?period=…` is how you can tell. To reach further back, call this once per
period; the bucket is 10 requests per minute per empresa.

**Force means force.** A call while a sync for the same period is still queued or running
attaches to that job rather than queueing a second one; a call after it has finished queues a
fresh read, whatever the daily sync did this morning.

```bash
curl -sS -X POST https://api.facturia.cl/v1/tax/sync \
  -H "Authorization: Bearer $FACTURIA_KEY" \
  -H "Facturia-Empresa: $EMPRESA" \
  -H "Idempotency-Key: $(uuidgen)" \
  -H "Content-Type: application/json" \
  -d '{"period":"2026-07"}'
```

**Parameters**

| Parameter          | In     | Required | Type   | Notes                                                                                                                                                                                                                                                                                                                                                       |
| ------------------ | ------ | -------- | ------ | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `Facturia-Empresa` | header | —        | string | Target empresa: canonical RUT (`77928532-4`) or empresa id (`emp_…`). Required on every empresa-scoped call unless the key is an empresa token. This header is the ONLY mechanism: there is no `?empresa=` query parameter and no `empresa` body field. Omitted where required → `400 empresa_required`; outside the allowlist → `403 empresa_not_allowed`. |
| `Idempotency-Key`  | header | —        | string | Client-generated key, unique per logical operation, retained 24h and scoped to (account, empresa, endpoint). Replays return the original response with `Facturia-Idempotent-Replay: true`. Same key + different body → `409`.                                                                                                                               |

**Body**

| Field         | Type   | Required | Notes                                                       |
| ------------- | ------ | -------- | ----------------------------------------------------------- |
| `period`      | Period | —        | Tax period `YYYY-MM` (America/Santiago). E.g.: `"2026-07"`. |
| **Responses** |        |          |                                                             |

| Code      | Meaning                                                                                                                                                                                                                                                                                                 | Body          |
| --------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------- |
| `202`     | Sync job accepted.                                                                                                                                                                                                                                                                                      | Job           |
| `401`     | Missing, malformed or revoked key.                                                                                                                                                                                                                                                                      | ErrorResponse |
| `403`     | Valid key, not permitted — scope, empresa allowlist, or mode.                                                                                                                                                                                                                                           | ErrorResponse |
| `429`     | Too many requests.                                                                                                                                                                                                                                                                                      | ErrorResponse |
| `default` | An error not otherwise enumerated for this operation, in the same §5.5 envelope as every other refusal. Branch on `error.code`, never on the HTTP status alone or on `error.message` — a code this operation has not been seen to throw yet is still safer to route on than a string meant for a human. | ErrorResponse |

## `POST /tax/purchases/characterize` [#post-tax-purchases-characterize]

**Caracterizar up to 500 purchase entries in one call**

Characterize purchase-ledger entries in bulk (`entry_ids[]` plus the shared `estado_contable`/tax treatment), for the common case of clearing a whole period at once.

```bash
curl -sS -X POST https://api.facturia.cl/v1/tax/purchases/characterize \
  -H "Authorization: Bearer $FACTURIA_KEY" \
  -H "Facturia-Empresa: $EMPRESA" \
  -H "Idempotency-Key: $(uuidgen)" \
  -H "Content-Type: application/json" \
  -d '{"entries":[{"id":"rcv_01K2RB7Q2M4X","tipo_compra":"del_giro"}]}'
```

**Parameters**

| Parameter          | In     | Required | Type   | Notes                                                                                                                                                                                                                                                                                                                                                       |
| ------------------ | ------ | -------- | ------ | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `Facturia-Empresa` | header | —        | string | Target empresa: canonical RUT (`77928532-4`) or empresa id (`emp_…`). Required on every empresa-scoped call unless the key is an empresa token. This header is the ONLY mechanism: there is no `?empresa=` query parameter and no `empresa` body field. Omitted where required → `400 empresa_required`; outside the allowlist → `403 empresa_not_allowed`. |
| `Idempotency-Key`  | header | —        | string | Client-generated key, unique per logical operation, retained 24h and scoped to (account, empresa, endpoint). Replays return the original response with `Facturia-Idempotent-Replay: true`. Same key + different body → `409`.                                                                                                                               |

**Body**

| Field         | Type                         | Required | Notes |
| ------------- | ---------------------------- | -------- | ----- |
| `entries`     | object + Characterization\[] | yes      |       |
| **Responses** |                              |          |       |

| Code      | Meaning                                                                                                                                                                                                                                                                                                 | Body          |
| --------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------- |
| `200`     | Per-entry results.                                                                                                                                                                                                                                                                                      | object        |
| `401`     | Missing, malformed or revoked key.                                                                                                                                                                                                                                                                      | ErrorResponse |
| `403`     | Valid key, not permitted — scope, empresa allowlist, or mode.                                                                                                                                                                                                                                           | ErrorResponse |
| `429`     | Too many requests.                                                                                                                                                                                                                                                                                      | ErrorResponse |
| `default` | An error not otherwise enumerated for this operation, in the same §5.5 envelope as every other refusal. Branch on `error.code`, never on the HTTP status alone or on `error.message` — a code this operation has not been seen to throw yet is still safer to route on than a string meant for a human. | ErrorResponse |

## `POST /tax/purchases/{entry_id}/characterize` [#post-tax-purchases-entry-id-characterize]

**Caracterizar one purchase entry (writes to the SII registry)**

Characterize one purchase-ledger entry — its `estado_contable` and whether its IVA is recoverable — overriding the SII's own proposal where the empresa's own accounting disagrees.

```bash
curl -sS -X POST https://api.facturia.cl/v1/tax/purchases/rcv_01K2RB7Q2M4X/characterize \
  -H "Authorization: Bearer $FACTURIA_KEY" \
  -H "Facturia-Empresa: $EMPRESA" \
  -H "Idempotency-Key: $(uuidgen)" \
  -H "Content-Type: application/json" \
  -d '{"tipo_compra":"del_giro","iva_uso_comun":true}'
```

**Parameters**

| Parameter          | In     | Required | Type   | Notes                                                                                                                                                                                                                                                                                                                                                       |
| ------------------ | ------ | -------- | ------ | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `entry_id`         | path   | yes      | string |                                                                                                                                                                                                                                                                                                                                                             |
| `Facturia-Empresa` | header | —        | string | Target empresa: canonical RUT (`77928532-4`) or empresa id (`emp_…`). Required on every empresa-scoped call unless the key is an empresa token. This header is the ONLY mechanism: there is no `?empresa=` query parameter and no `empresa` body field. Omitted where required → `400 empresa_required`; outside the allowlist → `403 empresa_not_allowed`. |
| `Idempotency-Key`  | header | —        | string | Client-generated key, unique per logical operation, retained 24h and scoped to (account, empresa, endpoint). Replays return the original response with `Facturia-Idempotent-Replay: true`. Same key + different body → `409`.                                                                                                                               |

**Body**

| Field                     | Type                                                                             | Required | Notes                                                             |
| ------------------------- | -------------------------------------------------------------------------------- | -------- | ----------------------------------------------------------------- |
| `tipo_compra`             | `del_giro` · `supermercado` · `activo_fijo` · `iva_uso_comun` · `no_recuperable` | —        |                                                                   |
| `iva_uso_comun`           | boolean                                                                          | —        |                                                                   |
| `iva_no_recuperable_code` | integer,null                                                                     | —        | SII reason code, required when `tipo_compra` is `no_recuperable`. |
| **Responses**             |                                                                                  |          |                                                                   |

| Code      | Meaning                                                                                                                                                                                                                                                                                                 | Body          |
| --------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------- |
| `200`     | The updated entry.                                                                                                                                                                                                                                                                                      | RcvEntry      |
| `401`     | Missing, malformed or revoked key.                                                                                                                                                                                                                                                                      | ErrorResponse |
| `403`     | Valid key, not permitted — scope, empresa allowlist, or mode.                                                                                                                                                                                                                                           | ErrorResponse |
| `422`     | Well-formed but violates a domain rule — folios exhausted, acuse window closed.                                                                                                                                                                                                                         | ErrorResponse |
| `429`     | Too many requests.                                                                                                                                                                                                                                                                                      | ErrorResponse |
| `default` | An error not otherwise enumerated for this operation, in the same §5.5 envelope as every other refusal. Branch on `error.code`, never on the HTTP status alone or on `error.message` — a code this operation has not been seen to throw yet is still safer to route on than a string meant for a human. | ErrorResponse |

## `POST /tax/purchases/{entry_id}/characterize/revert` [#post-tax-purchases-entry-id-characterize-revert]

**Undo the last settled caracterización on a purchase**

Queues a NEW caracterización restoring the `previous_tipo_compra` recorded on the last
settled action for this purchase, linked to it by `reverts`. It does not edit or delete the
original: a write to a tax register that happened, happened, and its row is the evidence.

An undo of a write to the SII is itself a write to the SII, so it passes the identical
opt-in gate and the identical confirmation two-step. `409 characterization_nothing_to_revert`
when no settled action exists, or when the last one recorded no previous value.

Reverting to `no_recuperable` needs an `iva_no_recuperable_code`: the SII does not accept one
without a reason, and the reason the earlier characterization used is only recoverable when a
prior action on the same document recorded it.

```bash
curl -sS -X POST https://api.facturia.cl/v1/tax/purchases/rcv_01K2RB7Q2M4X/characterize/revert \
  -H "Authorization: Bearer $FACTURIA_KEY" \
  -H "Facturia-Empresa: $EMPRESA" \
  -H "Idempotency-Key: $(uuidgen)" \
  -H "Content-Type: application/json" \
  -d '{"iva_no_recuperable_code":1,"confirmation_id":"…"}'
```

**Parameters**

| Parameter          | In     | Required | Type   | Notes                                                                                                                                                                                                                                                                                                                                                       |
| ------------------ | ------ | -------- | ------ | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `entry_id`         | path   | yes      | string |                                                                                                                                                                                                                                                                                                                                                             |
| `Facturia-Empresa` | header | —        | string | Target empresa: canonical RUT (`77928532-4`) or empresa id (`emp_…`). Required on every empresa-scoped call unless the key is an empresa token. This header is the ONLY mechanism: there is no `?empresa=` query parameter and no `empresa` body field. Omitted where required → `400 empresa_required`; outside the allowlist → `403 empresa_not_allowed`. |
| `Idempotency-Key`  | header | —        | string | Client-generated key, unique per logical operation, retained 24h and scoped to (account, empresa, endpoint). Replays return the original response with `Facturia-Idempotent-Replay: true`. Same key + different body → `409`.                                                                                                                               |

**Body**

| Field                     | Type                        | Required | Notes                                                            |
| ------------------------- | --------------------------- | -------- | ---------------------------------------------------------------- |
| `iva_no_recuperable_code` | `1` · `2` · `3` · `4` · `9` | —        | Required only when the value being restored is `no_recuperable`. |
| `confirmation_id`         | string                      | —        |                                                                  |
| **Responses**             |                             |          |                                                                  |

| Code      | Meaning                                                                                                                                                                                                                                                                                                 | Body                   |
| --------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ---------------------- |
| `202`     | The queued revert action.                                                                                                                                                                                                                                                                               | CharacterizationAction |
| `401`     | Missing, malformed or revoked key.                                                                                                                                                                                                                                                                      | ErrorResponse          |
| `403`     | Valid key, not permitted — scope, empresa allowlist, or mode.                                                                                                                                                                                                                                           | ErrorResponse          |
| `409`     | State conflict — idempotency reuse, duplicate external\_id, artifact not ready.                                                                                                                                                                                                                         | ErrorResponse          |
| `422`     | Well-formed but violates a domain rule — folios exhausted, acuse window closed.                                                                                                                                                                                                                         | ErrorResponse          |
| `429`     | Too many requests.                                                                                                                                                                                                                                                                                      | ErrorResponse          |
| `default` | An error not otherwise enumerated for this operation, in the same §5.5 envelope as every other refusal. Branch on `error.code`, never on the HTTP status alone or on `error.message` — a code this operation has not been seen to throw yet is still safer to route on than a string meant for a human. | ErrorResponse          |

## `POST /tax/purchases/{entry_id}/estado_contable` [#post-tax-purchases-entry-id-estado-contable]

**Move an entry between REGISTRO / PENDIENTE / NO\_INCLUIR**

Records a LOCAL bookkeeping estado for the purchase. It is written to
`estado_contable_override` and never over `estado_contable`, which belongs to the SII's own
register and is refreshed by every sync.

The F29 propuesta ignores the override unless the empresa's
`honor_estado_contable_override` automation setting is on; the response's
`estado_contable_effective` says which value the propuesta will use. Every write is recorded
with the key that made it and the SII value it did not replace.

Changing an entry's caracterización at the SII is a different act, with a different
endpoint (`POST /tax/purchases/\{entry_id\}/characterize`).

```bash
curl -sS -X POST https://api.facturia.cl/v1/tax/purchases/rcv_01K2RB7Q2M4X/estado_contable \
  -H "Authorization: Bearer $FACTURIA_KEY" \
  -H "Facturia-Empresa: $EMPRESA" \
  -H "Idempotency-Key: $(uuidgen)" \
  -H "Content-Type: application/json" \
  -d '{"estado_contable":"REGISTRO"}'
```

**Parameters**

| Parameter          | In     | Required | Type   | Notes                                                                                                                                                                                                                                                                                                                                                       |
| ------------------ | ------ | -------- | ------ | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `entry_id`         | path   | yes      | string |                                                                                                                                                                                                                                                                                                                                                             |
| `Facturia-Empresa` | header | —        | string | Target empresa: canonical RUT (`77928532-4`) or empresa id (`emp_…`). Required on every empresa-scoped call unless the key is an empresa token. This header is the ONLY mechanism: there is no `?empresa=` query parameter and no `empresa` body field. Omitted where required → `400 empresa_required`; outside the allowlist → `403 empresa_not_allowed`. |
| `Idempotency-Key`  | header | —        | string | Client-generated key, unique per logical operation, retained 24h and scoped to (account, empresa, endpoint). Replays return the original response with `Facturia-Idempotent-Replay: true`. Same key + different body → `409`.                                                                                                                               |

**Body**

| Field             | Type                                                  | Required | Notes |
| ----------------- | ----------------------------------------------------- | -------- | ----- |
| `estado_contable` | `REGISTRO` · `PENDIENTE` · `NO_INCLUIR` · `RECLAMADO` | yes      |       |
| **Responses**     |                                                       |          |       |

| Code      | Meaning                                                                                                                                                                                                                                                                                                 | Body          |
| --------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------- |
| `200`     | The updated entry.                                                                                                                                                                                                                                                                                      | RcvEntry      |
| `401`     | Missing, malformed or revoked key.                                                                                                                                                                                                                                                                      | ErrorResponse |
| `403`     | Valid key, not permitted — scope, empresa allowlist, or mode.                                                                                                                                                                                                                                           | ErrorResponse |
| `429`     | Too many requests.                                                                                                                                                                                                                                                                                      | ErrorResponse |
| `default` | An error not otherwise enumerated for this operation, in the same §5.5 envelope as every other refusal. Branch on `error.code`, never on the HTTP status alone or on `error.message` — a code this operation has not been seen to throw yet is still safer to route on than a string meant for a human. | ErrorResponse |

## `GET /tax/f29/proposals` [#get-tax-f29-proposals]

**List the periods that have a computed propuesta**

A SPEC ADDITION over §12.3, which documents only the per-period read. Without it a caller
reconciling a year, or a dashboard drawing twelve months, has to guess which periods exist
and probe each one — twelve requests, eleven of them `404`.

The rows omit `validation` and `filing_id`: both are one query per proposal, and a caller
scanning a year is asking "which months are computed", which `status` already answers. Read
the single propuesta for those.

```bash
curl -sS https://api.facturia.cl/v1/tax/f29/proposals \
  -H "Authorization: Bearer $FACTURIA_KEY" \
  -H "Facturia-Empresa: $EMPRESA"
```

**Parameters**

| Parameter          | In     | Required | Type    | Notes                                                                                                                                                                                                                                                                                                                                                       |
| ------------------ | ------ | -------- | ------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `Facturia-Empresa` | header | —        | string  | Target empresa: canonical RUT (`77928532-4`) or empresa id (`emp_…`). Required on every empresa-scoped call unless the key is an empresa token. This header is the ONLY mechanism: there is no `?empresa=` query parameter and no `empresa` body field. Omitted where required → `400 empresa_required`; outside the allowlist → `403 empresa_not_allowed`. |
| `limit`            | query  | —        | integer |                                                                                                                                                                                                                                                                                                                                                             |
| `cursor`           | query  | —        | string  | Opaque cursor from a previous response's `next_cursor`.                                                                                                                                                                                                                                                                                                     |

**Responses**

| Code      | Meaning                                                                                                                                                                                                                                                                                                 | Body                 |
| --------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------------------- |
| `200`     | A list of F29 propuestas, newest period first.                                                                                                                                                                                                                                                          | lista de F29Proposal |
| `401`     | Missing, malformed or revoked key.                                                                                                                                                                                                                                                                      | ErrorResponse        |
| `403`     | Valid key, not permitted — scope, empresa allowlist, or mode.                                                                                                                                                                                                                                           | ErrorResponse        |
| `429`     | Too many requests.                                                                                                                                                                                                                                                                                      | ErrorResponse        |
| `default` | An error not otherwise enumerated for this operation, in the same §5.5 envelope as every other refusal. Branch on `error.code`, never on the HTTP status alone or on `error.message` — a code this operation has not been seen to throw yet is still safer to route on than a string meant for a human. | ErrorResponse        |

## `GET /tax/f29/proposals/{period}` [#get-tax-f29-proposals-period]

**Computed F29 propuesta for a period**

Computed by Facturia from the synced RCV plus the empresa's PPM and remanente parameters.
The SII pre-fills its own F29 for its own portal but publishes no API for it.

```bash
curl -sS https://api.facturia.cl/v1/tax/f29/proposals/2026-07 \
  -H "Authorization: Bearer $FACTURIA_KEY" \
  -H "Facturia-Empresa: $EMPRESA"
```

**Parameters**

| Parameter          | In     | Required | Type   | Notes                                                                                                                                                                                                                                                                                                                                                       |
| ------------------ | ------ | -------- | ------ | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `period`           | path   | yes      | Period |                                                                                                                                                                                                                                                                                                                                                             |
| `Facturia-Empresa` | header | —        | string | Target empresa: canonical RUT (`77928532-4`) or empresa id (`emp_…`). Required on every empresa-scoped call unless the key is an empresa token. This header is the ONLY mechanism: there is no `?empresa=` query parameter and no `empresa` body field. Omitted where required → `400 empresa_required`; outside the allowlist → `403 empresa_not_allowed`. |

**Responses**

| Code      | Meaning                                                                                                                                                                                                                                                                                                 | Body          |
| --------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------- |
| `200`     | The proposal.                                                                                                                                                                                                                                                                                           | F29Proposal   |
| `401`     | Missing, malformed or revoked key.                                                                                                                                                                                                                                                                      | ErrorResponse |
| `403`     | Valid key, not permitted — scope, empresa allowlist, or mode.                                                                                                                                                                                                                                           | ErrorResponse |
| `404`     | No such object under this key.                                                                                                                                                                                                                                                                          | ErrorResponse |
| `429`     | Too many requests.                                                                                                                                                                                                                                                                                      | ErrorResponse |
| `default` | An error not otherwise enumerated for this operation, in the same §5.5 envelope as every other refusal. Branch on `error.code`, never on the HTTP status alone or on `error.message` — a code this operation has not been seen to throw yet is still safer to route on than a string meant for a human. | ErrorResponse |

## `GET /tax/f29/proposals/{period}/upload_file` [#get-tax-f29-proposals-period-upload-file]

**Download the SII-format upload .txt for this proposal**

The SII's own upload-ready `.txt` for this F29 period, generated from the same proposal `GET /tax/f29/proposals/\{period\}` returns.

```bash
curl -sS https://api.facturia.cl/v1/tax/f29/proposals/2026-07/upload_file \
  -H "Authorization: Bearer $FACTURIA_KEY" \
  -H "Facturia-Empresa: $EMPRESA"
```

**Parameters**

| Parameter          | In     | Required | Type   | Notes                                                                                                                                                                                                                                                                                                                                                       |
| ------------------ | ------ | -------- | ------ | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `period`           | path   | yes      | Period |                                                                                                                                                                                                                                                                                                                                                             |
| `Facturia-Empresa` | header | —        | string | Target empresa: canonical RUT (`77928532-4`) or empresa id (`emp_…`). Required on every empresa-scoped call unless the key is an empresa token. This header is the ONLY mechanism: there is no `?empresa=` query parameter and no `empresa` body field. Omitted where required → `400 empresa_required`; outside the allowlist → `403 empresa_not_allowed`. |

**Responses**

| Code      | Meaning                                                                                                                                                                                                                                                                                                 | Body          |
| --------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------- |
| `200`     | Fixed-format upload file, ready to submit manually if you prefer.                                                                                                                                                                                                                                       | text/plain    |
| `401`     | Missing, malformed or revoked key.                                                                                                                                                                                                                                                                      | ErrorResponse |
| `403`     | Valid key, not permitted — scope, empresa allowlist, or mode.                                                                                                                                                                                                                                           | ErrorResponse |
| `429`     | Too many requests.                                                                                                                                                                                                                                                                                      | ErrorResponse |
| `default` | An error not otherwise enumerated for this operation, in the same §5.5 envelope as every other refusal. Branch on `error.code`, never on the HTTP status alone or on `error.message` — a code this operation has not been seen to throw yet is still safer to route on than a string meant for a human. | ErrorResponse |

## `POST /tax/f29/proposals/{period}/public_links` [#post-tax-f29-proposals-period-public-links]

**Mint a no-auth link to the propuesta's upload .txt**

`upload_file_url` needs a bearer key, which makes it useless as an MCP `resource_link` —
most MCP hosts cannot attach the caller's OAuth token when dereferencing one. This mints the
same kind of signed, unguessable, expiring link a document's artifacts get (§9.6), serving
the identical ISO-8859-1 bytes.

`tax:read`, not `tax:write`: minting a link publishes nothing and changes no tax position.

```bash
curl -sS -X POST https://api.facturia.cl/v1/tax/f29/proposals/2026-07/public_links \
  -H "Authorization: Bearer $FACTURIA_KEY" \
  -H "Facturia-Empresa: $EMPRESA" \
  -H "Content-Type: application/json" \
  -d '{"artifacts":["upload_file"],"expires_in_days":90}'
```

**Parameters**

| Parameter          | In     | Required | Type   | Notes                                                                                                                                                                                                                                                                                                                                                       |
| ------------------ | ------ | -------- | ------ | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `period`           | path   | yes      | Period |                                                                                                                                                                                                                                                                                                                                                             |
| `Facturia-Empresa` | header | —        | string | Target empresa: canonical RUT (`77928532-4`) or empresa id (`emp_…`). Required on every empresa-scoped call unless the key is an empresa token. This header is the ONLY mechanism: there is no `?empresa=` query parameter and no `empresa` body field. Omitted where required → `400 empresa_required`; outside the allowlist → `403 empresa_not_allowed`. |

**Body**

| Field                | Type             | Required | Notes                                               |
| -------------------- | ---------------- | -------- | --------------------------------------------------- |
| `artifacts`          | `upload_file`\[] | —        | Default: `["upload_file"]`.                         |
| `expires_in_days`    | integer,null     | —        | Default: `90`.                                      |
| `expires_in_seconds` | integer,null     | —        | Clamped to 30s–365d. Wins when both units are sent. |
| **Responses**        |                  |          |                                                     |

| Code      | Meaning                                                                                                                                                                                                                                                                                                 | Body          |
| --------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------- |
| `200`     | The minted link. Capture it — the secret half is stored hashed.                                                                                                                                                                                                                                         | PublicLinks   |
| `401`     | Missing, malformed or revoked key.                                                                                                                                                                                                                                                                      | ErrorResponse |
| `403`     | Valid key, not permitted — scope, empresa allowlist, or mode.                                                                                                                                                                                                                                           | ErrorResponse |
| `404`     | No such object under this key.                                                                                                                                                                                                                                                                          | ErrorResponse |
| `409`     | State conflict — idempotency reuse, duplicate external\_id, artifact not ready.                                                                                                                                                                                                                         | ErrorResponse |
| `429`     | Too many requests.                                                                                                                                                                                                                                                                                      | ErrorResponse |
| `default` | An error not otherwise enumerated for this operation, in the same §5.5 envelope as every other refusal. Branch on `error.code`, never on the HTTP status alone or on `error.message` — a code this operation has not been seen to throw yet is still safer to route on than a string meant for a human. | ErrorResponse |

## `DELETE /tax/f29/proposals/{period}/public_links` [#delete-tax-f29-proposals-period-public-links]

**Revoke every public link for this propuesta**

Revoke every live public link minted for this F29 proposal's upload file.

```bash
curl -sS -X DELETE https://api.facturia.cl/v1/tax/f29/proposals/2026-07/public_links \
  -H "Authorization: Bearer $FACTURIA_KEY" \
  -H "Facturia-Empresa: $EMPRESA"
```

**Parameters**

| Parameter          | In     | Required | Type   | Notes                                                                                                                                                                                                                                                                                                                                                       |
| ------------------ | ------ | -------- | ------ | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `period`           | path   | yes      | Period |                                                                                                                                                                                                                                                                                                                                                             |
| `Facturia-Empresa` | header | —        | string | Target empresa: canonical RUT (`77928532-4`) or empresa id (`emp_…`). Required on every empresa-scoped call unless the key is an empresa token. This header is the ONLY mechanism: there is no `?empresa=` query parameter and no `empresa` body field. Omitted where required → `400 empresa_required`; outside the allowlist → `403 empresa_not_allowed`. |

**Responses**

| Code      | Meaning                                                                                                                                                                                                                                                                                                 | Body          |
| --------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------- |
| `204`     | Revoked. Existing URLs stop resolving immediately.                                                                                                                                                                                                                                                      | —             |
| `401`     | Missing, malformed or revoked key.                                                                                                                                                                                                                                                                      | ErrorResponse |
| `403`     | Valid key, not permitted — scope, empresa allowlist, or mode.                                                                                                                                                                                                                                           | ErrorResponse |
| `429`     | Too many requests.                                                                                                                                                                                                                                                                                      | ErrorResponse |
| `default` | An error not otherwise enumerated for this operation, in the same §5.5 envelope as every other refusal. Branch on `error.code`, never on the HTTP status alone or on `error.message` — a code this operation has not been seen to throw yet is still safer to route on than a string meant for a human. | ErrorResponse |

## `POST /tax/f29/proposals/{period}/recompute` [#post-tax-f29-proposals-period-recompute]

**Recompute the proposal, optionally overriding codes**

Rebuild the F29 proposal from the ledgers and any characterizations recorded since it was last computed. Does not file anything with the SII.

```bash
curl -sS -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":[]}'
```

**Parameters**

| Parameter          | In     | Required | Type   | Notes                                                                                                                                                                                                                                                                                                                                                       |
| ------------------ | ------ | -------- | ------ | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `period`           | path   | yes      | Period |                                                                                                                                                                                                                                                                                                                                                             |
| `Facturia-Empresa` | header | —        | string | Target empresa: canonical RUT (`77928532-4`) or empresa id (`emp_…`). Required on every empresa-scoped call unless the key is an empresa token. This header is the ONLY mechanism: there is no `?empresa=` query parameter and no `empresa` body field. Omitted where required → `400 empresa_required`; outside the allowlist → `403 empresa_not_allowed`. |

**Body**

| Field         | Type      | Required | Notes |
| ------------- | --------- | -------- | ----- |
| `overrides`   | object\[] | —        |       |
| **Responses** |           |          |       |

| Code      | Meaning                                                                                                                                                                                                                                                                                                 | Body          |
| --------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------- |
| `200`     | The recomputed proposal.                                                                                                                                                                                                                                                                                | F29Proposal   |
| `401`     | Missing, malformed or revoked key.                                                                                                                                                                                                                                                                      | ErrorResponse |
| `403`     | Valid key, not permitted — scope, empresa allowlist, or mode.                                                                                                                                                                                                                                           | ErrorResponse |
| `429`     | Too many requests.                                                                                                                                                                                                                                                                                      | ErrorResponse |
| `default` | An error not otherwise enumerated for this operation, in the same §5.5 envelope as every other refusal. Branch on `error.code`, never on the HTTP status alone or on `error.message` — a code this operation has not been seen to throw yet is still safer to route on than a string meant for a human. | ErrorResponse |

## `GET /tax/f29/filings` [#get-tax-f29-filings]

**List F29 filings**

F29 filings recorded for the empresa, newest first, each naming the period and the proposal it was filed from.

```bash
curl -sS https://api.facturia.cl/v1/tax/f29/filings \
  -H "Authorization: Bearer $FACTURIA_KEY" \
  -H "Facturia-Empresa: $EMPRESA"
```

**Parameters**

| Parameter          | In     | Required | Type    | Notes                                                                                                                                                                                                                                                                                                                                                       |
| ------------------ | ------ | -------- | ------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `Facturia-Empresa` | header | —        | string  | Target empresa: canonical RUT (`77928532-4`) or empresa id (`emp_…`). Required on every empresa-scoped call unless the key is an empresa token. This header is the ONLY mechanism: there is no `?empresa=` query parameter and no `empresa` body field. Omitted where required → `400 empresa_required`; outside the allowlist → `403 empresa_not_allowed`. |
| `limit`            | query  | —        | integer |                                                                                                                                                                                                                                                                                                                                                             |
| `cursor`           | query  | —        | string  | Opaque cursor from a previous response's `next_cursor`.                                                                                                                                                                                                                                                                                                     |
| `period[gte]`      | query  | —        | string  |                                                                                                                                                                                                                                                                                                                                                             |

**Responses**

| Code      | Meaning                                                                                                                                                                                                                                                                                                 | Body               |
| --------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------ |
| `200`     | A list of filings.                                                                                                                                                                                                                                                                                      | lista de F29Filing |
| `401`     | Missing, malformed or revoked key.                                                                                                                                                                                                                                                                      | ErrorResponse      |
| `403`     | Valid key, not permitted — scope, empresa allowlist, or mode.                                                                                                                                                                                                                                           | ErrorResponse      |
| `429`     | Too many requests.                                                                                                                                                                                                                                                                                      | ErrorResponse      |
| `default` | An error not otherwise enumerated for this operation, in the same §5.5 envelope as every other refusal. Branch on `error.code`, never on the HTTP status alone or on `error.message` — a code this operation has not been seen to throw yet is still safer to route on than a string meant for a human. | ErrorResponse      |

## `POST /tax/f29/filings` [#post-tax-f29-filings]

**File the F29 for a period (async job)**

There is no SII webservice for filing an F29. Facturia automates the SII "Upload" flow —
a certificate-authenticated session submitting a fixed-format .txt — and models it as a job.
`confirm_total_payable` must equal the proposal's figure.

```bash
curl -sS -X POST 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","confirm_total_payable":1373000}'
```

**Parameters**

| Parameter          | In     | Required | Type   | Notes                                                                                                                                                                                                                                                                                                                                                       |
| ------------------ | ------ | -------- | ------ | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `Facturia-Empresa` | header | —        | string | Target empresa: canonical RUT (`77928532-4`) or empresa id (`emp_…`). Required on every empresa-scoped call unless the key is an empresa token. This header is the ONLY mechanism: there is no `?empresa=` query parameter and no `empresa` body field. Omitted where required → `400 empresa_required`; outside the allowlist → `403 empresa_not_allowed`. |
| `Idempotency-Key`  | header | —        | string | Client-generated key, unique per logical operation, retained 24h and scoped to (account, empresa, endpoint). Replays return the original response with `Facturia-Idempotent-Replay: true`. Same key + different body → `409`.                                                                                                                               |

**Body**

| Field                   | Type    | Required | Notes                                                           |
| ----------------------- | ------- | -------- | --------------------------------------------------------------- |
| `period`                | Period  | yes      | Tax period `YYYY-MM` (America/Santiago). E.g.: `"2026-07"`.     |
| `proposal_id`           | string  | —        |                                                                 |
| `confirm_total_payable` | integer | yes      | Guard against filing the wrong number. Must match the proposal. |
| **Responses**           |         |          |                                                                 |

| Code      | Meaning                                                                                                                                                                                                                                                                                                 | Body          |
| --------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------- |
| `202`     | Filing accepted and queued.                                                                                                                                                                                                                                                                             | F29Filing     |
| `401`     | Missing, malformed or revoked key.                                                                                                                                                                                                                                                                      | ErrorResponse |
| `403`     | Valid key, not permitted — scope, empresa allowlist, or mode.                                                                                                                                                                                                                                           | ErrorResponse |
| `422`     | Well-formed but violates a domain rule — folios exhausted, acuse window closed.                                                                                                                                                                                                                         | ErrorResponse |
| `429`     | Too many requests.                                                                                                                                                                                                                                                                                      | ErrorResponse |
| `default` | An error not otherwise enumerated for this operation, in the same §5.5 envelope as every other refusal. Branch on `error.code`, never on the HTTP status alone or on `error.message` — a code this operation has not been seen to throw yet is still safer to route on than a string meant for a human. | ErrorResponse |

## `GET /tax/f29/filings/{filing_id}` [#get-tax-f29-filings-filing-id]

**Retrieve a filing**

One F29 filing: the period, the filed totals, and the SII's own acknowledgment if one was captured.

```bash
curl -sS https://api.facturia.cl/v1/tax/f29/filings/f29fil_01K2RD9K3M8T \
  -H "Authorization: Bearer $FACTURIA_KEY" \
  -H "Facturia-Empresa: $EMPRESA"
```

**Parameters**

| Parameter          | In     | Required | Type   | Notes                                                                                                                                                                                                                                                                                                                                                       |
| ------------------ | ------ | -------- | ------ | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `filing_id`        | path   | yes      | string |                                                                                                                                                                                                                                                                                                                                                             |
| `Facturia-Empresa` | header | —        | string | Target empresa: canonical RUT (`77928532-4`) or empresa id (`emp_…`). Required on every empresa-scoped call unless the key is an empresa token. This header is the ONLY mechanism: there is no `?empresa=` query parameter and no `empresa` body field. Omitted where required → `400 empresa_required`; outside the allowlist → `403 empresa_not_allowed`. |

**Responses**

| Code      | Meaning                                                                                                                                                                                                                                                                                                 | Body          |
| --------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------- |
| `200`     | The filing.                                                                                                                                                                                                                                                                                             | F29Filing     |
| `401`     | Missing, malformed or revoked key.                                                                                                                                                                                                                                                                      | ErrorResponse |
| `403`     | Valid key, not permitted — scope, empresa allowlist, or mode.                                                                                                                                                                                                                                           | ErrorResponse |
| `404`     | No such object under this key.                                                                                                                                                                                                                                                                          | ErrorResponse |
| `429`     | Too many requests.                                                                                                                                                                                                                                                                                      | ErrorResponse |
| `default` | An error not otherwise enumerated for this operation, in the same §5.5 envelope as every other refusal. Branch on `error.code`, never on the HTTP status alone or on `error.message` — a code this operation has not been seen to throw yet is still safer to route on than a string meant for a human. | ErrorResponse |

## `GET /tax/expenses` [#get-tax-expenses]

**List ingested foreign-currency charges**

Expense-ledger entries imported from a connected bank or accounting feed, filterable by period.

```bash
curl -sS https://api.facturia.cl/v1/tax/expenses \
  -H "Authorization: Bearer $FACTURIA_KEY" \
  -H "Facturia-Empresa: $EMPRESA"
```

**Parameters**

| Parameter          | In     | Required | Type    | Notes                                                                                                                                                                                                                                                                                                                                                       |
| ------------------ | ------ | -------- | ------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `Facturia-Empresa` | header | —        | string  | Target empresa: canonical RUT (`77928532-4`) or empresa id (`emp_…`). Required on every empresa-scoped call unless the key is an empresa token. This header is the ONLY mechanism: there is no `?empresa=` query parameter and no `empresa` body field. Omitted where required → `400 empresa_required`; outside the allowlist → `403 empresa_not_allowed`. |
| `limit`            | query  | —        | integer |                                                                                                                                                                                                                                                                                                                                                             |
| `cursor`           | query  | —        | string  | Opaque cursor from a previous response's `next_cursor`.                                                                                                                                                                                                                                                                                                     |
| `period`           | query  | —        | Period  | Tax period, `YYYY-MM`, America/Santiago.                                                                                                                                                                                                                                                                                                                    |

**Responses**

| Code      | Meaning                                                                                                                                                                                                                                                                                                 | Body                                   |
| --------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------- |
| `200`     | A list of expenses.                                                                                                                                                                                                                                                                                     | lista de ExpenseCreateRequest + object |
| `401`     | Missing, malformed or revoked key.                                                                                                                                                                                                                                                                      | ErrorResponse                          |
| `403`     | Valid key, not permitted — scope, empresa allowlist, or mode.                                                                                                                                                                                                                                           | ErrorResponse                          |
| `429`     | Too many requests.                                                                                                                                                                                                                                                                                      | ErrorResponse                          |
| `default` | An error not otherwise enumerated for this operation, in the same §5.5 envelope as every other refusal. Branch on `error.code`, never on the HTTP status alone or on `error.message` — a code this operation has not been seen to throw yet is still safer to route on than a string meant for a human. | ErrorResponse                          |

## `POST /tax/expenses` [#post-tax-expenses]

**Ingest a charge that may require a tipo-46 factura de compra**

Import expense-ledger entries directly (outside a `connections` sync), for a source the empresa does not have an automatic feed for yet.

```bash
curl -sS -X POST https://api.facturia.cl/v1/tax/expenses \
  -H "Authorization: Bearer $FACTURIA_KEY" \
  -H "Facturia-Empresa: $EMPRESA" \
  -H "Idempotency-Key: $(uuidgen)" \
  -H "Content-Type: application/json" \
  -d '{"provider":"fintoc","amount_original":1050,"currency":"USD","date":"2026-07-31"}'
```

**Parameters**

| Parameter          | In     | Required | Type   | Notes                                                                                                                                                                                                                                                                                                                                                       |
| ------------------ | ------ | -------- | ------ | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `Facturia-Empresa` | header | —        | string | Target empresa: canonical RUT (`77928532-4`) or empresa id (`emp_…`). Required on every empresa-scoped call unless the key is an empresa token. This header is the ONLY mechanism: there is no `?empresa=` query parameter and no `empresa` body field. Omitted where required → `400 empresa_required`; outside the allowlist → `403 empresa_not_allowed`. |
| `Idempotency-Key`  | header | —        | string | Client-generated key, unique per logical operation, retained 24h and scoped to (account, empresa, endpoint). Replays return the original response with `Facturia-Idempotent-Replay: true`. Same key + different body → `409`.                                                                                                                               |

**Body**

| Field             | Type                                     | Required | Notes                                                                                                                                                                                                                                                                                                                          |
| ----------------- | ---------------------------------------- | -------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| `provider`        | object                                   | yes      |                                                                                                                                                                                                                                                                                                                                |
| `description`     | string                                   | —        |                                                                                                                                                                                                                                                                                                                                |
| `amount_original` | number                                   | yes      |                                                                                                                                                                                                                                                                                                                                |
| `currency`        | string                                   | yes      | E.g.: `"USD"`.                                                                                                                                                                                                                                                                                                                 |
| `date`            | string                                   | yes      |                                                                                                                                                                                                                                                                                                                                |
| `fx_rate`         | number                                   | —        | REQUIRED whenever `currency` is not `CLP`; omitting it returns `400 fx_rate_required`. Facturia never invents a rate — it sets the peso base of a tax document.                                                                                                                                                                |
| `fx_source`       | `card_rate` · `sii_observado` · `custom` | —        | `card_rate` (the settlement rate the issuer actually applied) is the documented recommendation. CAVEAT: which rate is definitively correct for tipo 46 on foreign digital services is under review with an accountant and is not settled by a citable ruling; the value you send is stored verbatim and shown on the document. |
| `external_id`     | string                                   | —        |                                                                                                                                                                                                                                                                                                                                |
| **Responses**     |                                          |          |                                                                                                                                                                                                                                                                                                                                |

| Code      | Meaning                                                                                                                                                                                                                                                                                                 | Body          |
| --------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------- |
| `201`     | The stored expense; a suggestion may follow asynchronously.                                                                                                                                                                                                                                             | Expense       |
| `401`     | Missing, malformed or revoked key.                                                                                                                                                                                                                                                                      | ErrorResponse |
| `403`     | Valid key, not permitted — scope, empresa allowlist, or mode.                                                                                                                                                                                                                                           | ErrorResponse |
| `429`     | Too many requests.                                                                                                                                                                                                                                                                                      | ErrorResponse |
| `default` | An error not otherwise enumerated for this operation, in the same §5.5 envelope as every other refusal. Branch on `error.code`, never on the HTTP status alone or on `error.message` — a code this operation has not been seen to throw yet is still safer to route on than a string meant for a human. | ErrorResponse |

## `GET /tax/suggestions` [#get-tax-suggestions]

**List tax suggestions**

Categorization suggestions Facturia derived from imported statements and expenses, awaiting a `confirm` or `dismiss`.

```bash
curl -sS https://api.facturia.cl/v1/tax/suggestions \
  -H "Authorization: Bearer $FACTURIA_KEY" \
  -H "Facturia-Empresa: $EMPRESA"
```

**Parameters**

| Parameter          | In     | Required | Type                                                                       | Notes                                                                                                                                                                                                                                                                                                                                                       |
| ------------------ | ------ | -------- | -------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `Facturia-Empresa` | header | —        | string                                                                     | Target empresa: canonical RUT (`77928532-4`) or empresa id (`emp_…`). Required on every empresa-scoped call unless the key is an empresa token. This header is the ONLY mechanism: there is no `?empresa=` query parameter and no `empresa` body field. Omitted where required → `400 empresa_required`; outside the allowlist → `403 empresa_not_allowed`. |
| `limit`            | query  | —        | integer                                                                    |                                                                                                                                                                                                                                                                                                                                                             |
| `cursor`           | query  | —        | string                                                                     | Opaque cursor from a previous response's `next_cursor`.                                                                                                                                                                                                                                                                                                     |
| `type`             | query  | —        | `emit_46` · `missing_characterization` · `folios_low` · `unclaimed_credit` |                                                                                                                                                                                                                                                                                                                                                             |
| `status`           | query  | —        | `open` · `confirmed` · `auto_confirmed` · `dismissed` · `expired`          |                                                                                                                                                                                                                                                                                                                                                             |
| `period`           | query  | —        | Period                                                                     | Tax period, `YYYY-MM`, America/Santiago.                                                                                                                                                                                                                                                                                                                    |

**Responses**

| Code      | Meaning                                                                                                                                                                                                                                                                                                 | Body                |
| --------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------- |
| `200`     | A list of suggestions.                                                                                                                                                                                                                                                                                  | lista de Suggestion |
| `401`     | Missing, malformed or revoked key.                                                                                                                                                                                                                                                                      | ErrorResponse       |
| `403`     | Valid key, not permitted — scope, empresa allowlist, or mode.                                                                                                                                                                                                                                           | ErrorResponse       |
| `429`     | Too many requests.                                                                                                                                                                                                                                                                                      | ErrorResponse       |
| `default` | An error not otherwise enumerated for this operation, in the same §5.5 envelope as every other refusal. Branch on `error.code`, never on the HTTP status alone or on `error.message` — a code this operation has not been seen to throw yet is still safer to route on than a string meant for a human. | ErrorResponse       |

## `GET /tax/suggestions/{suggestion_id}` [#get-tax-suggestions-suggestion-id]

**Retrieve a suggestion**

One suggestion: what it proposes, and the evidence (matching entries, prior confirmations) it was derived from.

```bash
curl -sS https://api.facturia.cl/v1/tax/suggestions/sug_01K2RE2X7Q9V \
  -H "Authorization: Bearer $FACTURIA_KEY" \
  -H "Facturia-Empresa: $EMPRESA"
```

**Parameters**

| Parameter          | In     | Required | Type   | Notes                                                                                                                                                                                                                                                                                                                                                       |
| ------------------ | ------ | -------- | ------ | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `suggestion_id`    | path   | yes      | string |                                                                                                                                                                                                                                                                                                                                                             |
| `Facturia-Empresa` | header | —        | string | Target empresa: canonical RUT (`77928532-4`) or empresa id (`emp_…`). Required on every empresa-scoped call unless the key is an empresa token. This header is the ONLY mechanism: there is no `?empresa=` query parameter and no `empresa` body field. Omitted where required → `400 empresa_required`; outside the allowlist → `403 empresa_not_allowed`. |

**Responses**

| Code      | Meaning                                                                                                                                                                                                                                                                                                 | Body          |
| --------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------- |
| `200`     | The suggestion.                                                                                                                                                                                                                                                                                         | Suggestion    |
| `401`     | Missing, malformed or revoked key.                                                                                                                                                                                                                                                                      | ErrorResponse |
| `403`     | Valid key, not permitted — scope, empresa allowlist, or mode.                                                                                                                                                                                                                                           | ErrorResponse |
| `429`     | Too many requests.                                                                                                                                                                                                                                                                                      | ErrorResponse |
| `default` | An error not otherwise enumerated for this operation, in the same §5.5 envelope as every other refusal. Branch on `error.code`, never on the HTTP status alone or on `error.message` — a code this operation has not been seen to throw yet is still safer to route on than a string meant for a human. | ErrorResponse |

## `POST /tax/suggestions/{suggestion_id}/confirm` [#post-tax-suggestions-suggestion-id-confirm]

**Act on a suggestion (for `emit_46`, emits the document)**

Accept a suggestion, applying its proposed categorization to the entries it names.

```bash
curl -sS -X POST https://api.facturia.cl/v1/tax/suggestions/sug_01K2RE2X7Q9V/confirm \
  -H "Authorization: Bearer $FACTURIA_KEY" \
  -H "Facturia-Empresa: $EMPRESA" \
  -H "Idempotency-Key: $(uuidgen)"
```

**Parameters**

| Parameter          | In     | Required | Type   | Notes                                                                                                                                                                                                                                                                                                                                                       |
| ------------------ | ------ | -------- | ------ | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `suggestion_id`    | path   | yes      | string |                                                                                                                                                                                                                                                                                                                                                             |
| `Facturia-Empresa` | header | —        | string | Target empresa: canonical RUT (`77928532-4`) or empresa id (`emp_…`). Required on every empresa-scoped call unless the key is an empresa token. This header is the ONLY mechanism: there is no `?empresa=` query parameter and no `empresa` body field. Omitted where required → `400 empresa_required`; outside the allowlist → `403 empresa_not_allowed`. |
| `Idempotency-Key`  | header | —        | string | Client-generated key, unique per logical operation, retained 24h and scoped to (account, empresa, endpoint). Replays return the original response with `Facturia-Idempotent-Replay: true`. Same key + different body → `409`.                                                                                                                               |

**Responses**

| Code      | Meaning                                                                                                                                                                                                                                                                                                 | Body          |
| --------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------- |
| `201`     | The suggestion, with the resulting document when one was emitted.                                                                                                                                                                                                                                       | object        |
| `401`     | Missing, malformed or revoked key.                                                                                                                                                                                                                                                                      | ErrorResponse |
| `403`     | Valid key, not permitted — scope, empresa allowlist, or mode.                                                                                                                                                                                                                                           | ErrorResponse |
| `422`     | Well-formed but violates a domain rule — folios exhausted, acuse window closed.                                                                                                                                                                                                                         | ErrorResponse |
| `429`     | Too many requests.                                                                                                                                                                                                                                                                                      | ErrorResponse |
| `default` | An error not otherwise enumerated for this operation, in the same §5.5 envelope as every other refusal. Branch on `error.code`, never on the HTTP status alone or on `error.message` — a code this operation has not been seen to throw yet is still safer to route on than a string meant for a human. | ErrorResponse |

## `POST /tax/suggestions/{suggestion_id}/dismiss` [#post-tax-suggestions-suggestion-id-dismiss]

**Dismiss a suggestion**

Reject a suggestion without applying it. Facturia does not re-suggest the identical categorization for the same entries.

```bash
curl -sS -X POST https://api.facturia.cl/v1/tax/suggestions/sug_01K2RE2X7Q9V/dismiss \
  -H "Authorization: Bearer $FACTURIA_KEY" \
  -H "Facturia-Empresa: $EMPRESA" \
  -H "Content-Type: application/json" \
  -d '{"reason":"not_digital_service","note":"…"}'
```

**Parameters**

| Parameter          | In     | Required | Type   | Notes                                                                                                                                                                                                                                                                                                                                                       |
| ------------------ | ------ | -------- | ------ | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `suggestion_id`    | path   | yes      | string |                                                                                                                                                                                                                                                                                                                                                             |
| `Facturia-Empresa` | header | —        | string | Target empresa: canonical RUT (`77928532-4`) or empresa id (`emp_…`). Required on every empresa-scoped call unless the key is an empresa token. This header is the ONLY mechanism: there is no `?empresa=` query parameter and no `empresa` body field. Omitted where required → `400 empresa_required`; outside the allowlist → `403 empresa_not_allowed`. |

**Body**

| Field         | Type                                                                    | Required | Notes |
| ------------- | ----------------------------------------------------------------------- | -------- | ----- |
| `reason`      | `not_digital_service` · `already_declared` · `not_applicable` · `other` | —        |       |
| `note`        | string                                                                  | —        |       |
| **Responses** |                                                                         |          |       |

| Code      | Meaning                                                                                                                                                                                                                                                                                                 | Body          |
| --------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------- |
| `200`     | The dismissed suggestion.                                                                                                                                                                                                                                                                               | Suggestion    |
| `401`     | Missing, malformed or revoked key.                                                                                                                                                                                                                                                                      | ErrorResponse |
| `403`     | Valid key, not permitted — scope, empresa allowlist, or mode.                                                                                                                                                                                                                                           | ErrorResponse |
| `429`     | Too many requests.                                                                                                                                                                                                                                                                                      | ErrorResponse |
| `default` | An error not otherwise enumerated for this operation, in the same §5.5 envelope as every other refusal. Branch on `error.code`, never on the HTTP status alone or on `error.message` — a code this operation has not been seen to throw yet is still safer to route on than a string meant for a human. | ErrorResponse |
