Skip to content

What is a DTE? Chile's electronic tax documents, explained

A developer's guide to Chile's DTE system: the eight document types, folios and the CAF, the TED stamp, signatures, the SII lifecycle, and the pitfalls that break integrations.

Arrow Software Team
Arrow Software TeamOctober 28, 2026 · 6 min read
Laptop screen showing financial charts and reports
In Chile, every sale ends up as a signed XML document the tax authority can verify. Source: Unsplash.

If you sell anything in Chile, you issue DTEs. Every invoice, receipt and credit note travels to the tax authority as a signed XML file. For developers it's one of those domains that looks like "generate some XML and POST it" and turns out to be a chain of accounting and cryptographic rules, where a one-peso rounding difference or an expired file stops everything. This post explains the system from a developer's point of view: what a DTE is, which types you'll meet, the lifecycle every document goes through, and the pitfalls that catch most integrations.

What is a DTE?#

A DTE (Documento Tributario Electrónico) is a tax document issued electronically: an XML file, signed by the issuer, that the SII (Servicio de Impuestos Internos, Chile's tax authority) receives and validates. Electronic invoicing is mandatory for businesses in Chile, so for most companies DTEs aren't an option. They're simply how sales get documented.

The most important idea is that the XML is the document. The PDF you email to a customer, or the receipt printed at a till, is only a representation of it. That representation carries a barcode with a signed summary of the original, so anyone can check that the paper matches what was reported.

Every DTE is identified by three values: the issuer's RUT, the document type and the folio. The SII won't accept two documents that share all three.

The eight document types you'll meet#

Each type has a numeric code, and most integrations only ever touch a handful:

CodeDocumentWhen you use it
33Electronic invoiceTaxable sales to other businesses
34Exempt electronic invoiceSales exempt from IVA
39Electronic receiptSales to final consumers
41Exempt electronic receiptExempt sales to final consumers
46Electronic purchase invoiceThe buyer issues it when the seller can't
52Electronic dispatch guideMoving goods, with or without a sale
56Electronic debit noteIncreasing or correcting a previous document
61Electronic credit noteVoiding, reducing or correcting a previous document

Invoices list net prices and add 19% IVA on top; receipts show prices with IVA already included. Credit and debit notes never stand alone: they must reference the document they modify.

The lifecycle of a DTE#

Every document, whatever its type, goes through the same five stages.

1. Folios and the CAF. You can't number documents freely. The SII authorizes folios in ranges, per document type, by issuing a CAF (Código de Autorización de Folios): an XML file with the range, your RUT, the SII's signature and a private key. That key is what proves each folio you use was authorized.

2. The TED. Each document gets a TED (Timbre Electrónico DTE), a small block that summarizes the key fields (RUTs, type, folio, date, total, first item), embeds the CAF and is signed with the CAF's private key. It's the TED that gets printed as a PDF417 barcode.

3. The signature. The whole document is then signed with XMLDSig using a digital certificate issued to a person authorized to sign for the company. The TED proves the folio; the signature proves the issuer.

4. The upload. Signed documents travel in an envelope called EnvioDTE. Before uploading, the client authenticates with the same certificate by signing a seed the SII provides and exchanging it for a token. The SII answers with a track id.

5. Acceptance. Receiving an upload isn't accepting it. The SII validates the schema, the signatures, the TED and its business rules asynchronously, and each document ends up accepted, accepted with objections (reparos) or rejected. Only then is the document really issued.

Common pitfalls#

Rounding IVA line by line#

Amounts in a DTE are whole pesos, and IVA is calculated on the net total, not per line. Take two lines of CLP 2,450 net each. Rounding IVA per line gives 465.5 → 466 twice, so 932. Calculating it on the 4,900 net total gives 931. A one-peso difference is enough for the SII's validation to flag the document, and it only shows up with certain prices, which is why it survives testing.

TypeScript
import { calculateTotals } from 'dte-sdk'
 
calculateTotals([
  { name: 'Soporte mensual', quantity: 1, unitPrice: 2450 },
  { name: 'Hosting mensual', quantity: 1, unitPrice: 2450 },
])
// { net: 4900, exempt: 0, vatRate: 19, vat: 931, total: 5831 }

Round each line amount to whole pesos, add them up, and compute IVA once on the net total. Never let floating-point amounts reach the XML.

Letting a CAF expire#

CAFs have an expiry date. Teams request a generous range, use part of it, and months later find that the remaining folios can't be used. Size your requests to your actual volume, monitor the expiry date, and request the next CAF before the current one runs out of folios or time.

Sending to the wrong environment#

The SII runs a certification environment for testing and a production environment for real documents, and the two share nothing: a CAF from certification is useless in production. The expensive mistake goes the other way: test documents sent to production are real tax documents. Make the environment an explicit setting in every call, never a default.

Mixing up encodings#

The SII works in ISO-8859-1. An address like "Huérfanos" encoded as UTF-8 in one step and as ISO-8859-1 in another produces garbled text at best and an invalid signature at worst, because the signature covers the exact bytes. Pick one encoding at the boundary and keep it.

Treating "received" as "accepted"#

A track id means the upload arrived, nothing more. Store it next to the folio, check the status until it settles, and only then deliver the document to the customer.

How dte-sdk models it#

dte-sdk maps the lifecycle to one function per stage, and its types follow the same order: you can't sign a document that hasn't been stamped, or send one that hasn't been signed.

TypeScript
import { createDte, stampDte, signDte, sendToSii, getStatus } from 'dte-sdk'
 
const dte = createDte({ type: 33, folio: 1024, issuer, receiver, items })
const stamped = stampDte(dte, caf)                 // TED, signed with the CAF key
const signed = await signDte(stamped, certificate) // XMLDSig with your certificate
 
const { trackId } = await sendToSii(signed, {
  certificate,
  environment: 'certification',
  senderRut: '15.234.567-4',
  resolution: { number: 0, date: '2026-09-01' },
})
 
const status = await getStatus(trackId, {
  certificate,
  environment: 'certification',
  issuerRut: '76.123.456-0',
})

createDte() validates RUTs and amounts and computes totals with the rounding rules above, so most mistakes surface as a typed DteError in your code instead of a rejection from the SII. stampDte() checks that the folio is inside the CAF's range, that the CAF matches the document type and issuer, and that it hasn't expired. environment has no default. Error messages never include RUTs, amounts, keys or passwords, so they're safe to log.

dte-sdk is pre-release: the published 0.0.2 is a placeholder, and the code above shows the planned 1.0 API, which may still change.

Further reading#

dte-sdk

MIT License © 2026 Arrow Software