stampDte()
Adds the electronic stamp (TED, Timbre Electrónico DTE) to a document, using the CAF the SII authorized for its folio range.
Basic Usage#
import { readFile } from 'node:fs/promises'
import { parseCaf, stampDte } from 'dte-sdk'
const caf = parseCaf(await readFile(process.env.DTE_CAF_33_PATH!, 'latin1'))
const stamped = stampDte(dte, caf)
stamped.ted // '<TED version="1.0"><DD><RE>76123456-0</RE><TD>33</TD><F>1024</F>…</TED>'
stamped.pdf417 // payload for the PDF417 barcode on the printed versionType Signature#
function stampDte(dte: Dte, caf: Caf | string, options?: { stampedAt?: Date }): StampedDte
function parseCaf(xml: string): Caf
interface Caf {
type: DteType
issuerRut: string
range: { from: number; to: number }
authorizedAt: string
expiresAt: string
}
// StampedDte = Dte + { ted: string; pdf417: string }Parameters#
dte(Dte) - A document fromcreateDte().caf(Caf | string) - The CAF for the document's type, either parsed withparseCaf()or as the raw CAF XML string. When you stamp many documents, parse once and reuse theCaf.options(optional)stampedAt(Date, default: now) - The timestamp written into the TED. Pin it in tests for reproducible output.
Return Value#
Returns a StampedDte: the same document plus two fields.
ted(string) - The<TED>XML element, signed with the CAF private key.pdf417(string) - The payload to render as a PDF417 barcode on the printed version of the document. dte-sdk does not render PDFs or barcodes; hand this string to your own printing pipeline.
The input dte is not modified.
Errors#
| Code | When |
|---|---|
FOLIO_OUT_OF_RANGE | The document's folio is outside caf.range |
CAF_MISMATCH | The CAF is for a different document type, or for a different issuer RUT |
CAF_EXPIRED | The stamp date (stampedAt, or now) is after caf.expiresAt |
All three mean the same thing operationally: this CAF can't stamp this document. Request or load the right CAF; retrying won't help.
parseCaf()#
The SII hands you a CAF (Código de Autorización de Folios) as an XML file for each folio range you request. parseCaf() reads it into a typed Caf:
import { readFile } from 'node:fs/promises'
import { parseCaf } from 'dte-sdk'
const caf = parseCaf(await readFile(process.env.DTE_CAF_33_PATH!, 'latin1'))
caf.type // 33
caf.issuerRut // '76123456-0'
caf.range // { from: 1001, to: 2000 }
caf.authorizedAt // '2026-10-15'
caf.expiresAt // '2027-04-15'CAF files are encoded as ISO-8859-1, so read them as latin1 in Node to keep accented characters intact.
Treat the CAF as a secret. The CAF XML contains the private key that
produces the stamp. Keep it out of your repository and load it from a secret
store or a protected path. DteError messages never include CAF private keys.
parseCaf() only reads the file. Folio range and expiry are checked when you call stampDte().
Examples#
Check the Range Before Allocating a Folio#
import type { Caf } from 'dte-sdk'
function hasFolio(caf: Caf, folio: number): boolean {
return folio >= caf.range.from && folio <= caf.range.to
}
function foliosLeft(caf: Caf, lastUsed: number): number {
return caf.range.to - lastUsed
}
hasFolio(caf, 1024) // true
foliosLeft(caf, 1024) // 976Warn your team well before foliosLeft() reaches zero: a new CAF has to be requested before you can issue more documents of that type.
One CAF per Document Type#
Each CAF covers a single document type. Keep one per type you issue and pick it by dte.type:
import { parseCaf, stampDte, type Caf, type DteType } from 'dte-sdk'
const cafs = new Map<DteType, Caf>([
[33, parseCaf(invoiceCafXml)],
[61, parseCaf(creditNoteCafXml)],
])
const stamped = stampDte(dte, cafs.get(dte.type)!)Stamping a credit note with the invoice CAF throws CAF_MISMATCH.
Reproducible Stamps in Tests#
import { stampDte, toXml } from 'dte-sdk'
const stamped = stampDte(dte, caf, {
stampedAt: new Date('2026-10-28T10:15:00-03:00'),
})
expect(toXml(stamped)).toMatchSnapshot()Handling Stamp Errors#
import { DteError, stampDte } from 'dte-sdk'
try {
return stampDte(dte, caf)
} catch (error) {
if (!(error instanceof DteError)) throw error
switch (error.code) {
case 'FOLIO_OUT_OF_RANGE':
throw new Error('Folio range exhausted: load a new CAF')
case 'CAF_EXPIRED':
throw new Error('CAF expired: request a new one')
case 'CAF_MISMATCH':
throw new Error('Wrong CAF for this document type or issuer')
default:
throw error
}
}Related Functions#
createDte()- Builds the document you stampsignDte()- Next step: sign the stamped documenttoXml()- See where the<TED>lands in the XML