# Test helpers (/docs/referencia/test-helpers)

Base: `https://api.facturia.cl/v1`. Todos los endpoints de este capítulo se autentican con `Authorization: Bearer` salvo que se diga lo contrario, y el sobre de error es el de [Errores](/docs/errores).

| Método | Ruta                                                                                                              | Qué hace                                                                      |
| ------ | ----------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------- |
| `POST` | [`/test_helpers/received_documents`](#post-test-helpers-received-documents)                                       | Inyecta un DTE de proveedor como si hubiera llegado a la casilla de recepción |
| `POST` | [`/test_helpers/rcv/seed`](#post-test-helpers-rcv-seed)                                                           | Siembra filas de RCV en un período para que la propuesta de F29 tenga datos   |
| `POST` | [`/test_helpers/clock`](#post-test-helpers-clock)                                                                 | Adelanta el reloj simulado de esta empresa                                    |
| `POST` | [`/test_helpers/empresas/{empresa_id}/onboarding`](#post-test-helpers-empresas-empresa-id-onboarding)             | Lleva la puesta en marcha de una empresa a cualquier estado                   |
| `POST` | [`/test_helpers/empresas/{empresa_id}/onboarding/steps`](#post-test-helpers-empresas-empresa-id-onboarding-steps) | Fuerza el estado de un paso concreto de la puesta en marcha                   |
| `POST` | [`/test_helpers/documents/{document_id}/estado`](#post-test-helpers-documents-document-id-estado)                 | Fuerza el estado crudo del SII de un documento de sandbox ya emitido          |
| `POST` | [`/test_helpers/f29/proposals`](#post-test-helpers-f29-proposals)                                                 | Inject a computed F29 propuesta                                               |
| `POST` | [`/test_helpers/f29/validations`](#post-test-helpers-f29-validations)                                             | Fuerza el veredicto de la validación cruzada de un período                    |

## `POST /test_helpers/received_documents` [#post-test-helpers-received-documents]

**Inyecta un DTE de proveedor como si hubiera llegado a la casilla de recepción**

Solo en sandbox: inyecta un DTE de proveedor como si acabara de llegar a la casilla de recepción, sin esperar que una contraparte real lo envíe.

```bash
curl -sS -X POST https://api.facturia.cl/v1/test_helpers/received_documents \
  -H "Authorization: Bearer $FACTURIA_KEY" \
  -H "Facturia-Empresa: $EMPRESA" \
  -H "Content-Type: application/json" \
  -d '{"tipo_dte":33,"emisor":{"rut":"96790240-3","legal_name":"Proveedor Austral SpA"}}'
```

**Parámetros**

| Parámetro          | En     | Requerido | Tipo   | Notas                                                                                                                                                                                                                                                                                                                                                                                 |
| ------------------ | ------ | --------- | ------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `Facturia-Empresa` | header | —         | string | La empresa destino: RUT canónico (`77928532-4`) o id de empresa (`emp_…`). Obligatorio en toda llamada con alcance de empresa, salvo que la llave sea un token de empresa. Este header es el ÚNICO mecanismo: no hay parámetro `?empresa=` ni campo `empresa` en el cuerpo. Omitido donde se requiere → `400 empresa_required`; fuera de la lista blanca → `403 empresa_not_allowed`. |

**Cuerpo**

| Campo          | Tipo                                                  | Requerido | Notas                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                            |
| -------------- | ----------------------------------------------------- | --------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `tipo_dte`     | `33` · `34` · `39` · `41` · `46` · `52` · `56` · `61` | sí        | 33 factura afecta · 34 factura exenta · 39 boleta afecta · 41 boleta exenta · 46 factura de compra · 52 guía de despacho · 56 nota de débito · 61 nota de crédito. Las boletas (39/41) viajan por otro transporte del SII; eso es invisible desde esta API.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                      |
| `folio`        | integer                                               | —         |                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                  |
| `emisor`       | Party                                                 | sí        | Una contraparte — una empresa O una persona natural. No hay bandera de empresa, y no hace falta ninguna: una persona natural (`rut` + `legal_name`, sin `giro`, sin `address`) es un receptor válido para una boleta (39/41). Su nombre se escribe en `&lt;RznSocRecep&gt;` y en el `&lt;RSR&gt;` del timbre, su RUT en `&lt;RUTRecep&gt;`/`&lt;RR&gt;` — la boleta que un paciente presenta a una Isapre o a un seguro complementario. Sin `legal_name` la boleta nombra el RUT junto a «Sin RUT»; sin receptor se emite al consumidor anónimo `66666666-6`. Una nota de crédito (61) a una persona natural también es válida, pero es un documento de la familia factura: como toda 61 necesita `giro`, `address.street` y `address.comuna`, incluso cuando anula una boleta. `POST /v1/documents/\{id\}/credit_note` copia el receptor de la boleta original, así que guarda esos tres datos una vez con `PATCH /v1/empresas/\{id\}/counterparties/\{rut\}` antes de anular, o la nota se rechaza con `400 receptor_incomplete` antes de gastar ningún folio. |
| `issue_date`   | string                                                | —         |                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                  |
| `totals`       | Totals                                                | —         |                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                  |
| `items`        | DocumentItem\[]                                       | —         |                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                  |
| **Respuestas** |                                                       |           |                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                  |

| Código    | Significado                                                                                                                                                                                                                                                                                                               | Cuerpo           |
| --------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ---------------- |
| `201`     | El documento recibido inyectado; se dispara `received_document.created`.                                                                                                                                                                                                                                                  | ReceivedDocument |
| `401`     | Llave ausente, mal formada o revocada.                                                                                                                                                                                                                                                                                    | ErrorResponse    |
| `403`     | Llave válida pero sin permiso: scope, lista blanca de empresas o modo.                                                                                                                                                                                                                                                    | ErrorResponse    |
| `429`     | Demasiadas solicitudes.                                                                                                                                                                                                                                                                                                   | ErrorResponse    |
| `default` | Un error no enumerado aparte para esta operación, en el mismo sobre §5.5 que cualquier otro rechazo. Ramifica por `error.code`, nunca solo por el estado HTTP ni por `error.message` — un código que esta operación aún no se ha visto lanzar sigue siendo más seguro para decidir que un texto pensado para una persona. | ErrorResponse    |

## `POST /test_helpers/rcv/seed` [#post-test-helpers-rcv-seed]

**Siembra filas de RCV en un período para que la propuesta de F29 tenga datos**

Solo en sandbox: siembra los registros de compras/ventas con entradas sintéticas, para poder probar flujos que dependen del RCV (caracterización, F29) sin una sincronización real con el SII.

```bash
curl -sS -X POST https://api.facturia.cl/v1/test_helpers/rcv/seed \
  -H "Authorization: Bearer $FACTURIA_KEY" \
  -H "Facturia-Empresa: $EMPRESA" \
  -H "Content-Type: application/json" \
  -d '{"period":"2026-07"}'
```

**Parámetros**

| Parámetro          | En     | Requerido | Tipo   | Notas                                                                                                                                                                                                                                                                                                                                                                                 |
| ------------------ | ------ | --------- | ------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `Facturia-Empresa` | header | —         | string | La empresa destino: RUT canónico (`77928532-4`) o id de empresa (`emp_…`). Obligatorio en toda llamada con alcance de empresa, salvo que la llave sea un token de empresa. Este header es el ÚNICO mecanismo: no hay parámetro `?empresa=` ni campo `empresa` en el cuerpo. Omitido donde se requiere → `400 empresa_required`; fuera de la lista blanca → `403 empresa_not_allowed`. |

**Cuerpo**

| Campo          | Tipo    | Requerido | Notas                                                              |
| -------------- | ------- | --------- | ------------------------------------------------------------------ |
| `period`       | Period  | sí        | Período tributario `YYYY-MM` (America/Santiago). Ej.: `"2026-07"`. |
| `purchases`    | integer | —         | Por defecto: `10`.                                                 |
| `sales`        | integer | —         | Por defecto: `10`.                                                 |
| **Respuestas** |         |           |                                                                    |

| Código    | Significado                                                                                                                                                                                                                                                                                                               | Cuerpo        |
| --------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------- |
| `201`     | Las filas se escribieron, en esta misma petición. No hay job y no hay nada que consultar: el sandbox no tiene worker que esperar (§4.1), así que una siembra que respondiera `202` con un job sería la promesa de una asincronía que acá no existe.                                                                       | RcvSeed       |
| `401`     | Llave ausente, mal formada o revocada.                                                                                                                                                                                                                                                                                    | ErrorResponse |
| `403`     | Llave válida pero sin permiso: scope, lista blanca de empresas o modo.                                                                                                                                                                                                                                                    | ErrorResponse |
| `429`     | Demasiadas solicitudes.                                                                                                                                                                                                                                                                                                   | ErrorResponse |
| `default` | Un error no enumerado aparte para esta operación, en el mismo sobre §5.5 que cualquier otro rechazo. Ramifica por `error.code`, nunca solo por el estado HTTP ni por `error.message` — un código que esta operación aún no se ha visto lanzar sigue siendo más seguro para decidir que un texto pensado para una persona. | ErrorResponse |

## `POST /test_helpers/clock` [#post-test-helpers-clock]

**Adelanta el reloj simulado de esta empresa**

Ejercita la ventana de acuse de 8 días, el vencimiento de folios y los plazos del F29 sin esperar.

```bash
curl -sS -X POST https://api.facturia.cl/v1/test_helpers/clock \
  -H "Authorization: Bearer $FACTURIA_KEY" \
  -H "Facturia-Empresa: $EMPRESA" \
  -H "Content-Type: application/json" \
  -d '{"advance_days":9,"set_to":"…"}'
```

**Parámetros**

| Parámetro          | En     | Requerido | Tipo   | Notas                                                                                                                                                                                                                                                                                                                                                                                 |
| ------------------ | ------ | --------- | ------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `Facturia-Empresa` | header | —         | string | La empresa destino: RUT canónico (`77928532-4`) o id de empresa (`emp_…`). Obligatorio en toda llamada con alcance de empresa, salvo que la llave sea un token de empresa. Este header es el ÚNICO mecanismo: no hay parámetro `?empresa=` ni campo `empresa` en el cuerpo. Omitido donde se requiere → `400 empresa_required`; fuera de la lista blanca → `403 empresa_not_allowed`. |

**Cuerpo**

| Campo          | Tipo    | Requerido | Notas |
| -------------- | ------- | --------- | ----- |
| `advance_days` | integer | —         |       |
| `set_to`       | string  | —         |       |
| **Respuestas** |         |           |       |

| Código    | Significado                                                                                                                                                                                                                                                                                                               | Cuerpo        |
| --------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------- |
| `200`     | La nueva fecha simulada de la empresa.                                                                                                                                                                                                                                                                                    | object        |
| `401`     | Llave ausente, mal formada o revocada.                                                                                                                                                                                                                                                                                    | ErrorResponse |
| `403`     | Llave válida pero sin permiso: scope, lista blanca de empresas o modo.                                                                                                                                                                                                                                                    | ErrorResponse |
| `429`     | Demasiadas solicitudes.                                                                                                                                                                                                                                                                                                   | ErrorResponse |
| `default` | Un error no enumerado aparte para esta operación, en el mismo sobre §5.5 que cualquier otro rechazo. Ramifica por `error.code`, nunca solo por el estado HTTP ni por `error.message` — un código que esta operación aún no se ha visto lanzar sigue siendo más seguro para decidir que un texto pensado para una persona. | ErrorResponse |

## `POST /test_helpers/empresas/{empresa_id}/onboarding` [#post-test-helpers-empresas-empresa-id-onboarding]

**Lleva la puesta en marcha de una empresa a cualquier estado**

Solo en sandbox: fuerza el estado de puesta en marcha de la empresa a un `onboarding_status` dado, saltándose todos los pasos intermedios.

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

**Parámetros**

| Parámetro    | En   | Requerido | Tipo   | Notas |
| ------------ | ---- | --------- | ------ | ----- |
| `empresa_id` | path | sí        | string |       |

**Cuerpo**

| Campo          | Tipo                                                                                                                                                                                                                                                                                    | Requerido | Notas |
| -------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | --------- | ----- |
| `status`       | `draft` · `mandato_pending` · `mandato_signed` · `certificate_pending` · `certificate_verified` · `sii_postulacion_pending` · `certification_in_progress` · `cumplimiento_pending` · `resolucion_pending` · `folios_pending` · `emitting` · `action_required` · `blocked` · `suspended` | sí        |       |
| `step`         | string                                                                                                                                                                                                                                                                                  | —         |       |
| **Respuestas** |                                                                                                                                                                                                                                                                                         |           |       |

| Código    | Significado                                                                                                                                                                                                                                                                                                               | Cuerpo                                             |
| --------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------- |
| `200`     | El estado de puesta en marcha forzado.                                                                                                                                                                                                                                                                                    | [Onboarding](/docs/referencia/esquemas#onboarding) |
| `401`     | Llave ausente, mal formada o revocada.                                                                                                                                                                                                                                                                                    | ErrorResponse                                      |
| `403`     | Llave válida pero sin permiso: scope, lista blanca de empresas o modo.                                                                                                                                                                                                                                                    | ErrorResponse                                      |
| `429`     | Demasiadas solicitudes.                                                                                                                                                                                                                                                                                                   | ErrorResponse                                      |
| `default` | Un error no enumerado aparte para esta operación, en el mismo sobre §5.5 que cualquier otro rechazo. Ramifica por `error.code`, nunca solo por el estado HTTP ni por `error.message` — un código que esta operación aún no se ha visto lanzar sigue siendo más seguro para decidir que un texto pensado para una persona. | ErrorResponse                                      |

## `POST /test_helpers/empresas/{empresa_id}/onboarding/steps` [#post-test-helpers-empresas-empresa-id-onboarding-steps]

**Fuerza el estado de un paso concreto de la puesta en marcha**

La más fina de las dos palancas de puesta en marcha. `POST .../onboarding` mueve el ESTADO
de la empresa; esta mueve UN PASO, que es como se producen las partes de §7.4 que un estado
no alcanza a expresar: un paso en `action_required` con su `action_url`, una prueba de
certificación que `failed` para un `tipo_dte` mientras los demás pasaron, o un paso `skipped`
porque el RUT ya era emisor autorizado.

Los cuatro pasos de certificación (`set_de_pruebas`, `simulacion`, `intercambio`,
`muestras_impresas`) existen por tipo de documento. Omite `tipo_dte` para forzar todos los
tipos declarados de una vez; inclúyelo para forzar uno.

Devuelve el objeto de puesta en marcha completo y dispara el mismo webhook
`empresa.onboarding.*` que dispararía la máquina real.

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

**Parámetros**

| Parámetro    | En   | Requerido | Tipo   | Notas |
| ------------ | ---- | --------- | ------ | ----- |
| `empresa_id` | path | sí        | string |       |

**Cuerpo**

| Campo            | Tipo                                                                                                                                                                              | Requerido | Notas                                                                                                          |
| ---------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | --------- | -------------------------------------------------------------------------------------------------------------- |
| `step`           | `mandato` · `certificate` · `sii_postulacion` · `set_de_pruebas` · `simulacion` · `intercambio` · `muestras_impresas` · `cumplimiento` · `resolucion` · `habilitacion` · `folios` | sí        |                                                                                                                |
| `status`         | `pending` · `in_progress` · `action_required` · `completed` · `failed` · `skipped`                                                                                                | sí        |                                                                                                                |
| `tipo_dte`       | `33` · `34` · `39` · `41` · `46` · `52` · `56` · `61`                                                                                                                             | —         | Solo tiene sentido en un paso de certificación. Tiene que ser uno de los `doc_types` declarados de la empresa. |
| `blocked_reason` | object                                                                                                                                                                            | —         | Motivo estructurado que se adjunta a un paso `failed` o `action_required`.                                     |
| **Respuestas**   |                                                                                                                                                                                   |           |                                                                                                                |

| Código    | Significado                                                                                                                                                                                                                                                                                                               | Cuerpo                                             |
| --------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------- |
| `200`     | El objeto de puesta en marcha después de forzar el paso.                                                                                                                                                                                                                                                                  | [Onboarding](/docs/referencia/esquemas#onboarding) |
| `400`     | Entrada mal formada o incompleta.                                                                                                                                                                                                                                                                                         | ErrorResponse                                      |
| `401`     | Llave ausente, mal formada o revocada.                                                                                                                                                                                                                                                                                    | ErrorResponse                                      |
| `403`     | Llave válida pero sin permiso: scope, lista blanca de empresas o modo.                                                                                                                                                                                                                                                    | ErrorResponse                                      |
| `429`     | Demasiadas solicitudes.                                                                                                                                                                                                                                                                                                   | ErrorResponse                                      |
| `default` | Un error no enumerado aparte para esta operación, en el mismo sobre §5.5 que cualquier otro rechazo. Ramifica por `error.code`, nunca solo por el estado HTTP ni por `error.message` — un código que esta operación aún no se ha visto lanzar sigue siendo más seguro para decidir que un texto pensado para una persona. | ErrorResponse                                      |

## `POST /test_helpers/documents/{document_id}/estado` [#post-test-helpers-documents-document-id-estado]

**Fuerza el estado crudo del SII de un documento de sandbox ya emitido**

`test.outcome` en `POST /documents` fuerza un resultado AL EMITIR. Esto fuerza uno DESPUÉS, y es la única manera determinista de ejercitar la transición que de verdad le importa a quien consume webhooks: sin esto, `sent → accepted` es correrle al asentamiento de \~1 s del sandbox, y `stuck → accepted` es inalcanzable.

ESCRIBE EL ESTADO, NO EL STATUS, a propósito. El `status` público se deriva después con el mapeo de siempre, así que una prueba que lleva un documento a `DNK` demuestra que el mapeo a `reparo` funciona en vez de afirmarlo. Se publica el mismo evento `document.*` del ciclo de vida que dispararía la transición real, así que quien esté bajo prueba recibe exactamente lo que manda producción.

Solo sandbox, revisado tres veces: el modo de la llave, la bandera de la empresa y el `is_sandbox` del PROPIO documento — que se estampa al insertar y es inmutable, así que un documento real sigue siendo real aunque después se cambie la bandera de la empresa.

```bash
curl -sS -X POST https://api.facturia.cl/v1/test_helpers/documents/doc_01K2R7Q4XW9M3B8ZC5YHTVJD6N/estado \
  -H "Authorization: Bearer $FACTURIA_KEY" \
  -H "Facturia-Empresa: $EMPRESA" \
  -H "Content-Type: application/json" \
  -d '{"estado":"DOK"}'
```

**Parámetros**

| Parámetro          | En     | Requerido | Tipo   | Notas                                                                                                                                                                                                                                                                                                                                                                                 |
| ------------------ | ------ | --------- | ------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `document_id`      | path   | sí        | string |                                                                                                                                                                                                                                                                                                                                                                                       |
| `Facturia-Empresa` | header | —         | string | La empresa destino: RUT canónico (`77928532-4`) o id de empresa (`emp_…`). Obligatorio en toda llamada con alcance de empresa, salvo que la llave sea un token de empresa. Este header es el ÚNICO mecanismo: no hay parámetro `?empresa=` ni campo `empresa` en el cuerpo. Omitido donde se requiere → `400 empresa_required`; fuera de la lista blanca → `403 empresa_not_allowed`. |

**Cuerpo**

| Campo          | Tipo                                                                                  | Requerido | Notas                                                                                   |
| -------------- | ------------------------------------------------------------------------------------- | --------- | --------------------------------------------------------------------------------------- |
| `estado`       | `DOK` · `DNK` · `FAU` · `FNA` · `FAN` · `EMP` · `RCT` · `EPR` · `SOK` · `RPR` · `RLV` | sí        | El estado del SII que se va a escribir, exactamente como lo haría el ejecutor del poll. |
| **Respuestas** |                                                                                       |           |                                                                                         |

| Código    | Significado                                                                                                                                                                                                                                                                                                               | Cuerpo        |
| --------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------- |
| `200`     | El documento, con su status derivado.                                                                                                                                                                                                                                                                                     | Document      |
| `400`     | Entrada mal formada o incompleta.                                                                                                                                                                                                                                                                                         | ErrorResponse |
| `401`     | Llave ausente, mal formada o revocada.                                                                                                                                                                                                                                                                                    | ErrorResponse |
| `403`     | Llave válida pero sin permiso: scope, lista blanca de empresas o modo.                                                                                                                                                                                                                                                    | ErrorResponse |
| `404`     | No existe ese objeto bajo esta llave.                                                                                                                                                                                                                                                                                     | ErrorResponse |
| `429`     | Demasiadas solicitudes.                                                                                                                                                                                                                                                                                                   | ErrorResponse |
| `default` | Un error no enumerado aparte para esta operación, en el mismo sobre §5.5 que cualquier otro rechazo. Ramifica por `error.code`, nunca solo por el estado HTTP ni por `error.message` — un código que esta operación aún no se ha visto lanzar sigue siendo más seguro para decidir que un texto pensado para una persona. | ErrorResponse |

## `POST /test_helpers/f29/proposals` [#post-test-helpers-f29-proposals]

**Inject a computed F29 propuesta**

Calcular una propuesta es un job del WORKER, y el worker no es parte de la promesa del sandbox (§4.1: el modo de prueba es «una simulación completa en proceso»). Sin este helper, el sandbox puede sembrar un RCV y quedarse esperando para siempre una propuesta que solo produce un worker corriendo, lo que deja intestable toda la superficie de §12.3/§12.4 en modo de prueba.

Escribe la misma fila que escribe el cálculo real, así que todo lo que viene después —el serializador, el enlace al archivo de carga y sobre todo la PUERTA DE DECLARACIÓN— lee una propuesta ordinaria. La puerta no se salta: sigue leyendo `total_payable` y `observations` de esta fila, y sigue exigiendo una validación (ver `/test_helpers/f29/validations`).

Volver a sembrar el mismo período lo actualiza en vez de crear un segundo.

```bash
curl -sS -X POST https://api.facturia.cl/v1/test_helpers/f29/proposals \
  -H "Authorization: Bearer $FACTURIA_KEY" \
  -H "Facturia-Empresa: $EMPRESA" \
  -H "Content-Type: application/json" \
  -d '{"period":"2026-07"}'
```

**Parámetros**

| Parámetro          | En     | Requerido | Tipo   | Notas                                                                                                                                                                                                                                                                                                                                                                                 |
| ------------------ | ------ | --------- | ------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `Facturia-Empresa` | header | —         | string | La empresa destino: RUT canónico (`77928532-4`) o id de empresa (`emp_…`). Obligatorio en toda llamada con alcance de empresa, salvo que la llave sea un token de empresa. Este header es el ÚNICO mecanismo: no hay parámetro `?empresa=` ni campo `empresa` en el cuerpo. Omitido donde se requiere → `400 empresa_required`; fuera de la lista blanca → `403 empresa_not_allowed`. |

**Cuerpo**

| Campo          | Tipo      | Requerido | Notas                                                                                                                         |
| -------------- | --------- | --------- | ----------------------------------------------------------------------------------------------------------------------------- |
| `period`       | Period    | sí        | Período tributario `YYYY-MM` (America/Santiago). Ej.: `"2026-07"`.                                                            |
| `summary`      | object    | —         | Cualquier campo omitido vale 0, y `total_payable` vale `max(0, iva_debito - iva_credito) + iva_retenido + ppm`.               |
| `codes`        | object\[] | —         | Las filas de códigos del F29. Omítelas para un conjunto por defecto plausible.                                                |
| `observations` | object\[] | —         | Una observación con `severity: error` deja la propuesta en `review_required`, que es lo que la puerta de declaración rechaza. |
| **Respuestas** |           |           |                                                                                                                               |

| Código    | Significado                                                                                                                                                                                                                                                                                                               | Cuerpo        |
| --------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------- |
| `201`     | La propuesta sembrada.                                                                                                                                                                                                                                                                                                    | object        |
| `400`     | Entrada mal formada o incompleta.                                                                                                                                                                                                                                                                                         | ErrorResponse |
| `401`     | Llave ausente, mal formada o revocada.                                                                                                                                                                                                                                                                                    | ErrorResponse |
| `403`     | Llave válida pero sin permiso: scope, lista blanca de empresas o modo.                                                                                                                                                                                                                                                    | ErrorResponse |
| `429`     | Demasiadas solicitudes.                                                                                                                                                                                                                                                                                                   | ErrorResponse |
| `default` | Un error no enumerado aparte para esta operación, en el mismo sobre §5.5 que cualquier otro rechazo. Ramifica por `error.code`, nunca solo por el estado HTTP ni por `error.message` — un código que esta operación aún no se ha visto lanzar sigue siendo más seguro para decidir que un texto pensado para una persona. | ErrorResponse |

## `POST /test_helpers/f29/validations` [#post-test-helpers-f29-validations]

**Fuerza el veredicto de la validación cruzada de un período**

La validación cruzada real SE SALTA la consulta al SII en una empresa de sandbox y siempre registra `unavailable` — correctamente, porque una empresa de sandbox no tiene un SII contra el cual contrastarse. Pero `unavailable` no es `validated`, así que sin este helper la puerta de declaración rechaza TODA declaración de sandbox con `not_validated` y al resto de la §12.4 no se llega nunca.

Forzar el VEREDICTO en vez de la declaración es lo que lo mantiene honesto: una prueba que lleva una propuesta a `validated` y después declara demuestra que la puerta deja pasar una propuesta validada, y una que la deja en `unavailable` demuestra que la puerta detiene a la que no lo está. La puerta misma no se toca en ninguno de los dos casos.

```bash
curl -sS -X POST https://api.facturia.cl/v1/test_helpers/f29/validations \
  -H "Authorization: Bearer $FACTURIA_KEY" \
  -H "Facturia-Empresa: $EMPRESA" \
  -H "Content-Type: application/json" \
  -d '{"period":"2026-07"}'
```

**Parámetros**

| Parámetro          | En     | Requerido | Tipo   | Notas                                                                                                                                                                                                                                                                                                                                                                                 |
| ------------------ | ------ | --------- | ------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `Facturia-Empresa` | header | —         | string | La empresa destino: RUT canónico (`77928532-4`) o id de empresa (`emp_…`). Obligatorio en toda llamada con alcance de empresa, salvo que la llave sea un token de empresa. Este header es el ÚNICO mecanismo: no hay parámetro `?empresa=` ni campo `empresa` en el cuerpo. Omitido donde se requiere → `400 empresa_required`; fuera de la lista blanca → `403 empresa_not_allowed`. |

**Cuerpo**

| Campo            | Tipo                                       | Requerido | Notas                                                              |
| ---------------- | ------------------------------------------ | --------- | ------------------------------------------------------------------ |
| `period`         | Period                                     | sí        | Período tributario `YYYY-MM` (America/Santiago). Ej.: `"2026-07"`. |
| `verdict`        | `validated` · `discrepant` · `unavailable` | —         | Por defecto: `"validated"`.                                        |
| `material_count` | integer                                    | —         | Solo en `discrepant`; cuántas diferencias materiales registrar.    |
| **Respuestas**   |                                            |           |                                                                    |

| Código    | Significado                                                                                                                                                                                                                                                                                                               | Cuerpo        |
| --------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------- |
| `201`     | La validación registrada.                                                                                                                                                                                                                                                                                                 | object        |
| `400`     | Entrada mal formada o incompleta.                                                                                                                                                                                                                                                                                         | ErrorResponse |
| `401`     | Llave ausente, mal formada o revocada.                                                                                                                                                                                                                                                                                    | ErrorResponse |
| `403`     | Llave válida pero sin permiso: scope, lista blanca de empresas o modo.                                                                                                                                                                                                                                                    | ErrorResponse |
| `404`     | No existe ese objeto bajo esta llave.                                                                                                                                                                                                                                                                                     | ErrorResponse |
| `429`     | Demasiadas solicitudes.                                                                                                                                                                                                                                                                                                   | ErrorResponse |
| `default` | Un error no enumerado aparte para esta operación, en el mismo sobre §5.5 que cualquier otro rechazo. Ramifica por `error.code`, nunca solo por el estado HTTP ni por `error.message` — un código que esta operación aún no se ha visto lanzar sigue siendo más seguro para decidir que un texto pensado para una persona. | ErrorResponse |
