# Crear documentos (/docs/emision)

## La emisión mínima [#la-emisión-mínima]

El punto de guardar el perfil emisor en la empresa es que una factura son tres campos.

El receptor lleva `giro` y `address` porque el SII no acepta una factura sin ellos: acepta el SOBRE y después rechaza el DOCUMENTO, y el folio se gasta igual. Cuando ya le emitiste una vez a ese RUT, basta con `receptor: {"rut": "…"}` — el resto lo completamos desde tu documento anterior a ese mismo RUT. Si no hay ninguno, recibes `400 receptor_incomplete` nombrando los campos exactos, antes de asignar folio. Las boletas (39/41) y una factura de compra extranjera (46) nunca los necesitan.

#### curl

```bash
curl -sS https://api.facturia.cl/v1/documents \
  -H "Authorization: Bearer $FACTURIA_KEY" \
  -H "Facturia-Empresa: $EMPRESA" \
  -H "Idempotency-Key: $(uuidgen)" \
  -H "Content-Type: application/json" \
  -d '{
    "tipo_dte": 33,
    "receptor": {
      "rut": "76543212-K",
      "giro": "Venta al por mayor de alimentos",
      "address": { "street": "Los Militares 5001, of. 302", "comuna": "Las Condes", "city": "Santiago" }
    },
    "items": [
      { "description": "Desarrollo a medida — agosto", "quantity": 1, "unit_price": 2400000 }
    ]
  }'
```

#### JavaScript

```js
const res = await fetch('https://api.facturia.cl/v1/documents', {
  method: 'POST',
  headers: {
    Authorization: `Bearer ${process.env.FACTURIA_KEY}`,
    'Facturia-Empresa': process.env.EMPRESA,
    'Idempotency-Key': crypto.randomUUID(),
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({
    tipo_dte: 33,
    receptor: {
      rut: '76543212-K',
      giro: 'Venta al por mayor de alimentos',
      address: { street: 'Los Militares 5001, of. 302', comuna: 'Las Condes', city: 'Santiago' },
    },
    items: [{ description: 'Desarrollo a medida — agosto', quantity: 1, unit_price: 2400000 }],
  }),
});

if (!res.ok) {
  const { error } = await res.json();
  throw new Error(`${error.code}: ${error.message} (${error.request_id})`);
}

const documento = await res.json();
```

### Qué completamos por ti [#qué-completamos-por-ti]

| Campo                                                              | De dónde sale                                                                                          |
| ------------------------------------------------------------------ | ------------------------------------------------------------------------------------------------------ |
| Bloque emisor (RUT, razón social, giro, dirección, comuna, acteco) | el perfil de la empresa                                                                                |
| `folio`                                                            | el siguiente folio del CAF activo para este tipo                                                       |
| `issue_date`                                                       | hoy en America/Santiago                                                                                |
| Razón social, giro, dirección y comuna del receptor                | la libreta de direcciones de la empresa, si no el registro de contribuyentes del SII, resuelto por RUT |
| `totals`                                                           | calculados desde `items` bajo las reglas tributarias del tipo                                          |
| `payment_terms`, `currency`, `indicators`                          | valores por defecto sensatos (`contado`, CLP)                                                          |

Si el receptor no se puede resolver y el tipo requiere esos campos, recibes `400 receptor_incomplete`
nombrando exactamente cuáles enviar — nunca un rechazo silencioso del SII tres minutos después.

## La emisión completa [#la-emisión-completa]

Todo lo que el SII te deja decir, dicho explícitamente.

```bash
curl -sS https://api.facturia.cl/v1/documents \
  -H "Authorization: Bearer $FACTURIA_KEY" \
  -H "Facturia-Empresa: $EMPRESA" \
  -H "Idempotency-Key: $(uuidgen)" \
  -H "Content-Type: application/json" \
  -d '{
    "tipo_dte": 33,
    "external_id": "order-8842",
    "issue_date": "2026-08-14",
    "prices_include_tax": false,
    "receptor": {
      "rut": "76543212-K",
      "legal_name": "Comercial Andina Ltda.",
      "giro": "Venta al por mayor de alimentos",
      "address": { "street": "Los Militares 5001, of. 302", "comuna": "Las Condes", "city": "Santiago" },
      "contact": "pagos@andina.cl",
      "email_document_to": ["pagos@andina.cl", "gerencia@andina.cl"]
    },
    "items": [
      {
        "description": "Licencia plataforma — plan Enterprise",
        "detail": "Periodo 2026-08-01 a 2026-08-31",
        "quantity": 12, "unit": "UN", "unit_price": 180000,
        "discount_percent": 5,
        "item_code": { "type": "INT1", "value": "PLAT-ENT" }
      },
      { "description": "Servicio exento de capacitación", "quantity": 1, "unit_price": 300000, "exempt": true }
    ],
    "global_discounts": [ { "type": "percent", "value": 2, "applies_to": "afecto", "reason": "Acuerdo comercial" } ],
    "references": [
      { "tipo_dte": 801, "folio": "OC-99213", "date": "2026-08-01", "code": null, "reason": "Orden de compra" }
    ],
    "payment": { "terms": "credito", "due_date": "2026-09-13", "method": "transferencia" },
    "totals": { "net": 2352000, "iva": 446880, "exempt": 300000, "total": 3098880 },
    "pdf": { "format": "carta", "cedible": true, "public": true },
    "xml": { "public": true },
    "notes": "Gracias por su compra.",
    "metadata": { "crm_deal": "D-1182", "cost_center": "LATAM" }
  }'
```

### Los cuatro campos que conviene entender [#los-cuatro-campos-que-conviene-entender]

> **Trampa — prices_include_tax es el origen del bug del 19%**
>
> Por defecto depende del tipo: `true` para boletas (39/41), `false` para todo lo demás. Ponlo
> explícito y normalizamos en cualquier dirección.
>
> Es la fuente número uno de errores de 19% en la facturación chilena. Que sea un campo con nombre en
> vez de una convención implícita es deliberado: si tu sistema guarda precios brutos y emites una
> factura, dilo.
>
> La normalización no es simétrica. En una factura (33/34/56/61/46) el `<PrcItem>`/`<MontoItem>` del
> SII siempre es NETO (`DTE_v10.xsd`: neto salvo que venga `MntBruto`, que nunca mandamos), así que
> `prices_include_tax: true` ahí se normaliza HACIA ABAJO en la puerta — los `items` que devolvemos, el
> PDF y el `<PrcItem>` quedan en neto (`11990` → `10075.6303`), y el total puede quedar un peso distinto
> del bruto cotizado. En una boleta (39/41), cuyo `MontoItem` es bruto por esquema, el precio se queda
> bruto sin importar `prices_include_tax`.

* **`totals` es opcional y, cuando viene, es una aserción.** Si nuestro cálculo difiere aunque sea en
  un peso, recibes `422 totals_mismatch` con ambas cifras y no se emite nada. Un sistema financiero
  debería mandarlo siempre.
* **`totals.other_taxes`** es 0 salvo en un tipo 46 con `withholding`, donde lleva la retención en
  NEGATIVO (p. ej. `-1891` si el IVA retenido es `1891`) — es la única forma de que
  `total = net + exempt + iva + other_taxes` siga siendo cierto se retenga o no.
* **`global_discounts` acepta como máximo una entrada.** El `<DscRcgGlobal>` del SII es un solo
  `NroLinDR>1`, así que una segunda entrada se rechaza con `400 invalid_field` antes de reservar
  folio — júntalas en una, o pasa el resto a `items[].discount_percent`.
* **Los descuentos son del canal `mercado`.** En una empresa con `emission_channel=sfg` se rechazan
  en la puerta los dos: `global_discounts` con `422 global_discount_not_available_for_channel`, y
  cualquier `items[].discount_percent` mayor que 0 con `422 line_discount_not_available_for_channel`,
  nombrando la línea. El formulario de emisión del portal del SII no tiene ningún campo de descuento
  que hayamos capturado — el formulario capturado trae comentadas tanto la columna «% Desc» por línea
  como sus entradas `EFXP_PCT_DESC`/`EFXP_MNT_DESC` —, así que un descuento aceptado ahí sería un
  descuento que el portal nunca ve: te cotizaríamos `neto 80.000 / total 95.200` y el SII firmaría
  `neto 100.000 / total 119.000`. Se rechaza en vez de descartarse en silencio, porque la diferencia
  se la cobrarías a tu cliente en un documento que solo una nota de crédito puede deshacer. Métele el
  descuento al `unit_price`, o emite por `emission_channel=mercado`. Un `discount_percent` en `0` se
  acepta en los dos canales: es exactamente lo que el portal emitiría.
* **`references` con `code: 1|2|3`** son los códigos de referencia del SII (1 = anula el documento
  referenciado, 2 = corrige texto, 3 = corrige montos). Las referencias a documentos que no son DTE
  (orden de compra, contrato) usan los códigos de `tipo_dte` del SII en el rango 800 y omiten `code`.
  `references[].date` toma la `issue_date` del documento si se omite; `references[].folio` acepta
  número o string, y un número se convierte a su string decimal (`<FolioRef>` es `xs:string` en el
  esquema del SII).
* **`metadata`** es un mapa de strings arbitrario (≤ 20 llaves, ≤ 500 caracteres cada una) que
  guardamos y devolvemos intacto. Nunca llega al SII.
* **`email_document_to`** envía el PDF y el XML al receptor cuando el documento llega a `accepted`.

## El objeto documento [#el-objeto-documento]

```json
{
  "id": "doc_01K2R7Q4XW9M3B8ZC5YHTVJD6N",
  "object": "document",
  "mode": "live",
  "empresa": { "id": "emp_01K2R6ZC4P8QW1VN7T3MHDY9EK", "rut": "77928532-4" },
  "external_id": "order-8842",
  "tipo_dte": 33,
  "folio": 412,
  "issue_date": "2026-08-14",
  "status": "accepted",
  "receptor": { "rut": "76543212-K", "legal_name": "Comercial Andina Ltda." },
  "items": [ { "description": "Licencia plataforma — plan Enterprise", "quantity": 12, "unit_price": 180000, "amount": 2052000 } ],
  "totals": { "net": 2352000, "iva": 446880, "exempt": 300000, "other_taxes": 0, "total": 3098880 },
  "references": [],
  "pdf_url": "https://api.facturia.cl/v1/documents/doc_01K2R7Q4XW9M3B8ZC5YHTVJD6N/pdf",
  "xml_url": "https://api.facturia.cl/v1/documents/doc_01K2R7Q4XW9M3B8ZC5YHTVJD6N/xml",
  "sii": {
    "environment": "produccion",
    "track_id": "0252083112",
    "estado": "DOK",
    "glosa": "Documento Recibido por el SII, datos coinciden",
    "err_code": "0",
    "num_atencion": "8812394",
    "received_at": "2026-08-14T13:06:55Z",
    "last_checked_at": "2026-08-14T13:07:02Z"
  },
  "rejection_reasons": [],
  "metadata": { "crm_deal": "D-1182" },
  "created_at": "2026-08-14T13:04:11Z",
  "accepted_at": "2026-08-14T13:06:55Z"
}
```

## Leer documentos [#leer-documentos]

```bash
# Listar, del más nuevo al más antiguo, con filtros
curl -G https://api.facturia.cl/v1/documents \
  -H "Authorization: Bearer $FACTURIA_KEY" -H "Facturia-Empresa: $EMPRESA" \
  -d status=accepted -d tipo_dte=33 \
  -d "issue_date[gte]=2026-08-01" -d "issue_date[lte]=2026-08-31" \
  -d limit=50

# Un documento
curl https://api.facturia.cl/v1/documents/doc_01K2R7Q4XW9M3B8ZC5YHTVJD6N \
  -H "Authorization: Bearer $FACTURIA_KEY" -H "Facturia-Empresa: $EMPRESA"

# Por folio (los folios son únicos por empresa+tipo, así que es una búsqueda legítima)
curl -G https://api.facturia.cl/v1/documents \
  -H "Authorization: Bearer $FACTURIA_KEY" -H "Facturia-Empresa: $EMPRESA" \
  -d tipo_dte=33 -d folio=412
```

Filtros: `status`, `tipo_dte`, `folio`, `receptor_rut`, `external_id`, `issue_date[gte|lte]`,
`created_at[gte|lte]`. El `mode` es implícito de la llave.

Un `status` no reconocido devuelve `400 invalid_field` nombrando los siete valores válidos — una
página vacía se leería como «no tienes ninguno de esos», que es una respuesta distinta y mucho más
confusa.

**Cada filtro, `status` incluido, se aplica en la consulta.** Una página filtrada es una página
completa, y `has_more` / `next_cursor` significan lo que dicen: pagina hasta que `has_more` sea false
y tienes el conjunto entero.

## Expansión [#expansión]

Los documentos devuelven `pdf_url` y `xml_url` por defecto. Para evitar una segunda vuelta:

```bash
curl "https://api.facturia.cl/v1/documents/doc_01K2R7Q4XW9M3B8ZC5YHTVJD6N?expand=xml,pdf_base64,events" \
  -H "Authorization: Bearer $FACTURIA_KEY" -H "Facturia-Empresa: $EMPRESA"
```

`expand` acepta una lista separada por comas: `xml` (string en línea), `pdf_base64`, `events`,
`references`, `received_document` (en documentos emitidos en respuesta a uno recibido). Un valor no
reconocido es `400 invalid_field` con la lista de lo que sí acepta este recurso — no un 200 en
silencio en el que no puedes distinguir un typo de un resultado vacío.

**En un listado el vocabulario es más angosto.** `GET /v1/documents?expand=…` acepta `events`,
`references` y `received_document`; `xml` y `pdf_base64` son `400` ahí y solo existen en
`GET /v1/documents/{document_id}`. Cada uno de los excluidos incorpora un artefacto completo por
fila, así que en una página de cien documentos serían cien lecturas de archivo en una sola respuesta.

`received_document` se resuelve **al emitir**: el documento emitido debe referenciar el `tipo_dte` y
`folio` del recibido, y el RUT emisor del recibido debe ser el RUT receptor del emitido, dentro de la
misma empresa. Si calzan dos, el vínculo queda en `null` — un antecedente equivocado es una
afirmación, y una ausencia no lo es.

**El objeto documento no trae enlaces públicos.** Ni en una lectura, ni en un listado, ni en un
webhook: la URL con su secreto `?k=` aparece una sola vez, dentro del objeto `public_links` de la
respuesta que la mintea — la emisión que pidió `pdf: { "public": true }` / `xml: { "public": true }`,
o `POST /v1/documents/{document_id}/public_links`. Guardamos el secreto hasheado, igual que una llave
de API, así que no hay lectura capaz de reconstruirlo. Ver
[Artefactos y enlaces públicos](/docs/emision/artefactos#enlaces-publicos).

- [Tipos de documento](/docs/emision/tipos): Los ocho tipos, sus bloques específicos y las referencias.

- [Previews](/docs/emision/previews): Precio y validación completos sin gastar un folio.

- [Estados](/docs/emision/estados): El mapa de DOK, DNK, RCT y los siete estados públicos.
