# Empresas (/en/docs/referencia/empresas)

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).

This chapter is ordered the way it makes sense to read it, starting with the **mandato**: it is step 1 of both onboarding tracks, and the certificate (or the portal credential) is step 2. Uploading the certificate first works, but the step stays `pending` until the machine reaches `certificate_pending`. The full path is in [From sandbox to production](/en/docs/empezar/produccion).

| Method   | Path                                                                                                                                                                | What it does                                                                        |
| -------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------- |
| `GET`    | [`/empresas`](#get-empresas)                                                                                                                                        | List empresas visible to this key                                                   |
| `POST`   | [`/empresas`](#post-empresas)                                                                                                                                       | Create an empresa                                                                   |
| `GET`    | [`/empresas/{empresa_id}`](#get-empresas-empresa-id)                                                                                                                | Retrieve an empresa                                                                 |
| `PATCH`  | [`/empresas/{empresa_id}`](#patch-empresas-empresa-id)                                                                                                              | Update an empresa                                                                   |
| `DELETE` | [`/empresas/{empresa_id}`](#delete-empresas-empresa-id)                                                                                                             | Delete a SANDBOX empresa                                                            |
| `GET`    | [`/empresas/{empresa_id}/mandato`](#get-empresas-empresa-id-mandato)                                                                                                | Whether the representante legal has signed, against which terms, and how            |
| `POST`   | [`/empresas/{empresa_id}/mandato`](#post-empresas-empresa-id-mandato)                                                                                               | Record the mandato authorizing Facturia to act before the SII                       |
| `DELETE` | [`/empresas/{empresa_id}/mandato`](#delete-empresas-empresa-id-mandato)                                                                                             | Revoke the mandato                                                                  |
| `GET`    | [`/empresas/{empresa_id}/certificate`](#get-empresas-empresa-id-certificate)                                                                                        | Retrieve certificate metadata                                                       |
| `POST`   | [`/empresas/{empresa_id}/certificate`](#post-empresas-empresa-id-certificate)                                                                                       | Upload (or reuse) the empresa's digital certificate                                 |
| `DELETE` | [`/empresas/{empresa_id}/certificate`](#delete-empresas-empresa-id-certificate)                                                                                     | Purge the certificate from the vault (revokes custody, suspends emission)           |
| `GET`    | [`/empresas/{empresa_id}/sfg_credential`](#get-empresas-empresa-id-sfg-credential)                                                                                  | Retrieve the SFG centralizado clave's custody metadata                              |
| `POST`   | [`/empresas/{empresa_id}/sfg_credential`](#post-empresas-empresa-id-sfg-credential)                                                                                 | Store (or replace) the SFG centralizado clave                                       |
| `DELETE` | [`/empresas/{empresa_id}/sfg_credential`](#delete-empresas-empresa-id-sfg-credential)                                                                               | Destroy the SFG centralizado clave (ends custody)                                   |
| `POST`   | [`/empresas/{empresa_id}/mandato/revocation_link`](#post-empresas-empresa-id-mandato-revocation-link)                                                               | Mint the hosted page where the representante legal revokes                          |
| `POST`   | [`/empresas/{empresa_id}/resolucion/verify`](#post-empresas-empresa-id-resolucion-verify)                                                                           | Verify a declared resolución with one production timbraje (Facturia operators only) |
| `GET`    | [`/empresas/{empresa_id}/counterparties`](#get-empresas-empresa-id-counterparties)                                                                                  | Counterparties you have invoiced, with the address and contacts on file for each    |
| `GET`    | [`/contribuyentes/{rut}`](#get-contribuyentes-rut)                                                                                                                  | What the SII publishes about a company, by RUT, and a giro that fits a factura      |
| `GET`    | [`/empresas/{empresa_id}/counterparties/{counterparty_rut}`](#get-empresas-empresa-id-counterparties-counterparty-rut)                                              | What you know about one counterparty, and whether you stated it or we inferred it   |
| `PATCH`  | [`/empresas/{empresa_id}/counterparties/{counterparty_rut}`](#patch-empresas-empresa-id-counterparties-counterparty-rut)                                            | Put a counterparty's razón social, giro and address on file                         |
| `GET`    | [`/empresas/{empresa_id}/counterparties/{counterparty_rut}/contacts`](#get-empresas-empresa-id-counterparties-counterparty-rut-contacts)                            | The contacts on file for one counterparty                                           |
| `POST`   | [`/empresas/{empresa_id}/counterparties/{counterparty_rut}/contacts`](#post-empresas-empresa-id-counterparties-counterparty-rut-contacts)                           | Put a contacto responsable on file                                                  |
| `PATCH`  | [`/empresas/{empresa_id}/counterparties/{counterparty_rut}/contacts/{contact_id}`](#patch-empresas-empresa-id-counterparties-counterparty-rut-contacts-contact-id)  | Edit a contact, promote it, or record an opt-out                                    |
| `DELETE` | [`/empresas/{empresa_id}/counterparties/{counterparty_rut}/contacts/{contact_id}`](#delete-empresas-empresa-id-counterparties-counterparty-rut-contacts-contact-id) | Remove a contact from the address book                                              |
| `GET`    | [`/empresas/{empresa_id}/onboarding`](#get-empresas-empresa-id-onboarding)                                                                                          | Onboarding lifecycle, steps and blocking human actions                              |
| `POST`   | [`/empresas/{empresa_id}/onboarding/links`](#post-empresas-empresa-id-onboarding-links)                                                                             | Mint a link to a hosted representante-legal page                                    |
| `DELETE` | [`/empresas/{empresa_id}/onboarding/links/{step}`](#delete-empresas-empresa-id-onboarding-links-step)                                                               | Revoke a hosted representante-legal link                                            |
| `POST`   | [`/empresas/{empresa_id}/onboarding/go_live`](#post-empresas-empresa-id-onboarding-go-live)                                                                         | Ask the titular to approve the go-live, or state the decision on their behalf       |
| `POST`   | [`/empresas/{empresa_id}/onboarding/steps/{step}/recheck`](#post-empresas-empresa-id-onboarding-steps-step-recheck)                                                 | Tell us a human step was performed, and we go and look                              |
| `POST`   | [`/empresas/{empresa_id}/onboarding/steps/{step}/attest`](#post-empresas-empresa-id-onboarding-steps-step-attest)                                                   | Record that a human performed a step this build cannot probe (#395)                 |
| `POST`   | [`/empresas/{empresa_id}/onboarding/steps/{step}/approve`](#post-empresas-empresa-id-onboarding-steps-step-approve)                                                 | Record the titular's authorization for a step Facturia then performs (#452, #453)   |
| `GET`    | [`/empresas/{empresa_id}/onboarding/certification`](#get-empresas-empresa-id-onboarding-certification)                                                              | The set de pruebas - what was uploaded, what is missing, what the SII said          |
| `POST`   | [`/empresas/{empresa_id}/onboarding/certification/set_file`](#post-empresas-empresa-id-onboarding-certification-set-file)                                           | Upload the set de pruebas the SII issued for this empresa                           |
| `POST`   | [`/empresas/{empresa_id}/onboarding/certification/inputs`](#post-empresas-empresa-id-onboarding-certification-inputs)                                               | Supply the facts the set de pruebas does not carry                                  |
| `GET`    | [`/empresas/{empresa_id}/onboarding/evidence`](#get-empresas-empresa-id-onboarding-evidence)                                                                        | The rendicion de cuentas - what we did on the empresa's behalf                      |
| `GET`    | [`/empresas/{empresa_id}/onboarding/evidence/export`](#get-empresas-empresa-id-onboarding-evidence-export)                                                          | The rendicion de cuentas as one CSV file                                            |
| `GET`    | [`/empresas/{empresa_id}/automation_settings`](#get-empresas-empresa-id-automation-settings)                                                                        | Retrieve per-empresa automation settings                                            |
| `PATCH`  | [`/empresas/{empresa_id}/automation_settings`](#patch-empresas-empresa-id-automation-settings)                                                                      | Update per-empresa automation settings                                              |
| `GET`    | [`/empresas/{empresa_id}/branding`](#get-empresas-empresa-id-branding)                                                                                              | Read logo, default print format and footer text                                     |
| `PATCH`  | [`/empresas/{empresa_id}/branding`](#patch-empresas-empresa-id-branding)                                                                                            | Update logo, default print format and footer text                                   |

## `GET /empresas` [#get-empresas]

**List empresas visible to this key**

List every empresa this key can reach — its own allowlist resolved to real rows, or the whole account for an unrestricted key.

```bash
curl -sS https://api.facturia.cl/v1/empresas \
  -H "Authorization: Bearer $FACTURIA_KEY"
```

**Parameters**

| Parameter | In    | Required | Type                                               | Notes                                                   |
| --------- | ----- | -------- | -------------------------------------------------- | ------------------------------------------------------- |
| `limit`   | query | —        | integer                                            |                                                         |
| `cursor`  | query | —        | string                                             | Opaque cursor from a previous response's `next_cursor`. |
| `status`  | query | —        | `onboarding` · `active` · `suspended` · `archived` |                                                         |

**Responses**

| Code      | Meaning                                                                                                                                                                                                                                                                                                 | Body                                                     |
| --------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------- |
| `200`     | A list of empresas.                                                                                                                                                                                                                                                                                     | lista de [Empresa](/en/docs/referencia/esquemas#empresa) |
| `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 /empresas` [#post-empresas]

**Create an empresa**

In test mode the empresa is born `emitting`: no mandato, no certificate, no certification.
In live mode it starts at `mandato_pending` and progresses through the onboarding state machine.

**`origen` IS REQUIRED IN LIVE MODE** and this operation refuses without it —
`400 invalid_field` with `param: "origen"` (#495). It is not in `required` above because
the mode is a property of the CREDENTIAL, not of the body, and a schema cannot say «required
when the bearer token starts with `sk_live_`»: declaring it unconditionally would make every
sandbox call — where it defaults to `ninguno` — fail a generated client's own validation
before it left the machine. So the rule lives on the `400` below, where a codegen'd client
can at least see it, and in the field's own description.

```bash
curl -sS -X POST https://api.facturia.cl/v1/empresas \
  -H "Authorization: Bearer $FACTURIA_KEY" \
  -H "Idempotency-Key: $(uuidgen)" \
  -H "Content-Type: application/json" \
  -d '{"rut":"77928532-4","legal_name":"Connect SpA"}'
```

**Parameters**

| Parameter         | In     | Required | Type   | Notes                                                                                                                                                                                                                         |
| ----------------- | ------ | -------- | ------ | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `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                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                           |
| -------------------- | -------------------------------------------------------- | -------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `rut`                | Rut                                                      | yes      | Canonical RUT — no dots, one hyphen, uppercase K. E.g.: `"77928532-4"`.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                         |
| `legal_name`         | string                                                   | yes      |                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                 |
| `giro`               | string                                                   | —        |                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                 |
| `acteco`             | integer\[]                                               | —        |                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                 |
| `address`            | Address                                                  | —        |                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                 |
| `codigo_sucursal`    | integer,null                                             | —        | SII branch code (`CdgSIISucur`). Omit, or send null, for casa matriz.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                           |
| `contact_email`      | string                                                   | —        |                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                 |
| `emission_channel`   | `mercado` · `sfg`                                        | —        | How this empresa will emit. `mercado` runs Facturia's certified engine and the eleven-step certification; `sfg` drives the SII's free Sistema de Facturación Gratuito for an empresa that is already enrolled there, and runs a short checklist with no certification in it. Choosing `sfg` for an empresa that is NOT enrolled does not enrol it: the `emisor_verificado` step will say so. Choosing `mercado` for one that is happy on the free portal starts a certification it does not need. `ambiente` is DERIVED from this and is not accepted here — see `Empresa.ambiente`.  Default: `"mercado"`.                                                                                                                                                                                                                                                                                                     |
| `doc_types`          | `33` · `34` · `39` · `41` · `46` · `52` · `56` · `61`\[] | —        | WHAT THIS EMPRESA INTENDS TO EMIT — the declaration that drives certification and which folios are requested; `capabilities.tipos` is what it can emit NOW. Defaults to `[33, 34, 61]`; an explicit `[]` is `400 invalid_field`, because an empresa with zero tipos can never finish certification. Declaring 39 or 41 (boletas) on `emission_channel: sfg` is `422 doc_type_not_supported_on_channel`: the SII's free Portal MIPYME exposes no boleta form. Boletas need the `mercado` channel, where they also add the `habilitacion` step to the checklist.  Default: `[33,34,61]`.                                                                                                                                                                                                                                                                                                                          |
| `origen`             | `gratuito` · `mercado` · `ninguno`                       | —        | **REQUIRED IN LIVE MODE** — an `sk_live_` key that omits it gets `400 invalid_field` with `param: "origen"`, which is the first empresa of every real customer. It is not in this schema's `required` list because the mode is a property of the credential and not of the body; the operation's `400` declares the refusal (#495). Optional in test mode, where it defaults to `ninguno` because a sandbox empresa is born emitting and never meets the wizard this field routes. See the `Origen` schema for what it does and does not decide.                                                                                                                                                                                                                                                                                                                                                                |
| `resolucion`         | ResolucionClaimRequest                                   | —        | **THE RESOLUCIÓN THIS EMPRESA ALREADY HOLDS** (ruling 2026-09-07). Send it when the empresa already invoices electronically through another provider; send `null` to clear it. Both halves are printed on the carátula of every documento tributario electrónico the empresa emits today (`NroResol`, `FchResol`), so an agent can read them off a recent invoice rather than sending anybody to Mi SII. &#x2A;*IT IS A CLAIM, NOT A SKIP.** It writes two columns and moves nothing else: the empresa is still created at `mandato_pending`, still needs the certificate and the mandato, and still certifies unless our own production timbraje proves the resolución. That timbraje is made only when a Facturia operator confirms it for this empresa; until then the claim reads `resolucion.verification_status: pending_verification`. Read `resolucion.verified` on the empresa object for the outcome. |
| `resolucion_boletas` | ResolucionBoletasClaimRequest                            | —        | **THE BOLETA HABILITACIÓN THIS EMPRESA ALREADY HOLDS** (ruling 2026-09-07). Send it alongside `doc_types` containing 39 or 41; send `null` to clear it. It carries no `numero` because the SII issues none for boletas: the habilitación arrives as «habilitados los documentos de boleta electrónica a contar del …», and that date is the whole of it. Verified by a tipo-39/41 production timbraje, exactly as the resolución claim is; refused, the ordinary habilitación steps appear on the checklist instead.                                                                                                                                                                                                                                                                                                                                                                                            |
| **Responses**        |                                                          |          |                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                 |

| Code      | Meaning                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                            | Body                                            |
| --------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ----------------------------------------------- |
| `201`     | The created empresa.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                               | [Empresa](/en/docs/referencia/esquemas#empresa) |
| `400`     | Malformed input. The codes this operation answers:   \* `invalid_rut` — `rut` missing, or its check digit is wrong.   \* `invalid_field` with `param: "legal_name"` — absent or empty.   \* `invalid_field` with `param: "origen"` — &#x2A;*absent, on a live key.** The first     empresa of every real customer hits this if the caller treated the field as     optional because the schema does. See the operation description.   \* `invalid_field` with `param: "doc_types"` — not an array of supported tipos, or     an explicit `[]`.   \* `invalid_field` with `param: "emission_channel"` / `"acteco"` /     `"codigo_sucursal"` — a value outside what the field admits.   \* `invalid_field` with `param: "ambiente"` — `ambiente` is derived and is refused     rather than ignored. | ErrorResponse                                   |
| `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`     | `doc_type_not_supported_on_channel` — `doc_types` names a tipo the resolved `emission_channel` cannot build (39/41 on `sfg`). `error.param` is `doc_types`.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                        | 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 /empresas/{empresa_id}` [#get-empresas-empresa-id]

**Retrieve an empresa**

One empresa: legal identity, `ambiente`, `emission_channel`/`certification_track`, onboarding spine and `capabilities`.

```bash
curl -sS https://api.facturia.cl/v1/empresas/emp_01K2R6ZC4P8QW1VN7T3MHDY9EK \
  -H "Authorization: Bearer $FACTURIA_KEY"
```

**Parameters**

| Parameter    | In   | Required | Type   | Notes |
| ------------ | ---- | -------- | ------ | ----- |
| `empresa_id` | path | yes      | string |       |

**Responses**

| Code      | Meaning                                                                                                                                                                                                                                                                                                 | Body                                            |
| --------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ----------------------------------------------- |
| `200`     | The empresa.                                                                                                                                                                                                                                                                                            | [Empresa](/en/docs/referencia/esquemas#empresa) |
| `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                                   |

## `PATCH /empresas/{empresa_id}` [#patch-empresas-empresa-id]

**Update an empresa**

Update `legal_name`, `giro`, `contact_email`, `acteco`, `origen`, `codigo_sucursal`,
`doc_types`, `emission_channel`, `certification_track` or `status`. `ambiente` is
derived and rejected if sent (`422`); `origen` is the titular's own claim about how the
empresa emits today, correctable, never a canal preference.

Two of these move the onboarding machine and say so in their own descriptions:
`doc_types` (adding a tipo re-opens certification for it; 39/41 need the `mercado`
channel) and `certification_track` (which checklist governs the empresa).

THE PANEL MIRROR IS NARROWER. `PATCH /dashboard/empresas/\{empresa_id\}` — the same
handler behind an account session — accepts only `doc_types` and `certification_track`,
and refuses every other field with `400 invalid_field` naming it. Those two are what the
puesta en marcha wizard has to record; the rest are the taxpayer identity each document
is printed from, and a browser session is not the credential that rewrites what the SII
sees on an invoice. An `sk_` key on THIS path is unaffected.

```bash
curl -sS -X PATCH https://api.facturia.cl/v1/empresas/emp_01K2R6ZC4P8QW1VN7T3MHDY9EK \
  -H "Authorization: Bearer $FACTURIA_KEY" \
  -H "Content-Type: application/json" \
  -d '{"legal_name":"Connect SpA","giro":"…"}'
```

**Parameters**

| Parameter    | In   | Required | Type   | Notes |
| ------------ | ---- | -------- | ------ | ----- |
| `empresa_id` | path | yes      | string |       |

**Body**

| Field                 | Type                                                     | Required | Notes                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                             |
| --------------------- | -------------------------------------------------------- | -------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `legal_name`          | string                                                   | —        |                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                   |
| `giro`                | string                                                   | —        |                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                   |
| `acteco`              | array,null                                               | —        | SII activity codes, most specific first; the first one becomes `&lt;Acteco&gt;` on the emisor block of every document. An empty array — or null — clears it. Omitting the field leaves the stored value alone.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                    |
| `address`             | Address                                                  | —        |                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                   |
| `codigo_sucursal`     | integer,null                                             | —        | SII branch code (`CdgSIISucur`); null clears it back to casa matriz. Omitting the field leaves the stored value alone — a distinction that matters here, because an SFG empresa's Portal MIPYME preview refuses a document whose emisor origin is incomplete.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                     |
| `contact_email`       | string                                                   | —        |                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                   |
| `doc_types`           | `33` · `34` · `39` · `41` · `46` · `52` · `56` · `61`\[] | —        | WHAT THIS EMPRESA INTENDS TO EMIT — the declaration that drives certification and which folios are requested. Read `capabilities.tipos` for what it can emit NOW. An empty array is `400 invalid_field`: an empresa with zero tipos can never finish certification. Omitting the field leaves the stored value alone. ADDING a tipo to an empresa already `emitting` re-opens its checklist at `certification_in_progress` — certification and CAF are per tipo, and the SII authorizes only the types you certified. Adding 39 or 41 is what makes the `habilitacion` step appear, ON EITHER CHANNEL. BOLETAS ARE ALLOWED ON THE `sfg` CHANNEL, and declaring one is how you ask for the habilitación. The SII's free Portal MIPYME exposes no boleta form to anybody, so a 39/41 always leaves through our own engine whatever the empresa emits through — which means an empresa can keep issuing its facturas on the free portal and have us run the boleta certification for it in the background. The `habilitacion` and `folios` steps appear on the free lane's checklist the moment you declare a boleta, and `capabilities.tipos` gains 39/41 once the SII habilitates them. TIPO 46 ON THE `sfg` CHANNEL IS `422 doc_type_not_supported_on_channel`: unlike a boleta, it is not a document our engine builds on that lane, so it needs `emission_channel: "mercado"`. The same refusal fires when `emission_channel` is moved to `sfg` while a 46 is already declared. |
| `certification_track` | `mercado` · `sfg` · `null`                               | —        | WHICH CHECKLIST GOVERNS THIS EMPRESA — settable since #474, because the code has always read it and no surface could state it: `PATCH \{emission_channel: "sfg"\}` moved the tipos, the ambiente and the driver and left the empresa on the ten-step mercado checklist with `blocked_on: mandato`, a list an SFG emisor never runs. `null` means «not pursuing certification» and is a real, permanent answer. Setting it to `null` or to `sfg` HIDES the mercado checklist WITHOUT deleting anything: the step records stay exactly as they are and setting the track back to `mercado` shows them again, unchanged. It is a projection, not a destructive write.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                |
| `origen`              | `gratuito` · `mercado` · `ninguno`                       | —        | Correctable, and the only way an empresa created before the field existed can acquire one.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                        |
| `emission_channel`    | `mercado` · `sfg`                                        | —        | Correctable, like `origen`: an empresa can move onto the SFG lane or off it. Moving to `sfg` sets `ambiente` to `produccion` in the same write, because an empresa in the free system is a production emisor. Moving to `mercado` leaves `ambiente` alone — the resolución is the only thing that moves it the other way. It does NOT change `certification_track` on its own — that is a separate field on this same request body (#474). Those are two facts and each is stated where it belongs.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                               |
| `resolucion`          | ResolucionClaimRequest                                   | —        | **THE RESOLUCIÓN THIS EMPRESA ALREADY HOLDS** (ruling 2026-09-07). Send it when the empresa already invoices electronically through another provider; send `null` to clear it. Both halves are printed on the carátula of every documento tributario electrónico the empresa emits today (`NroResol`, `FchResol`), so an agent can read them off a recent invoice rather than sending anybody to Mi SII. &#x2A;*IT IS A CLAIM, NOT A SKIP.** It writes two columns and moves nothing else: the empresa is still created at `mandato_pending`, still needs the certificate and the mandato, and still certifies unless our own production timbraje proves the resolución. That timbraje is made only when a Facturia operator confirms it for this empresa; until then the claim reads `resolucion.verification_status: pending_verification`. Read `resolucion.verified` on the empresa object for the outcome.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                   |
| `resolucion_boletas`  | ResolucionBoletasClaimRequest                            | —        | **THE BOLETA HABILITACIÓN THIS EMPRESA ALREADY HOLDS** (ruling 2026-09-07). Send it alongside `doc_types` containing 39 or 41; send `null` to clear it. It carries no `numero` because the SII issues none for boletas: the habilitación arrives as «habilitados los documentos de boleta electrónica a contar del …», and that date is the whole of it. Verified by a tipo-39/41 production timbraje, exactly as the resolución claim is; refused, the ordinary habilitación steps appear on the checklist instead.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                              |
| `status`              | `active` · `archived`                                    | —        |                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                   |
| **Responses**         |                                                          |          |                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                   |

| Code      | Meaning                                                                                                                                                                                                                                                                                                 | Body                                            |
| --------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ----------------------------------------------- |
| `200`     | The updated empresa.                                                                                                                                                                                                                                                                                    | [Empresa](/en/docs/referencia/esquemas#empresa) |
| `400`     | Malformed or missing input.                                                                                                                                                                                                                                                                             | ErrorResponse                                   |
| `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                                   |

## `DELETE /empresas/{empresa_id}` [#delete-empresas-empresa-id]

**Delete a SANDBOX empresa**

Throw away a scratch empresa. &#x2A;*Sandbox only.**

A sandbox empresa holds nothing that is a tax record: its documents are mocked, it never
reached the SII, and it reserves nothing — not the RUT (uniqueness is per mode) and not the
`<rut>@dte.facturia.cl` reception alias, which live empresas alone carry. So it can be
deleted, and the empresa plus everything hanging off it goes in one transaction.

A LIVE empresa is `409 empresa_delete_not_allowed`, always. §7.1: emitted documents are tax
records. The two real exits are `DELETE /v1/empresas/\{empresa_id\}/mandato` (ends the
authorization, cláusula 7.1.3) and `PATCH /v1/empresas/\{empresa_id\}` with
`\{"status": "archived"\}` (stops emission and billing); both keep the history.

```bash
curl -sS -X DELETE https://api.facturia.cl/v1/empresas/emp_01K2R6ZC4P8QW1VN7T3MHDY9EK \
  -H "Authorization: Bearer $FACTURIA_KEY"
```

**Parameters**

| Parameter    | In   | Required | Type   | Notes |
| ------------ | ---- | -------- | ------ | ----- |
| `empresa_id` | path | yes      | string |       |

**Responses**

| Code      | Meaning                                                                                                                                                                                                                                                                                                 | Body          |
| --------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------- |
| `204`     | Deleted. No body.                                                                                                                                                                                                                                                                                       | —             |
| `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`     | `empresa_delete_not_allowed` — the empresa is live. Revoke the mandato and/or archive it.                                                                                                                                                                                                               | 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 /empresas/{empresa_id}/mandato` [#get-empresas-empresa-id-mandato]

**Whether the representante legal has signed, against which terms, and how**

The read half of the hosted mode. Mint a `signing_url` with an empty `POST`, send it to
the representante legal, then poll this - completion is observable by the agent that
asked for it, without subscribing to a webhook or inferring it from `steps[].status`.

Two fields answer questions the onboarding checklist cannot. `terms_current: false` on a
`signed` mandato means the text has moved on and the pipeline has already stopped
trusting the acceptance - `POST` again to collect a fresh one. And `acceptance_method`
distinguishes an *aprobacion* (`hosted`: a human of the required role completed a page
that showed them what they were signing) from an *atestacion* (`api`: an integrator's
claim that one did). Those are different pieces of evidence.

`signing_url` is ALWAYS `null` here: only a SHA-256 of the token is stored, so no read
can reproduce it. `POST` with an empty body re-mints, revoking the previous link.

`status: "none"` for an empresa nobody has asked yet. It is a state, not a missing
resource - the empresa exists and you are authorized for it.

Scope: `mandato:write` (which `empresas:write` implies). The scope that mints the link
is the scope that reads whether it was used.

```bash
curl -sS https://api.facturia.cl/v1/empresas/emp_01K2R6ZC4P8QW1VN7T3MHDY9EK/mandato \
  -H "Authorization: Bearer $FACTURIA_KEY"
```

**Parameters**

| Parameter    | In   | Required | Type   | Notes |
| ------------ | ---- | -------- | ------ | ----- |
| `empresa_id` | path | yes      | string |       |

**Responses**

| Code      | Meaning                                                                                                                                                                                                                                                                                                 | Body          |
| --------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------- |
| `200`     | The mandato, or a `none` status when nobody has been asked yet.                                                                                                                                                                                                                                         | Mandato       |
| `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 |

## `POST /empresas/{empresa_id}/mandato` [#post-empresas-empresa-id-mandato]

**Record the mandato authorizing Facturia to act before the SII**

Post the acceptance you collected yourself, or omit the body to receive a hosted
`signing_url` to send the representante legal.

We record that an acceptance happened, by whom, from where, and against which exact
bytes of the mandato text. We do NOT verify a firma electrónica avanzada: whether one
is required is an open legal question, and until it is answered this endpoint claims
no more than the evidence it holds.

While `GET /v1/mandato_terms` reports `status: "draft"`, a live-mode acceptance is
refused with `422 mandato_terms_draft` — the same warning §7.3 prints, enforced.

**Two forms, two scopes (ADR-0012 §4).** No body — mint the enlace de firma for the
representante legal — needs `mandato:write`, which `empresas:write` implies. A body —
asserting a signature you collected in your own flow — is an *atestación* and needs
`mandato:attest` **itself**: `empresas:write` does NOT imply it (corrected 2026-09-03), so
a key that used to post a body under `empresas:write` alone now gets
`403 insufficient_scope` naming `mandato:attest`.

```bash
curl -sS -X POST https://api.facturia.cl/v1/empresas/emp_01K2R6ZC4P8QW1VN7T3MHDY9EK/mandato \
  -H "Authorization: Bearer $FACTURIA_KEY" \
  -H "Content-Type: application/json" \
  -d '{"requested_by":"…","representante_legal":{}}'
```

**Parameters**

| Parameter    | In   | Required | Type   | Notes |
| ------------ | ---- | -------- | ------ | ----- |
| `empresa_id` | path | yes      | string |       |

**Body**

| Field                 | Type              | Required | Notes                                                                                                                                                                                                       |
| --------------------- | ----------------- | -------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `requested_by`        | RequestedBy + any | —        |                                                                                                                                                                                                             |
| `representante_legal` | object            | —        |                                                                                                                                                                                                             |
| `accepted_at`         | string            | —        | When the representante legal accepted. Clamped to now if it is in the future.                                                                                                                               |
| `accepted_ip`         | string            | —        |                                                                                                                                                                                                             |
| `accepted_user_agent` | string            | —        |                                                                                                                                                                                                             |
| `terms_version`       | string            | —        |                                                                                                                                                                                                             |
| `evidence`            | object            | —        | The same facts in the shape a signing page naturally produces. Accepted as an alternative to the flat fields above, and kept verbatim in the rendición de cuentas alongside whatever we recorded ourselves. |
| **Responses**         |                   |          |                                                                                                                                                                                                             |

| Code      | Meaning                                                                                                                                                                                                                                                                                                 | Body          |
| --------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------- |
| `201`     | The mandato.                                                                                                                                                                                                                                                                                            | Mandato       |
| `400`     | Malformed or missing input.                                                                                                                                                                                                                                                                             | ErrorResponse |
| `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 |
| `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 |

## `DELETE /empresas/{empresa_id}/mandato` [#delete-empresas-empresa-id-mandato]

**Revoke the mandato**

Cláusula 7.1: at any time, without cause, without penalty, and without ending the
contract. The empresa moves to `suspended` immediately, everything already queued is
cancelled in the same transaction, and the `mandato` step returns to `action_required`.

**This is an atestación, not a write (ADR-0012 §4, ticket #465).** It is the act with
the largest effect in the contract, so `empresas:write` is NOT enough: send it with
`mandato:attest`, which is granted explicitly, is never implied by `empresas:write` and
is never in the MCP vocabulary. A dashboard session may also call it — a session is the
account holder in person. Anything else gets `403 insufficient_scope`, whose
`error.details` carries `required_scope` and the `\{method, url\}` that mints the hosted
revocation page for the representante legal
(`POST /empresas/\{empresa_id\}/mandato/revocation_link`).

It does NOT destroy the certificate — that is `DELETE .../certificate`, a separate
revocation with its own deadline. And it does not undo what preceded it: the empresa's
position is remembered, so a fresh acceptance returns it to where it was rather than
restarting onboarding.

The empresa stays READABLE while suspended (ticket #515): `GET /empresas/\{id\}`,
`GET .../onboarding` and `GET .../mandato` all answer, `onboarding.blocked_on` names
`mandato`, and `onboarding.pending_action` is the `mandato_revocado` handoff whose
`link.mint` re-signs. `active` is untouched — a right the contract calls reversible is
never implemented as a disappearance.

```bash
curl -sS -X DELETE https://api.facturia.cl/v1/empresas/emp_01K2R6ZC4P8QW1VN7T3MHDY9EK/mandato \
  -H "Authorization: Bearer $FACTURIA_KEY"
```

**Parameters**

| Parameter    | In   | Required | Type   | Notes |
| ------------ | ---- | -------- | ------ | ----- |
| `empresa_id` | path | yes      | string |       |

**Responses**

| Code      | Meaning                                                                                                                                                                                                                                                                                                 | Body          |
| --------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------- |
| `204`     | Revoked. The empresa moves to `suspended`, and stays readable.                                                                                                                                                                                                                                          | —             |
| `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 /empresas/{empresa_id}/certificate` [#get-empresas-empresa-id-certificate]

**Retrieve certificate metadata**

Metadata only. The .pfx and its password are never readable through the API.

```bash
curl -sS https://api.facturia.cl/v1/empresas/emp_01K2R6ZC4P8QW1VN7T3MHDY9EK/certificate \
  -H "Authorization: Bearer $FACTURIA_KEY"
```

**Parameters**

| Parameter    | In   | Required | Type   | Notes |
| ------------ | ---- | -------- | ------ | ----- |
| `empresa_id` | path | yes      | string |       |

**Responses**

| Code      | Meaning                                                                                                                                                                                                                                                                                                 | Body          |
| --------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------- |
| `200`     | Certificate metadata.                                                                                                                                                                                                                                                                                   | Certificate   |
| `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 |

## `POST /empresas/{empresa_id}/certificate` [#post-empresas-empresa-id-certificate]

**Upload (or reuse) the empresa's digital certificate**

Upload the empresa's `.pfx` (`multipart/form-data` with `file` and `password`) or reuse another empresa's valid certificate (`reuse_from_empresa`). An expired certificate is refused at ingest.

```bash
curl -sS -X POST https://api.facturia.cl/v1/empresas/emp_01K2R6ZC4P8QW1VN7T3MHDY9EK/certificate \
  -H "Authorization: Bearer $FACTURIA_KEY" \
  -F "file=…" \
  -F "password=…"
```

**Parameters**

| Parameter    | In   | Required | Type   | Notes |
| ------------ | ---- | -------- | ------ | ----- |
| `empresa_id` | path | yes      | string |       |

**Body (multipart/form-data)**

| Field                | Type   | Required | Notes                                                                                                                                                                            |
| -------------------- | ------ | -------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `file`               | string | —        | PKCS#12 (.pfx) file.                                                                                                                                                             |
| `password`           | string | —        | The .pfx password.                                                                                                                                                               |
| `reuse_from_empresa` | string | —        | Instead of uploading, reference a certificate already held for another empresa on this account. Valid only when that certificate is a SII-authorized user of this empresa's RUT. |
| **Responses**        |        |          |                                                                                                                                                                                  |

| Code      | Meaning                                                                                                                                                                                                                                                                                                 | Body                 |
| --------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------------------- |
| `201`     | Certificate stored and verified.                                                                                                                                                                                                                                                                        | Certificate + object |
| `400`     | Malformed or missing input.                                                                                                                                                                                                                                                                             | ErrorResponse        |
| `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        |

## `DELETE /empresas/{empresa_id}/certificate` [#delete-empresas-empresa-id-certificate]

**Purge the certificate from the vault (revokes custody, suspends emission)**

Remove the stored certificate metadata. The empresa returns to needing one before it can sign anything the SII will accept.

```bash
curl -sS -X DELETE https://api.facturia.cl/v1/empresas/emp_01K2R6ZC4P8QW1VN7T3MHDY9EK/certificate \
  -H "Authorization: Bearer $FACTURIA_KEY"
```

**Parameters**

| Parameter    | In   | Required | Type   | Notes |
| ------------ | ---- | -------- | ------ | ----- |
| `empresa_id` | path | yes      | string |       |

**Responses**

| Code      | Meaning                                                                                                                                                                                                                                                                                                 | Body          |
| --------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------- |
| `204`     | Purged.                                                                                                                                                                                                                                                                                                 | —             |
| `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 /empresas/{empresa_id}/sfg_credential` [#get-empresas-empresa-id-sfg-credential]

**Retrieve the SFG centralizado clave's custody metadata**

Metadata only — whether we hold the clave and when it was stored. The value itself is
never readable through the API: there is no code path in this endpoint that decrypts it.

Only an `emission_channel: sfg` empresa in live mode has one. A mercado empresa signs
with the certificate in custody and never asks the SII to sign for it, and a test-mode
empresa has no Portal MIPYME at all; both answer `422` naming the fix.

```bash
curl -sS https://api.facturia.cl/v1/empresas/emp_01K2R6ZC4P8QW1VN7T3MHDY9EK/sfg_credential \
  -H "Authorization: Bearer $FACTURIA_KEY"
```

**Parameters**

| Parameter    | In   | Required | Type   | Notes |
| ------------ | ---- | -------- | ------ | ----- |
| `empresa_id` | path | yes      | string |       |

**Responses**

| Code      | Meaning                                                                                                                                                                                                                                                                                                 | Body          |
| --------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------- |
| `200`     | The custody record.                                                                                                                                                                                                                                                                                     | SfgCredential |
| `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 |
| `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 /empresas/{empresa_id}/sfg_credential` [#post-empresas-empresa-id-sfg-credential]

**Store (or replace) the SFG centralizado clave**

The value goes straight to the per-tenant vault and its id to the empresa's credential
row; there is no plaintext column. Replacing destroys the outgoing secret first, so the
destruction is in the custody record rather than a side effect nobody can point at.

The response is the same metadata `GET` returns. The clave is not echoed back.

```bash
curl -sS -X POST https://api.facturia.cl/v1/empresas/emp_01K2R6ZC4P8QW1VN7T3MHDY9EK/sfg_credential \
  -H "Authorization: Bearer $FACTURIA_KEY" \
  -H "Content-Type: application/json" \
  -d '{"clave_centralizado":"…"}'
```

**Parameters**

| Parameter    | In   | Required | Type   | Notes |
| ------------ | ---- | -------- | ------ | ----- |
| `empresa_id` | path | yes      | string |       |

**Body**

| Field                | Type   | Required | Notes                                                                                                                                                                                                                                                                                                                                                  |
| -------------------- | ------ | -------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| `clave_centralizado` | string | yes      | The clave of the empresa's certificado CENTRALIZADO at the SII. ONE FIELD NAME, NO SYNONYMS: `clave`, `password` and `clave_tributaria` are refused with `400 invalid_field` rather than coerced. The one mistake this endpoint exists to make impossible is a customer handing us their SII portal password under a field name we were relaxed about. |
| **Responses**        |        |          |                                                                                                                                                                                                                                                                                                                                                        |

| Code      | Meaning                                                                                                                                                                                                                                                                                                 | Body                   |
| --------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ---------------------- |
| `201`     | Stored.                                                                                                                                                                                                                                                                                                 | SfgCredential + object |
| `400`     | Malformed or missing input.                                                                                                                                                                                                                                                                             | ErrorResponse          |
| `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          |
| `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          |

## `DELETE /empresas/{empresa_id}/sfg_credential` [#delete-empresas-empresa-id-sfg-credential]

**Destroy the SFG centralizado clave (ends custody)**

Destroys the bytes. `204` even when there was nothing to destroy — you asked for a state
("you hold nothing of mine"), and that state is the outcome either way.

Unlike `DELETE .../certificate` it does NOT walk the empresa's onboarding back: the next
SFG emission refuses for want of a signing clave, which the emit path already reports
honestly, and a clave can be re-supplied in one call.

```bash
curl -sS -X DELETE https://api.facturia.cl/v1/empresas/emp_01K2R6ZC4P8QW1VN7T3MHDY9EK/sfg_credential \
  -H "Authorization: Bearer $FACTURIA_KEY"
```

**Parameters**

| Parameter    | In   | Required | Type   | Notes |
| ------------ | ---- | -------- | ------ | ----- |
| `empresa_id` | path | yes      | string |       |

**Responses**

| Code      | Meaning                                                                                                                                                                                                                                                                                                 | Body          |
| --------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------- |
| `204`     | Destroyed.                                                                                                                                                                                                                                                                                              | —             |
| `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 |
| `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 /empresas/{empresa_id}/mandato/revocation_link` [#post-empresas-empresa-id-mandato-revocation-link]

**Mint the hosted page where the representante legal revokes**

Cláusula 7.1 belongs to the person who signed, and this is how you put them in front of
it (ticket #465). The acceptance already hands them this address once, and the receipt
e-mail carries it; this endpoint is for every later moment — the e-mail was lost, or
never went out, or the customer is asking their integrator to help them stop.

Holding the link is not holding the power: the page demands the representante legal's
RUT **as recorded on the mandato they signed**, which this response deliberately does
not echo. Minting revokes any previous revocation link, which is what single-use means
when a link is reissued.

The URL is returned EXACTLY ONCE — only a SHA-256 of the token is stored. It does not
expire: the right it addresses does not either.

`409 mandato_not_signed` when nothing is in force, because an address for a right that
cannot be exercised is worse than a refusal that says so.

```bash
curl -sS -X POST https://api.facturia.cl/v1/empresas/emp_01K2R6ZC4P8QW1VN7T3MHDY9EK/mandato/revocation_link \
  -H "Authorization: Bearer $FACTURIA_KEY"
```

**Parameters**

| Parameter    | In   | Required | Type   | Notes |
| ------------ | ---- | -------- | ------ | ----- |
| `empresa_id` | path | yes      | string |       |

**Responses**

| Code      | Meaning                                                                                                                                                                                                                                                                                                 | Body                  |
| --------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | --------------------- |
| `201`     | The link. Returned once.                                                                                                                                                                                                                                                                                | MandatoRevocationLink |
| `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         |

## `POST /empresas/{empresa_id}/resolucion/verify` [#post-empresas-empresa-id-resolucion-verify]

**Verify a declared resolución with one production timbraje (Facturia operators only)**

**OPERATOR ONLY — NOT CALLABLE WITH AN API KEY** (sii-api#581 D1, founder decision
2026-09-23). Documented so an integrator knows what moves `resolucion.verification_status`
and who moves it.

A resolución stated on `POST`/`PATCH /v1/empresas` is a claim. It is verified by asking
the PRODUCTION SII for ONE folio range of one declared factura tipo: the SII refuses a
timbraje for a RUT it has not authorized for that tipo, so a granted range is the proof.
That request is irreversible (a registered range must be used or annulled), so it is made
only when a Facturia operator confirms it for this empresa. Nothing is requested
implicitly, nothing during `POST /v1/empresas`, and nothing against the certification
environment.

Without `confirm: true` the call refuses with `400 confirmation_required` and names the
exact request in the message and in `error.details.request`. With it, the confirmation
(who, when, why) is recorded and ONE `folio_request` job is queued; the SII's answer then
moves `resolucion.verification_status` from `pending_verification` to `verified` or
`refused`. An attempt that gets no answer about the RUT (the SII's edge block, an unusable
certificate) stays `pending_verification`.

`409 resolucion_verification_not_allowed` names the blocking fact in
`error.details.reason`: `sandbox`, `sfg_channel`, `no_claim`, `already_verified`,
`refused`, `in_flight`, `range_registered`, `not_ready` (the empresa is not at
`certificate_verified`) or `no_factura_tipo`.

```bash
curl -sS -X POST https://api.facturia.cl/v1/empresas/emp_01K2R6ZC4P8QW1VN7T3MHDY9EK/resolucion/verify \
  -H "X-Admin-Secret: $FACTURIA_OPERATOR_SECRET" \
  -H "Content-Type: application/json" \
  -d '{"confirm":true,"authorized_by":"…"}'
```

**Parameters**

| Parameter    | In   | Required | Type   | Notes |
| ------------ | ---- | -------- | ------ | ----- |
| `empresa_id` | path | yes      | string |       |

**Body**

| Field           | Type        | Required | Notes                                                                             |
| --------------- | ----------- | -------- | --------------------------------------------------------------------------------- |
| `confirm`       | boolean     | yes      | Must be `true`. Anything else is `400 confirmation_required` and nothing is sent. |
| `authorized_by` | string      | yes      | The person confirming. Recorded beside the SII's answer.                          |
| `reason`        | string,null | —        | Why, in a sentence (the ticket, the customer). Recorded.                          |
| **Responses**   |             |          |                                                                                   |

| Code      | Meaning                                                                                                                                                                                                                                                                                                 | Body                   |
| --------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ---------------------- |
| `202`     | Confirmed. The one production request is queued; the SII's answer lands on `resolucion`.                                                                                                                                                                                                                | ResolucionVerification |
| `400`     | Malformed or missing input.                                                                                                                                                                                                                                                                             | ErrorResponse          |
| `401`     | Missing, malformed or revoked key.                                                                                                                                                                                                                                                                      | 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          |

## `GET /empresas/{empresa_id}/counterparties` [#get-empresas-empresa-id-counterparties]

**Counterparties you have invoiced, with the address and contacts on file for each**

A DERIVED list, not a stored one: it reads the receivers of the documents this empresa
has already emitted (tipos 33, 34, 56 and 61) and joins whatever contacts and address
book entries exist, so the screen opens as a checklist rather than a blank form. A
counterparty that has an address or a contact but no document yet is included.

The address fields come from the address book only. Where none is on file they are null
and so is `source`, which on this list means "nothing recorded" rather than "nothing
known" — the single-counterparty read is the one that falls back to what earlier
documents said.

`has_more` is always `false`. The window bounds the SCAN, not a page of results, and
promising a cursor this shape cannot honour would be worse than saying so.

```bash
curl -sS https://api.facturia.cl/v1/empresas/emp_01K2R6ZC4P8QW1VN7T3MHDY9EK/counterparties \
  -H "Authorization: Bearer $FACTURIA_KEY"
```

**Parameters**

| Parameter    | In   | Required | Type   | Notes |
| ------------ | ---- | -------- | ------ | ----- |
| `empresa_id` | path | yes      | string |       |

**Responses**

| Code      | Meaning                                                                                                                                                                                                                                                                                                 | Body                  |
| --------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | --------------------- |
| `200`     | The counterparties, newest first.                                                                                                                                                                                                                                                                       | lista de Counterparty |
| `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 /contribuyentes/{rut}` [#get-contribuyentes-rut]

**What the SII publishes about a company, by RUT, and a giro that fits a factura**

The razón social and economic activities the SII publishes for a persona jurídica, and a
suggested `giro` that fits the receptor of a factura (at most 40 characters, ISO-8859-1).
For prefilling a customer before the first invoice to them.

The source is the SII's public nómina of personas jurídicas
([https://www.sii.cl/sobre\_el\_sii/nominapersonasjuridicas.html](https://www.sii.cl/sobre_el_sii/nominapersonasjuridicas.html)), which the SII republishes
every few months and does not guarantee to be complete or current. `source.published_at`
says which edition answered. Personas naturales are not in it: their RUTs answer 404, like
a RUT that does not exist.

A SUGGESTION, not a statement: nothing here is written into a document on its own. Show it
to the person, and once confirmed, put it on file with
`PATCH /v1/empresas/\{id\}/counterparties/\{rut\}` — that is what the next emission reads.

`suggested_giro.basis` is `curated` when the text comes from Facturia's short wording for
a common activity code (the official descriptions are usually longer than 40 characters,
and a cut one would change what the factura says), `sii_description` when the official
description fits as it stands. Null when neither applies: ask the person.

Not empresa-scoped: the data is public and about a third party, so no `Facturia-Empresa`
is needed. Limited to 120 requests a minute per account.

```bash
curl -sS https://api.facturia.cl/v1/contribuyentes/{rut} \
  -H "Authorization: Bearer $FACTURIA_KEY"
```

**Parameters**

| Parameter | In   | Required | Type | Notes                                                                                     |
| --------- | ---- | -------- | ---- | ----------------------------------------------------------------------------------------- |
| `rut`     | path | yes      | Rut  | Any persona jurídica's RUT, canonical (`76000002-7`) or with dots, or without the hyphen. |

**Responses**

| Code      | Meaning                                                                                                                                                                                                                                                                                                 | Body          |
| --------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------- |
| `200`     | The contribuyente.                                                                                                                                                                                                                                                                                      | Contribuyente |
| `400`     | Malformed or missing input.                                                                                                                                                                                                                                                                             | ErrorResponse |
| `401`     | Missing, malformed or revoked key.                                                                                                                                                                                                                                                                      | ErrorResponse |
| `403`     | Valid key, not permitted — scope, empresa allowlist, or mode.                                                                                                                                                                                                                                           | ErrorResponse |
| `404`     | The nómina does not list this RUT (a persona natural, or no such company).                                                                                                                                                                                                                              | ErrorResponse |
| `429`     | Too many requests.                                                                                                                                                                                                                                                                                      | ErrorResponse |
| `503`     | The nómina has not been loaded yet (`contribuyentes_unavailable`). Retry after `Retry-After`.                                                                                                                                                                                                           | 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 /empresas/{empresa_id}/counterparties/{counterparty_rut}` [#get-empresas-empresa-id-counterparties-counterparty-rut]

**What you know about one counterparty, and whether you stated it or we inferred it**

Your address book entry for this RUT — the razón social, giro and domicilio we will put
on the next document to it.

Two sources, in the order the emission resolver uses them. If you have put an address on
file, that is the answer and `source` is `api`. If you have not, but you have already
emitted a document to this RUT, the answer is read off the newest one and `source` says
so — that is inference, not a statement, and it is the difference worth knowing before
you spend a folio. If neither exists, this is a 404.

The counterparty has no id: there is exactly one identity per RUT, so the RUT is the key.

```bash
curl -sS https://api.facturia.cl/v1/empresas/emp_01K2R6ZC4P8QW1VN7T3MHDY9EK/counterparties/{counterparty_rut} \
  -H "Authorization: Bearer $FACTURIA_KEY"
```

**Parameters**

| Parameter          | In   | Required | Type   | Notes                                                                                                                                                                                                  |
| ------------------ | ---- | -------- | ------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| `empresa_id`       | path | yes      | string |                                                                                                                                                                                                        |
| `counterparty_rut` | path | yes      | Rut    | The counterparty's RUT, canonical (`76000002-7`). It is the key of the relationship and of the address book entry — a counterparty has no id of its own, because there is exactly one of each per RUT. |

**Responses**

| Code      | Meaning                                                                                                                                                                                                                                                                                                 | Body                 |
| --------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------------------- |
| `200`     | The counterparty.                                                                                                                                                                                                                                                                                       | CounterpartyIdentity |
| `400`     | Malformed or missing input.                                                                                                                                                                                                                                                                             | ErrorResponse        |
| `401`     | Missing, malformed or revoked key.                                                                                                                                                                                                                                                                      | ErrorResponse        |
| `403`     | Valid key, not permitted — scope, empresa allowlist, or mode.                                                                                                                                                                                                                                           | ErrorResponse        |
| `404`     | Nothing is on file for this RUT and no document has ever been emitted to it.                                                                                                                                                                                                                            | 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        |

## `PATCH /empresas/{empresa_id}/counterparties/{counterparty_rut}` [#patch-empresas-empresa-id-counterparties-counterparty-rut]

**Put a counterparty's razón social, giro and address on file**

The SII will not file a factura whose receptor has no giro, dirección and comuna: it
accepts the ENVELOPE and then refuses the DOCUMENT, and the folio is spent either way.
Recording the address here answers that once instead of on every emission — and it is
the only source that can answer for a counterparty you have never invoiced, which is
exactly when the question bites.

An upsert: the first call creates the entry, later ones edit it. There is no POST and no
DELETE, because the entry has no lifecycle of its own.

Partial. A field you do not send keeps its value; a field sent as `null` is cleared.
Every value is held to the same SII schema limit a value sent on a document is held to —
`giro` 40 characters, `address.street` 70, `address.comuna` and `address.city` 20,
`legal_name` 100 — and to the same ISO-8859-1 rule. Over the limit is refused, never
truncated: a silently shortened name of trade would change what every document to this
counterparty says about who they are.

No earlier document is required. Recording an address for a RUT you have not invoiced
yet is the point.

```bash
curl -sS -X PATCH https://api.facturia.cl/v1/empresas/emp_01K2R6ZC4P8QW1VN7T3MHDY9EK/counterparties/{counterparty_rut} \
  -H "Authorization: Bearer $FACTURIA_KEY" \
  -H "Content-Type: application/json" \
  -d '{"legal_name":"Connect SpA","giro":"…"}'
```

**Parameters**

| Parameter          | In   | Required | Type   | Notes                                                                                                                                                                                                  |
| ------------------ | ---- | -------- | ------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| `empresa_id`       | path | yes      | string |                                                                                                                                                                                                        |
| `counterparty_rut` | path | yes      | Rut    | The counterparty's RUT, canonical (`76000002-7`). It is the key of the relationship and of the address book entry — a counterparty has no id of its own, because there is exactly one of each per RUT. |

**Body**

| Field         | Type                | Required | Notes                                                                                                                                                                                                                                                |
| ------------- | ------------------- | -------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `legal_name`  | string,null         | —        | RznSocRecep, at most 100 characters.                                                                                                                                                                                                                 |
| `giro`        | string,null         | —        | GiroRecep, at most 40 characters — half of what the emisor's own giro is allowed, and the cap that bites most often. Refused over the limit, never truncated.                                                                                        |
| `address`     | CounterpartyAddress | —        | The receptor's domicilio, as the SII's own elements: street is DirRecep, comuna is CmnaRecep, city is CiudadRecep. Always present as an object, even when every part of it is null, so a client never has to guard the parent before reading a part. |
| **Responses** |                     |          |                                                                                                                                                                                                                                                      |

| Code      | Meaning                                                                                                                                                                                                                                                                                                 | Body                 |
| --------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------------------- |
| `200`     | The stored counterparty.                                                                                                                                                                                                                                                                                | CounterpartyIdentity |
| `400`     | A malformed RUT, a body naming no field at all, a value longer than the SII element it becomes (`field_too_long`) or one carrying a character ISO-8859-1 cannot represent (`unencodable_character`).                                                                                                    | ErrorResponse        |
| `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 /empresas/{empresa_id}/counterparties/{counterparty_rut}/contacts` [#get-empresas-empresa-id-counterparties-counterparty-rut-contacts]

**The contacts on file for one counterparty**

The primary contact comes first — it is the only one that is notified.

```bash
curl -sS https://api.facturia.cl/v1/empresas/emp_01K2R6ZC4P8QW1VN7T3MHDY9EK/counterparties/{counterparty_rut}/contacts \
  -H "Authorization: Bearer $FACTURIA_KEY"
```

**Parameters**

| Parameter          | In   | Required | Type   | Notes                                                                                                                                                                                                  |
| ------------------ | ---- | -------- | ------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| `empresa_id`       | path | yes      | string |                                                                                                                                                                                                        |
| `counterparty_rut` | path | yes      | Rut    | The counterparty's RUT, canonical (`76000002-7`). It is the key of the relationship and of the address book entry — a counterparty has no id of its own, because there is exactly one of each per RUT. |

**Responses**

| Code      | Meaning                                                                                                                                                                                                                                                                                                 | Body                         |
| --------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ---------------------------- |
| `200`     | The contacts.                                                                                                                                                                                                                                                                                           | lista de CounterpartyContact |
| `400`     | Malformed or missing input.                                                                                                                                                                                                                                                                             | ErrorResponse                |
| `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 /empresas/{empresa_id}/counterparties/{counterparty_rut}/contacts` [#post-empresas-empresa-id-counterparties-counterparty-rut-contacts]

**Put a contacto responsable on file**

A contact with no attestation is a legitimate state: it is stored, it is shown, and it
is never messaged. Sending `opt_in: true` without `opt_in_method` is refused, because
consent recorded without recording how it was obtained is not a record.

The first contact for a counterparty becomes the primary unless you say otherwise.

A number that has opted out cannot be re-added under a new id: that is `422
contact_opted_out`, and it is what stops delete-and-recreate from undoing a STOP.

```bash
curl -sS -X POST https://api.facturia.cl/v1/empresas/emp_01K2R6ZC4P8QW1VN7T3MHDY9EK/counterparties/{counterparty_rut}/contacts \
  -H "Authorization: Bearer $FACTURIA_KEY" \
  -H "Content-Type: application/json" \
  -d '{"name":"cliente — Comercial Andina","phone":"+56912345678"}'
```

**Parameters**

| Parameter          | In   | Required | Type   | Notes                                                                                                                                                                                                  |
| ------------------ | ---- | -------- | ------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| `empresa_id`       | path | yes      | string |                                                                                                                                                                                                        |
| `counterparty_rut` | path | yes      | Rut    | The counterparty's RUT, canonical (`76000002-7`). It is the key of the relationship and of the address book entry — a counterparty has no id of its own, because there is exactly one of each per RUT. |

**Body**

| Field                | Type                                                              | Required | Notes                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                         |
| -------------------- | ----------------------------------------------------------------- | -------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `name`               | string                                                            | yes      |                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                               |
| `phone`              | string                                                            | yes      | E.164. Anything that cannot be brought to that form is `400 invalid_phone`. E.g.: `"+56912345678"`.                                                                                                                                                                                                                                                                                                                                                                                                           |
| `counterparty_name`  | string,null                                                       | —        | Overrides the razón social the documents carried, for display only.                                                                                                                                                                                                                                                                                                                                                                                                                                           |
| `primary`            | boolean                                                           | —        | Defaults to true for the first contact of a counterparty, false afterwards.                                                                                                                                                                                                                                                                                                                                                                                                                                   |
| `opt_in`             | boolean                                                           | —        | Your attestation that this person agreed to receive WhatsApp notifications from you. Omitting it is a legitimate state: the contact is stored as an address-book entry and is never messaged (skip reason `no_optin`).                                                                                                                                                                                                                                                                                        |
| `opt_in_method`      | `en_persona` · `telefono` · `email` · `escrito` · `otro` · `null` | —        | How the person actually agreed to be messaged. `en_persona` = in person or at the point of sale; `telefono` = by phone, recorded by whoever took the call; `email` = by email or a web form; `escrito` = on paper, signed; `otro` = something else, said plainly rather than forced into the nearest fit. WhatsApp's policy is that holding a number is not consent — "an affirmative, disclosed opt-in action is required" — so an attestation without a method is refused with `400 optin_method_required`. |
| `opt_in_attested_by` | string                                                            | —        | Who collected the consent. Defaults to the credential that made the call.                                                                                                                                                                                                                                                                                                                                                                                                                                     |
| **Responses**        |                                                                   |          |                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                               |

| Code      | Meaning                                                                                                                                                                                                                                                                                                 | Body                |
| --------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------- |
| `201`     | The contact.                                                                                                                                                                                                                                                                                            | CounterpartyContact |
| `400`     | Malformed or missing input.                                                                                                                                                                                                                                                                             | ErrorResponse       |
| `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       |

## `PATCH /empresas/{empresa_id}/counterparties/{counterparty_rut}/contacts/{contact_id}` [#patch-empresas-empresa-id-counterparties-counterparty-rut-contacts-contact-id]

**Edit a contact, promote it, or record an opt-out**

`primary: true` demotes whoever held it, in the same call — exactly one contact per
counterparty may be primary and the database is what enforces it.

`opted_out: true` records that the person asked to stop by some other channel.
`opted_out: false` does not exist: an opted-out contact is frozen and cannot be edited,
re-attested or re-enabled. Someone who asked to be left alone is not un-asked by a
colleague fixing a typo in their name.

```bash
curl -sS -X PATCH https://api.facturia.cl/v1/empresas/emp_01K2R6ZC4P8QW1VN7T3MHDY9EK/counterparties/{counterparty_rut}/contacts/{contact_id} \
  -H "Authorization: Bearer $FACTURIA_KEY" \
  -H "Content-Type: application/json" \
  -d '{"name":"cliente — Comercial Andina","phone":"…"}'
```

**Parameters**

| Parameter          | In   | Required | Type   | Notes                                                                                                                                                                                                  |
| ------------------ | ---- | -------- | ------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| `empresa_id`       | path | yes      | string |                                                                                                                                                                                                        |
| `counterparty_rut` | path | yes      | Rut    | The counterparty's RUT, canonical (`76000002-7`). It is the key of the relationship and of the address book entry — a counterparty has no id of its own, because there is exactly one of each per RUT. |
| `contact_id`       | path | yes      | string | The `cnt_…` id.                                                                                                                                                                                        |

**Body**

| Field               | Type                                                              | Required | Notes                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                         |
| ------------------- | ----------------------------------------------------------------- | -------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `name`              | string                                                            | —        |                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                               |
| `phone`             | string                                                            | —        |                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                               |
| `counterparty_name` | string,null                                                       | —        |                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                               |
| `primary`           | boolean                                                           | —        | `true` demotes whoever currently holds it, in the same call. Two primaries cannot exist even momentarily.                                                                                                                                                                                                                                                                                                                                                                                                     |
| `opt_in`            | boolean                                                           | —        | `false` clears the attestation — a consent record that can only ever be added to is worse for the person it exists to protect.                                                                                                                                                                                                                                                                                                                                                                                |
| `opt_in_method`     | `en_persona` · `telefono` · `email` · `escrito` · `otro` · `null` | —        | How the person actually agreed to be messaged. `en_persona` = in person or at the point of sale; `telefono` = by phone, recorded by whoever took the call; `email` = by email or a web form; `escrito` = on paper, signed; `otro` = something else, said plainly rather than forced into the nearest fit. WhatsApp's policy is that holding a number is not consent — "an affirmative, disclosed opt-in action is required" — so an attestation without a method is refused with `400 optin_method_required`. |
| `opted_out`         | boolean                                                           | —        | `true` records that the person asked to stop by another channel. `false` is not accepted: an opt-out is not reversible through this API.                                                                                                                                                                                                                                                                                                                                                                      |
| **Responses**       |                                                                   |          |                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                               |

| Code      | Meaning                                                                                                                                                                                                                                                                                                 | Body                |
| --------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------- |
| `200`     | The updated contact.                                                                                                                                                                                                                                                                                    | CounterpartyContact |
| `400`     | Malformed or missing input.                                                                                                                                                                                                                                                                             | ErrorResponse       |
| `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       |
| `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       |

## `DELETE /empresas/{empresa_id}/counterparties/{counterparty_rut}/contacts/{contact_id}` [#delete-empresas-empresa-id-counterparties-counterparty-rut-contacts-contact-id]

**Remove a contact from the address book**

204 whether or not it was there. The exception is an opted-out contact, which is kept:
its row is precisely what makes re-adding the same number refusable.

```bash
curl -sS -X DELETE https://api.facturia.cl/v1/empresas/emp_01K2R6ZC4P8QW1VN7T3MHDY9EK/counterparties/{counterparty_rut}/contacts/{contact_id} \
  -H "Authorization: Bearer $FACTURIA_KEY"
```

**Parameters**

| Parameter          | In   | Required | Type   | Notes                                                                                                                                                                                                  |
| ------------------ | ---- | -------- | ------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| `empresa_id`       | path | yes      | string |                                                                                                                                                                                                        |
| `counterparty_rut` | path | yes      | Rut    | The counterparty's RUT, canonical (`76000002-7`). It is the key of the relationship and of the address book entry — a counterparty has no id of its own, because there is exactly one of each per RUT. |
| `contact_id`       | path | yes      | string | The `cnt_…` id.                                                                                                                                                                                        |

**Responses**

| Code      | Meaning                                                                                                                                                                                                                                                                                                 | Body          |
| --------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------- |
| `204`     | Removed.                                                                                                                                                                                                                                                                                                | —             |
| `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 /empresas/{empresa_id}/onboarding` [#get-empresas-empresa-id-onboarding]

**Onboarding lifecycle, steps and blocking human actions**

Everything a wizard needs to render progress and tell the user what to do next.

```bash
curl -sS https://api.facturia.cl/v1/empresas/emp_01K2R6ZC4P8QW1VN7T3MHDY9EK/onboarding \
  -H "Authorization: Bearer $FACTURIA_KEY"
```

**Parameters**

| Parameter    | In   | Required | Type   | Notes |
| ------------ | ---- | -------- | ------ | ----- |
| `empresa_id` | path | yes      | string |       |

**Responses**

| Code      | Meaning                                                                                                                                                                                                                                                                                                 | Body                                                  |
| --------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------- |
| `200`     | Onboarding state.                                                                                                                                                                                                                                                                                       | [Onboarding](/en/docs/referencia/esquemas#onboarding) |
| `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                                         |

## `POST /empresas/{empresa_id}/onboarding/links` [#post-empresas-empresa-id-onboarding-links]

**Mint a link to a hosted representante-legal page**

The person who has to act is often not the person holding the account: the account
belongs to the accountant, the certificate belongs to a socio, and the SII steps that
need a person are the socio's. So the hosted pages are reached by a link, not by a
login.

`step` is any step of THIS empresa's checklist that needs a person - `actor: customer`
(the step they perform) OR `stall_actor: customer` (a step of OURS that cannot finish
until they decide). Which ones exist depends on its `certification_track`:
`certificate`, `sii_postulacion`, `cumplimiento` and `habilitacion` on the mercado
catalog; `credential`, `clave_centralizado` and `usuario_autorizado` on the SFG one. A
step from the other catalog is refused with a `400` naming the ones this empresa does
have. The mandato's link is single-use and comes from
`POST /empresas/\{empresa_id\}/mandato` with an empty body instead.

The `url` is returned exactly once - only its SHA-256 is stored. The link is reusable
and lives thirty days, and re-minting revokes the previous one.

The response also carries the step's `pending_action`, with `action_url` set to the URL
just minted: the mint is the one moment both halves exist at once, so an agent gets the
live address and the instructions to relay with it in a single call.

```bash
curl -sS -X POST https://api.facturia.cl/v1/empresas/emp_01K2R6ZC4P8QW1VN7T3MHDY9EK/onboarding/links \
  -H "Authorization: Bearer $FACTURIA_KEY" \
  -H "Content-Type: application/json" \
  -d '{"step":"…"}'
```

**Parameters**

| Parameter    | In   | Required | Type   | Notes |
| ------------ | ---- | -------- | ------ | ----- |
| `empresa_id` | path | yes      | string |       |

**Body**

| Field          | Type        | Required | Notes                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                        |
| -------------- | ----------- | -------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `step`         | string      | yes      | Which hosted page the link opens: any step of THIS empresa's checklist that needs a human - `actor: customer` (they perform it) or `stall_actor: customer` (we perform it and it waits on their decision). `mandato` is deliberately absent: its link is single-use and comes from `POST /empresas/\{empresa_id\}/mandato` with an empty body. Read the valid values off `GET /empresas/\{empresa_id\}/onboarding`.                                                                                                                                                                                                                          |
| `requested_by` | RequestedBy | —        | Who is asking for this link, as YOU describe yourself (2026-09, #459). Optional, and rendered to the person who receives the link: "Este enlace lo pidio Claude Desktop el 4 de septiembre" instead of "lo genero una integracion o un agente en nombre de tu cuenta", which was the only sentence available for every agent that has ever existed. A CLAIM, NOT A CREDENTIAL. It changes nothing about authorization and is never trusted for a decision; the credential your request actually arrived on is recorded separately. Send `\{"kind": "agent", "name": "&lt;your client name&gt;"\}` when you are an agent acting for a person. |
| **Responses**  |             |          |                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                              |

| Code      | Meaning                                                                                                                                                                                                                                                                                                 | Body           |
| --------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------------- |
| `201`     | The link. `url` carries the token and is never shown again.                                                                                                                                                                                                                                             | OnboardingLink |
| `400`     | Malformed or missing input.                                                                                                                                                                                                                                                                             | ErrorResponse  |
| `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  |

## `DELETE /empresas/{empresa_id}/onboarding/links/{step}` [#delete-empresas-empresa-id-onboarding-links-step]

**Revoke a hosted representante-legal link**

204 whether or not one existed. A revoked link answers exactly like one that never
existed, so a token cannot be used to learn whether we ever asked a given company to
sign something.

```bash
curl -sS -X DELETE https://api.facturia.cl/v1/empresas/emp_01K2R6ZC4P8QW1VN7T3MHDY9EK/onboarding/links/{step} \
  -H "Authorization: Bearer $FACTURIA_KEY"
```

**Parameters**

| Parameter    | In   | Required | Type   | Notes                                                                                                                                                                                                |
| ------------ | ---- | -------- | ------ | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `empresa_id` | path | yes      | string |                                                                                                                                                                                                      |
| `step`       | path | yes      | string | The step whose link is being revoked. Any step either catalog can mint a link for - the wider set on purpose, so a link minted under a checklist the empresa has since left can still be taken back. |

**Responses**

| Code      | Meaning                                                                                                                                                                                                                                                                                                 | Body          |
| --------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------- |
| `204`     | Revoked.                                                                                                                                                                                                                                                                                                | —             |
| `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 /empresas/{empresa_id}/onboarding/go_live` [#post-empresas-empresa-id-onboarding-go-live]

**Ask the titular to approve the go-live, or state the decision on their behalf**

The Declaracion de Cumplimiento is a decision about a month, not a progression. On
declaring, the empresa "queda operando automaticamente en el sistema de facturacion
electronica" and owes the Informacion Electronica de Compras y Ventas FROM THE MONTH OF
THE DECLARACION, whether or not it emits anything. The SII's own page says the step may
be postponed.

So the month is the customer's to choose and a custody mandate does not carry it.

**TWO FORMS, and the body is which one.**

* **No body** mints an *enlace de aprobacion* for the titular and answers `201` with
  `approval_url` and `expires_at`. The human opens the page, sees the month and the
  IECV consequence in their own language, and decides. Single use, seven days, and the
  URL is returned exactly once - only its SHA-256 is stored. Scope `onboarding:write`.
* **`\{"authorized": true|false\}`** states the decision on the titular's behalf: an
  *atestacion*, for an integrator that collected it in its own flow. Answers `200` with
  the authorization. Scope `onboarding:attest`.

`empresas:write` implies `onboarding:write` — the no-body form — but NOT
`onboarding:attest` (corrected 2026-09-03): an atestación is a human granting that power
on purpose, every time, never a side effect of a wider grant a key already held. A key
that used to send `\{"authorized": true|false\}` under `empresas:write` alone now gets
`403 insufficient_scope` naming `onboarding:attest`.

**This changed in 2026-09.** An empty body used to DEFAULT to `authorized: true`, so a
caller who sent no body silently authorized a tax consequence. An omitted field is not a
decision; if you were relying on that, send `\{"authorized": true\}` explicitly.

`\{"authorized": false\}` withdraws while nothing has been filed. Once the declaracion is
filed there is nothing left to withdraw and the call is refused with
`409 cumplimiento_already_filed`.

**Refusals arrive together.** The status and code are the first blocker's own - `422
mandato_revoked`, for instance - and `error.details.blockers[]` lists every one, so you
do not learn them one round trip at a time.

**THE AUTHORIZATION IS FREE** (2026-09-04, #530). It used to be gated on the
subscription, and only on this door: the hosted `cumplimiento` page for the
representante legal answered `200` for the same unsubscribed empresa, so the rule lived
in one channel and an agent that sent the human to the other one walked around it. It
is a DECISION, not an emission — the titular saying «start my obligation this month» —
and the gate stands where the value is: every act that spends a folio or leaves the
building is still gated, so an authorized empresa that has not paid emits nothing. This
operation no longer answers `402`.

**There has to BE a decision (2026-09, #451).** Minting an approval link for an empresa
that has not reached the Declaracion de Cumplimiento handed a human a page with nothing
on it. Two refusals come first, before the blockers and before the mint:

* `409 go_live_not_ready` - the mercado lane has not reached the decision.
  `error.details.blocked_on` names the step holding it up and `error.details.next` is
  the `\{method, url\}` that reports when it moves. Retriable: it WILL be ready.
* `409 go_live_not_applicable` - this empresa is not certifying for mercado, so it has
  no Declaracion de Cumplimiento at all. What gates an SFG empresa's emission is
  `puesta_en_vivo`, which is ours. Not retriable.

Neither applies to `\{"authorized": false\}`: a decision that exists can always be
withdrawn, whatever the lane has done since.

```bash
curl -sS -X POST https://api.facturia.cl/v1/empresas/emp_01K2R6ZC4P8QW1VN7T3MHDY9EK/onboarding/go_live \
  -H "Authorization: Bearer $FACTURIA_KEY" \
  -H "Content-Type: application/json" \
  -d '{"authorized":true}'
```

**Parameters**

| Parameter    | In   | Required | Type   | Notes |
| ------------ | ---- | -------- | ------ | ----- |
| `empresa_id` | path | yes      | string |       |

**Body**

| Field         | Type    | Required | Notes                                                                                                                                                                                                                                                                                                                                                                                                                                                                             |
| ------------- | ------- | -------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `authorized`  | boolean | —        | Present at all, this states the decision on the titular's behalf - an *atestacion*, behind `onboarding:attest`. `false` withdraws an authorization that has not been acted on yet; once the declaracion is filed the call is refused with `409 cumplimiento_already_filed`. &#x2A;*No default.** Omit the whole body to mint an approval link for the titular instead. It used to default to `true`, which meant a caller who sent no body silently authorized a tax consequence. |
| **Responses** |         |          |                                                                                                                                                                                                                                                                                                                                                                                                                                                                                   |

| Code      | Meaning                                                                                                                                                                                                                                                                                                 | Body                |
| --------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------- |
| `200`     | The authorization, as it now stands. Answered for the body form.                                                                                                                                                                                                                                        | GoLiveAuthorization |
| `201`     | The approval link, answered for an empty body. `approval_url` is shown once.                                                                                                                                                                                                                            | GoLiveApproval      |
| `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 /empresas/{empresa_id}/onboarding/steps/{step}/recheck` [#post-empresas-empresa-id-onboarding-steps-step-recheck]

**Tell us a human step was performed, and we go and look**

The resume half of the `pending_action` handoff. A person has performed one of the acts
Chilean law reserves to them (see `pending_action.performed_by`), and this asks us to
find out whether the SII agrees.

**This endpoint accepts a claim and produces no fact.** It takes no request body, writes
no step status and moves no empresa. What it does is enqueue the producer that READS the
SII, plus the tick that folds whatever that producer finds, and return the step's status
as it stood the moment you called — read before the enqueue and returned unchanged. If
you post a recheck on a step that is `action_required` and read `action_required` back,
that is the endpoint working: the step advances when we see the fact, not when you say
so. `verified` is on the response and it is always `false`.

`evidence_source` says how (or whether) the step can be confirmed at all. `sii_probe`
means we go and read the SII. `own_record` means the act lands in our own tables and we
will see it. `no_producer` means this build genuinely cannot observe that step yet — the
boleta `habilitacion` is the one — and `contact` names the door out:
`POST .../onboarding/steps/\{step\}/attest` (#395), which is a DIFFERENT endpoint that
writes a fact rather than merely recording a claim. Do not tell a user this call alone is
watching a `no_producer` step; nothing is.

`queued` and `already_queued` split the jobs this call created from the ones that were
already scheduled for the same five-minute window. Both mean "we are about to look".

For a sandbox empresa nothing is enqueued and `evidence_source` is `sandbox`: a test
empresa's onboarding never opens a session against the SII, so there is nothing to
re-read. Move its steps with the test helpers instead.

```bash
curl -sS -X POST https://api.facturia.cl/v1/empresas/emp_01K2R6ZC4P8QW1VN7T3MHDY9EK/onboarding/steps/{step}/recheck \
  -H "Authorization: Bearer $FACTURIA_KEY"
```

**Parameters**

| Parameter    | In   | Required | Type   | Notes                                                     |
| ------------ | ---- | -------- | ------ | --------------------------------------------------------- |
| `empresa_id` | path | yes      | string |                                                           |
| `step`       | path | yes      | string | An onboarding step key from this empresa's own checklist. |

**Responses**

| Code      | Meaning                                                                                                                                                                                                                                                                                                 | Body                                                                |
| --------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------- |
| `202`     | The claim was accepted for verification. Nothing has been verified yet.                                                                                                                                                                                                                                 | [OnboardingRecheck](/en/docs/referencia/esquemas#onboardingrecheck) |
| `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                                                       |

## `POST /empresas/{empresa_id}/onboarding/steps/{step}/attest` [#post-empresas-empresa-id-onboarding-steps-step-attest]

**Record that a human performed a step this build cannot probe (#395)**

The endpoint `recheck`'s own `contact` field points at when `evidence_source:
'no_producer'`. Unlike `recheck` — which accepts a claim and produces no fact —
**this endpoint writes one**: a `sii_onboarding_evidence` row the next onboarding tick
reads as the fact that lets the step complete.

Refused with `422 invalid_field` on any step whose `evidence_source` is not
`no_producer` — attesting a step the SII probe or our own records already confirm would
be a second, competing source of truth for a fact we can already verify. `habilitacion`
(boleta habilitación at `certBolElectDteInternet`, an uncaptured SII SPA) is the only
step this map names `no_producer` today.

Requires `onboarding:attest` **itself**: never in the bootstrap default set, never
implied by `empresas:write` alone (ADR-0012 §3-4). `attested_by` is required — who told
you this happened.

```bash
curl -sS -X POST https://api.facturia.cl/v1/empresas/emp_01K2R6ZC4P8QW1VN7T3MHDY9EK/onboarding/steps/{step}/attest \
  -H "Authorization: Bearer $FACTURIA_KEY" \
  -H "Content-Type: application/json" \
  -d '{"attested_by":"…"}'
```

**Parameters**

| Parameter    | In   | Required | Type   | Notes                                                     |
| ------------ | ---- | -------- | ------ | --------------------------------------------------------- |
| `empresa_id` | path | yes      | string |                                                           |
| `step`       | path | yes      | string | An onboarding step key from this empresa's own checklist. |

**Body**

| Field         | Type   | Required | Notes                                                                 |
| ------------- | ------ | -------- | --------------------------------------------------------------------- |
| `attested_by` | string | yes      | A name, or the representante legal's RUT. Who told you this happened. |
| `note`        | string | —        |                                                                       |
| **Responses** |        |          |                                                                       |

| Code      | Meaning                                                                                                                                                                                                                                                                                                 | Body                  |
| --------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | --------------------- |
| `202`     | The attestation was recorded. The step folds on the next tick.                                                                                                                                                                                                                                          | OnboardingAttestation |
| `400`     | Malformed or missing input.                                                                                                                                                                                                                                                                             | ErrorResponse         |
| `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         |
| `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 /empresas/{empresa_id}/onboarding/steps/{step}/approve` [#post-empresas-empresa-id-onboarding-steps-step-approve]

**Record the titular's authorization for a step Facturia then performs (#452, #453)**

The sibling of `attest`, for the opposite situation. `attest` says «a person did
something we cannot see»; this says «a person authorized something WE are about to do».

Two acts in this pipeline are ours to perform once somebody chooses the moment. The
postulacion is presented with the representante legal's own custodied certificate under
mandato 4.2 a), and it costs an empresa on the Sistema de Facturacion Gratuito its
"calidad de usuario activo" the instant the SII authorizes it. The boleta habilitacion
opens a 24-hour SII clock. Neither is a decision a custody mandate carries, so each
waits for a row in `sii_onboarding_step_approvals`.

**`act` must be the one the step is currently asking for.** Read
`steps[].pending_action.approval` on `GET .../onboarding`: it names the act, whose
decision it is, the consequences to show first, and both button labels. A step asking
for nothing answers `409 onboarding_approval_not_offered`; a mismatched `act` answers
`400 invalid_field`. One step carries different decisions at different points of its
life, and an approval recorded against the wrong one is consent that was never given.

**A rejection is recorded, not ignored.** `decision: "reject"` writes a row exactly as
an approval does, so the product can say "you left it for later" rather than "nobody
answered". Executors read the LATEST row for the act and branch on `decision`.

Requires `onboarding:attest` itself — never in the bootstrap default set, never implied
by `empresas:write` (ADR-0012 §3-4). The canonical form of an approval is the hosted
page (`POST /onboarding/steps/\{step\}/approve` with the link token); this is the
integrator door for a decision collected in their own flow.

```bash
curl -sS -X POST https://api.facturia.cl/v1/empresas/emp_01K2R6ZC4P8QW1VN7T3MHDY9EK/onboarding/steps/{step}/approve \
  -H "Authorization: Bearer $FACTURIA_KEY" \
  -H "Content-Type: application/json" \
  -d '{"act":"…","decision":"approve"}'
```

**Parameters**

| Parameter    | In   | Required | Type   | Notes                                                     |
| ------------ | ---- | -------- | ------ | --------------------------------------------------------- |
| `empresa_id` | path | yes      | string |                                                           |
| `step`       | path | yes      | string | An onboarding step key from this empresa's own checklist. |

**Body**

| Field         | Type                 | Required | Notes                                                                     |
| ------------- | -------------------- | -------- | ------------------------------------------------------------------------- |
| `act`         | string               | yes      | The act being decided, exactly as `pending_action.approval.act` names it. |
| `decision`    | `approve` · `reject` | yes      |                                                                           |
| `note`        | string               | —        |                                                                           |
| **Responses** |                      |          |                                                                           |

| Code      | Meaning                                                                                                                                                                                                                                                                                                 | Body                   |
| --------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ---------------------- |
| `201`     | The decision was recorded. On `approve`, the fold tick is enqueued.                                                                                                                                                                                                                                     | OnboardingStepApproval |
| `400`     | Malformed or missing input.                                                                                                                                                                                                                                                                             | ErrorResponse          |
| `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          |

## `GET /empresas/{empresa_id}/onboarding/certification` [#get-empresas-empresa-id-onboarding-certification]

**The set de pruebas - what was uploaded, what is missing, what the SII said**

One read, not four. A certification is a bounded thing - one set file, one input
document, a handful of envios across at most three rounds - and splitting it would
make the obvious screen four round trips whose answers can disagree.

TWO FIELDS THAT LOOK ALIKE AND ARE OPPOSITE. `envios[].estado` is the ENVIO estado,
where `SOK` means "envio recibido" - arrived, not judged. `envios[].verdict` is the
SET verdict, where `SOK` means the set was APPROVED. Same three letters, opposite
consequences, which is why they are two fields and never merged.

`envios[].dry_run: true` means the envelope was built and NOT sent. `submittable` is
`null` until a build has happened at all, which is not the same as `false`.

`problems[].message` may be `null`: the sentences live in the build artifact beside
the record, and when it cannot be read the response degrades to codes rather than
failing. The code is always there.

```bash
curl -sS https://api.facturia.cl/v1/empresas/emp_01K2R6ZC4P8QW1VN7T3MHDY9EK/onboarding/certification \
  -H "Authorization: Bearer $FACTURIA_KEY"
```

**Parameters**

| Parameter    | In   | Required | Type   | Notes |
| ------------ | ---- | -------- | ------ | ----- |
| `empresa_id` | path | yes      | string |       |

**Responses**

| Code      | Meaning                                                                                                                                                                                                                                                                                                 | Body          |
| --------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------- |
| `200`     | The certification, as it now stands.                                                                                                                                                                                                                                                                    | Certification |
| `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 /empresas/{empresa_id}/onboarding/certification/set_file` [#post-empresas-empresa-id-onboarding-certification-set-file]

**Upload the set de pruebas the SII issued for this empresa**

The SII issues the set `.txt` per taxpayer when it accepts the postulacion. Nothing
downloads it for you; this is how the bytes get in.

MULTIPART, NOT BASE64 IN JSON. The file is ISO-8859-1 and its accents are part of the
document - `Cajon` and `Panuelo` are two of the items the SII reported as reparos when
theirs were lost. Multipart hands us the bytes; a JSON string would already have been
through somebody's idea of a text encoding by the time we saw it. The bytes are stored
verbatim and never re-encoded. Limit: 1 MB.

Bytes that are not a set de pruebas are refused with `422 set_file_unrecognized` and
NOTHING is stored - a portal login page parsed as an empty set would report the
empresa as having no casos, which is a different thing from having no set file.

A set that IS recognised is stored even when parts of it were not understood; those
appear in `problems[]`.

This endpoint does not run a round, does not open a socket to the SII and does not
spend a folio. The round is the engine's, on its own clock.

```bash
curl -sS -X POST https://api.facturia.cl/v1/empresas/emp_01K2R6ZC4P8QW1VN7T3MHDY9EK/onboarding/certification/set_file \
  -H "Authorization: Bearer $FACTURIA_KEY" \
  -F "file=…"
```

**Parameters**

| Parameter    | In   | Required | Type   | Notes |
| ------------ | ---- | -------- | ------ | ----- |
| `empresa_id` | path | yes      | string |       |

**Body (multipart/form-data)**

| Field         | Type   | Required | Notes                                                      |
| ------------- | ------ | -------- | ---------------------------------------------------------- |
| `file`        | string | yes      | The `.txt` as the SII issued it. ISO-8859-1, at most 1 MB. |
| **Responses** |        |          |                                                            |

| Code      | Meaning                                                                                                                                                                                                                                                                                                 | Body                 |
| --------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------------------- |
| `201`     | The set as we read it.                                                                                                                                                                                                                                                                                  | CertificationSetFile |
| `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 /empresas/{empresa_id}/onboarding/certification/inputs` [#post-empresas-empresa-id-onboarding-certification-inputs]

**Supply the facts the set de pruebas does not carry**

The set states several things by implication and never spells them out: who issued
each purchase in the libro de compras, what the CodRef-2 correction says, which
factura invoiced a guia the set marks "facturada", the factor de proporcionalidad,
the SII-issued folio de notificacion, and - for a boleta round - the abbreviated
unidades and ten everyday boletas. Each one is a deliberate refusal in the engine:
the round reports what it needs rather than inventing a value and spending folios on
a document the SII will reject.

THE MERGE IS PER TOP-LEVEL SLOT: absent keeps, `null` clears, present replaces WHOLE.
Restating `proveedores` restates all of them - which is what a form submits and the
only way to REMOVE one. A deep merge would leave the row you deleted in the next
libro.

NOTHING IS WRITTEN WHEN ANYTHING IS INVALID, not even the valid half: a partial write
leaves the empresa in a state nobody asked for and a round that refuses for a reason
you believe you already fixed. `400 certification_input_invalid` carries EVERY problem
in `error.details.problems`, not the first. It may also refuse over a value you did
not send, when the stored document your patch merges into is itself invalid.

ONE SLOT IS PREFILLED: `libro_guias.folio_notificacion` defaults to 3, the number
continuing the 1 and 2 the libro de ventas and the libro de compras carry.
LibroGuia\_v10.xsd makes the element mandatory where the IECV's is optional, so it
cannot simply be omitted, and a round that goes out on the default says so in a
notice. `libro_boleta_folio_notificacion` has no default and will not get one: it is
an SII-issued number answering a specific notificacion and nothing can derive it.

```bash
curl -sS -X POST https://api.facturia.cl/v1/empresas/emp_01K2R6ZC4P8QW1VN7T3MHDY9EK/onboarding/certification/inputs \
  -H "Authorization: Bearer $FACTURIA_KEY" \
  -H "Content-Type: application/json" \
  -d '{"receptor":{"rut":"76543212-K"},"giro_recep_emisor":"…"}'
```

**Parameters**

| Parameter    | In   | Required | Type   | Notes |
| ------------ | ---- | -------- | ------ | ----- |
| `empresa_id` | path | yes      | string |       |

**Body**

| Field                             | Type         | Required | Notes                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                              |
| --------------------------------- | ------------ | -------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `receptor`                        | object,null  | —        | The party the test documents are issued to. `giro` is measured against `GiroRecep` (40), which is shorter than `GiroEmis` (80) - an emisor's own name of trade is frequently illegal in this slot.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                 |
| `giro_recep_emisor`               | string,null  | —        | A ≤40-character abbreviation of the EMISOR's own giro, for the ONE place a traslado interno guia writes it back: the receptor is the emisor itself (a traslado interno moves goods between the empresa's own premises), so its giro is what would be written into `GiroRecep` - which caps at 40 where the emisor's own `GiroEmis` allows 80. Absent, and the emisor's giro fits within 40 characters anyway: written verbatim, same as always. Absent, and it does not fit: `GiroRecep` is optional in the schema, so the element is OMITTED rather than truncated, and the round raises `giro_recep_omitted` so the omission is visible rather than silent - this is the exact reparo the SII drew over the pilot's own 65-character giro. Present: written verbatim, and refused - never truncated - if it does not fit either. |
| `text_correction`                 | object,null  | —        | The CodRef-2 correction. Written as "Dice: \{says} y debe decir: \{shouldSay}" into `RazonRef`, which caps at 90 - 21 of them are the scaffolding, so the two halves share 69. Measured on the composition, and never truncated for you.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                           |
| `proveedores`                     | object,null  | —        | Who issued each purchase, keyed `&lt;tipoDte&gt;:&lt;folio&gt;` - the two things the set prints for every row. A RUT whose verifier digit fails modulo 11 is one of the two documented causes of an LRH "Descuadrado", found after the folios are spent. `razonSocial` is measured against the LIBRO's `RznSoc` (50), not the DTE's 100.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                           |
| `iva_no_rec_codes`                | object,null  | —        | Why a purchase loses its credito. LibroCV\_v10.xsd enumerates 1,2,3,4,9.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                           |
| `libro_treatments`                | object,null  | —        | The IVA treatment of a purchase the set does not classify. "unknown" is the planner's word for "the set said nothing" and "exento\_sin\_iva" is arithmetic, so neither is an input.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                |
| `libro_guias`                     | object,null  | —        |                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                    |
| `factor_proporcionalidad`         | number,null  | —        | The set prints it as "EL FACTOR DE PROPORCIONALIDAD DEL IVA ES DE 0.60". It decides how much credito is claimed, so it is never guessed.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                           |
| `libro_boleta_folio_notificacion` | integer,null | —        | The SII-issued "Folio de la Notificacion con que se Solicita el Libro Especial". NO DEFAULT, and there will not be one - nothing can derive it, and a boleta round refuses without it.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                             |
| `boleta_unidades`                 | object,null  | —        | `UnmdItem` by `&lt;casoId&gt;:&lt;nroLinDet&gt;`, for the one thing a set can demand that its own schema forbids - a unidad longer than four characters. Refused, never truncated: "mens" is not a unit.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                           |
| `boleta_muestras`                 | array,null   | —        | The ten everyday boletas the SII's boleta review asks for, describing what this empresa actually sells at prices it actually charges. Fewer than ten is an incomplete request and is refused; more is fine.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                        |
| `permiso_usuario_rut`             | string,null  | —        | The natural person the permisos probe asks "Mantencion de usuarios" about, when the custodied certificate encodes no RUT of its own. THE ONLY SLOT HERE THAT IS NOT A DOCUMENT FACT, and the only one no builder reads. Estado 106 "Usuario sin permiso de envio" is about the RUT the SII token was minted for, so the probe reads it out of the certificate first and falls back to this. Absence does NOT refuse a round: the round still builds and signs, and it is the permisos gate that parks, reporting `no_target` with the remedy attached. Validated modulo 11 like every other RUT here. `null` clears it. Never the empresa's own RUT - that table lists natural persons, so an empresa RUT would find nobody and report the sender as unlisted.                                                                     |
| **Responses**                     |              |          |                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                    |

| Code      | Meaning                                                                                                                                                                                                                                                                                                 | Body          |
| --------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------- |
| `200`     | The inputs as they now stand on the empresa.                                                                                                                                                                                                                                                            | 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 |

## `GET /empresas/{empresa_id}/onboarding/evidence` [#get-empresas-empresa-id-onboarding-evidence]

**The rendicion de cuentas - what we did on the empresa's behalf**

Clausula 4.4 of the mandato obliges us to render account of what we did on the
customer's behalf. Every act the onboarding pipeline performs is kept as an artifact,
and this reads them back, newest first.

`retention_until` is on every row and is six years from the act - the Codigo
Tributario's prescripcion extraordinaria plus its conservation duty, which is also the
retention purpose under Ley 21.719. On revocation or traspaso the record freezes
read-only and is offered as an export; it is never purged early.

```bash
curl -sS https://api.facturia.cl/v1/empresas/emp_01K2R6ZC4P8QW1VN7T3MHDY9EK/onboarding/evidence \
  -H "Authorization: Bearer $FACTURIA_KEY"
```

**Parameters**

| Parameter    | In    | Required | Type    | Notes                                                   |
| ------------ | ----- | -------- | ------- | ------------------------------------------------------- |
| `empresa_id` | path  | yes      | string  |                                                         |
| `limit`      | query | —        | integer |                                                         |
| `cursor`     | query | —        | string  | Opaque cursor from a previous response's `next_cursor`. |
| `step`       | query | —        | string  | Only artifacts of this onboarding step.                 |
| `kind`       | query | —        | string  | Only artifacts of this kind.                            |

**Responses**

| Code      | Meaning                                                                                                                                                                                                                                                                                                 | Body                        |
| --------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | --------------------------- |
| `200`     | The artifacts.                                                                                                                                                                                                                                                                                          | lista de OnboardingEvidence |
| `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 /empresas/{empresa_id}/onboarding/evidence/export` [#get-empresas-empresa-id-onboarding-evidence-export]

**The rendicion de cuentas as one CSV file**

The same rows the list endpoint serves, complete in one response, as a file you can hand
to a customer, an accountant or a lawyer. The retention ruling says that on revocation or
traspaso we offer the customer a full export as the formal clausula 4.4 rendicion; this is
that export, and it is available at any time, not only on the way out.

RFC 4180, comma-separated, UTF-8 with NO byte-order mark, CRLF line endings. The columns
are the JSON object's own fields in the same order - `id`, `empresa_id`, `step`,
`tipo_dte`, `kind`, `captured_at`, `retention_until`, `sha256`, `bytes`, `content_type`,
`detail` - so `storage_path` is absent here exactly as it is absent there. `detail`
travels as its compact JSON, quoted.

Paged internally and capped at 50,000 rows. When the cap is reached the response says so
in `Facturia-Export-Complete: false` rather than serving a truncated file that looks
whole; `step` and `kind` are how you narrow an export that hit it.

```bash
curl -sS https://api.facturia.cl/v1/empresas/emp_01K2R6ZC4P8QW1VN7T3MHDY9EK/onboarding/evidence/export \
  -H "Authorization: Bearer $FACTURIA_KEY"
```

**Parameters**

| Parameter    | In    | Required | Type   | Notes                                   |
| ------------ | ----- | -------- | ------ | --------------------------------------- |
| `empresa_id` | path  | yes      | string |                                         |
| `step`       | query | —        | string | Only artifacts of this onboarding step. |
| `kind`       | query | —        | string | Only artifacts of this kind.            |

**Responses**

| Code      | Meaning                                                                                                                                                                                                                                                                                                 | Body          |
| --------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------- |
| `200`     | The rendicion, as a CSV attachment.                                                                                                                                                                                                                                                                     | text/csv      |
| `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 /empresas/{empresa_id}/automation_settings` [#get-empresas-empresa-id-automation-settings]

**Retrieve per-empresa automation settings**

The empresa's automatic-emission toggles (`auto_characterize_purchases`, `auto_emit_46`, …), each defaulted where unset.

```bash
curl -sS https://api.facturia.cl/v1/empresas/emp_01K2R6ZC4P8QW1VN7T3MHDY9EK/automation_settings \
  -H "Authorization: Bearer $FACTURIA_KEY"
```

**Parameters**

| Parameter    | In   | Required | Type   | Notes |
| ------------ | ---- | -------- | ------ | ----- |
| `empresa_id` | path | yes      | string |       |

**Responses**

| Code      | Meaning                                                                                                                                                                                                                                                                                                 | Body               |
| --------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------ |
| `200`     | Automation settings.                                                                                                                                                                                                                                                                                    | AutomationSettings |
| `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      |

## `PATCH /empresas/{empresa_id}/automation_settings` [#patch-empresas-empresa-id-automation-settings]

**Update per-empresa automation settings**

Every automation defaults to OFF except `auto_request_folios`. `auto_emit_46` and
`auto_file_f29` are opt-in per empresa and capped.

```bash
curl -sS -X PATCH https://api.facturia.cl/v1/empresas/emp_01K2R6ZC4P8QW1VN7T3MHDY9EK/automation_settings \
  -H "Authorization: Bearer $FACTURIA_KEY" \
  -H "Content-Type: application/json" \
  -d '{"object":"…","empresa_id":"…"}'
```

**Parameters**

| Parameter    | In   | Required | Type   | Notes |
| ------------ | ---- | -------- | ------ | ----- |
| `empresa_id` | path | yes      | string |       |

**Body**

| Field                             | Type                                     | Required | Notes                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                            |
| --------------------------------- | ---------------------------------------- | -------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `object`                          | string                                   | —        |                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                  |
| `empresa_id`                      | string                                   | —        |                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                  |
| `auto_emit_46`                    | boolean                                  | —        | Default: `false`.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                |
| `auto_emit_46_max_amount`         | Clp                                      | —        | Amount in CLP. Integer pesos, never decimals or strings.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                         |
| `auto_file_f29`                   | boolean                                  | —        | Default: `false`.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                |
| `auto_file_f29_day`               | integer                                  | —        | Default: `18`.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                   |
| `auto_file_f29_max_payable`       | Clp                                      | —        | Default 0 — out of the box only a zero or refund position files itself, and any month you actually owe IVA waits for a human. Raise deliberately, per empresa.  Default: `0`.                                                                                                                                                                                                                                                                                                                                                                                                                                                    |
| `auto_request_folios`             | boolean                                  | —        | Default: `true`.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                 |
| `auto_request_folios_threshold`   | integer                                  | —        | Default: `50`.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                   |
| `auto_accept_received`            | boolean                                  | —        | Default: `false`.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                |
| `auto_accept_received_after_days` | integer,null                             | —        |                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                  |
| `require_confirmation`            | boolean                                  | —        | When true, money-moving actions initiated from an agent surface — emitting a document, filing an F29, registering a reclamo through the MCP server's tools — require a draft → confirm two-step instead of executing on the first call. It exists primarily for the MCP surface (see `mcp-server-spec.md`); the REST API described here is unaffected, and the flag lives on this resource so one settings object governs the empresa on every surface.  Default: `false`.                                                                                                                                                       |
| `rcv_sync_frequency`              | `hourly` · `daily` · `weekly` · `manual` | —        | Default: `"daily"`.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                              |
| `honor_estado_contable_override`  | boolean                                  | —        | Whether the F29 propuesta obeys the LOCAL `estado_contable_override` set through `POST /tax/purchases/\{entry_id\}/estado_contable` instead of the `estado_contable` the SII's own register supplied. Off by default, and the direction of that default is the point: only `REGISTRO` purchases carry a crédito fiscal, so a local `PENDIENTE` → `REGISTRO` flip claims IVA the SII does not agree exists — and the SII's value is the one an audit reads. Turned on, every affected propuesta carries an explicit observation naming the documents, and every write is recorded on the document's event log.  Default: `false`. |
| `updated_at`                      | string                                   | —        |                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                  |
| **Responses**                     |                                          |          |                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                  |

| Code      | Meaning                                                                                                                                                                                                                                                                                                 | Body               |
| --------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------ |
| `200`     | Updated settings.                                                                                                                                                                                                                                                                                       | AutomationSettings |
| `400`     | Malformed or missing input.                                                                                                                                                                                                                                                                             | ErrorResponse      |
| `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 /empresas/{empresa_id}/branding` [#get-empresas-empresa-id-branding]

**Read logo, default print format and footer text**

Every field is filled in from the platform defaults where the empresa has set nothing, so
the object always describes what a PDF will actually look like rather than only what was
overridden.

```bash
curl -sS https://api.facturia.cl/v1/empresas/emp_01K2R6ZC4P8QW1VN7T3MHDY9EK/branding \
  -H "Authorization: Bearer $FACTURIA_KEY"
```

**Parameters**

| Parameter    | In   | Required | Type   | Notes |
| ------------ | ---- | -------- | ------ | ----- |
| `empresa_id` | path | yes      | string |       |

**Responses**

| Code      | Meaning                                                                                                                                                                                                                                                                                                 | Body          |
| --------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------- |
| `200`     | The empresa's branding.                                                                                                                                                                                                                                                                                 | Branding      |
| `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 |

## `PATCH /empresas/{empresa_id}/branding` [#patch-empresas-empresa-id-branding]

**Update logo, default print format and footer text**

Update the panel and hosted-page branding fields (logo, colors, display name). An unknown field name is refused (`422 unknown_setting`), never silently ignored.

```bash
curl -sS -X PATCH https://api.facturia.cl/v1/empresas/emp_01K2R6ZC4P8QW1VN7T3MHDY9EK/branding \
  -H "Authorization: Bearer $FACTURIA_KEY" \
  -H "Content-Type: application/json" \
  -d '{"object":"…","logo_url":"…"}'
```

**Parameters**

| Parameter    | In   | Required | Type   | Notes |
| ------------ | ---- | -------- | ------ | ----- |
| `empresa_id` | path | yes      | string |       |

**Body**

| Field                | Type    | Required | Notes                                                                                                                                                                                                                                                                                                                                                                           |
| -------------------- | ------- | -------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `object`             | string  | —        |                                                                                                                                                                                                                                                                                                                                                                                 |
| `logo_url`           | string  | —        |                                                                                                                                                                                                                                                                                                                                                                                 |
| `default_pdf_format` | `carta` | —        | `carta` is the only legal value — `80mm` was removed in wave 9 along with the `format` parameter, and no thermal layout exists. `PATCH` refuses any other value with `400 invalid_field` (ticket #18 wave 10). There is nothing further for it to select: it already names the only layout this API renders, so validating it is what "applying" it means.  Default: `"carta"`. |
| `cedible_by_default` | boolean | —        | Applies to facturas — tipo 33 and 34 (Ley 19.983; not "tipo 33 only", corrected in ticket #18 wave 10). Consumed by `GET /documents/\{document_id\}/pdf`'s default-copy resolution: a per-document `pdf.cedible` (§9.3) overrides it; an explicit `?copy=` overrides both. See that endpoint's `copy` parameter for the full precedence.  Default: `false`.                     |
| `footer_text`        | string  | —        |                                                                                                                                                                                                                                                                                                                                                                                 |
| **Responses**        |         |          |                                                                                                                                                                                                                                                                                                                                                                                 |

| Code      | Meaning                                                                                                                                                                                                                                                                                                 | Body          |
| --------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------- |
| `200`     | Updated branding.                                                                                                                                                                                                                                                                                       | Branding      |
| `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 |
