Skip to content

Core API (dte-sdk)

The root entry of the package. It holds documents, stamps, signatures and envelopes, the verification of received documents, the SII books and the SII web services client (seed and token, uploads, status queries, acceptance and claims) and the public registry of authorized issuers. It runs on Node, Bun and Deno, bundles for the browser, and never mentions a node: module. The Node adapters, the portal and the printed samples have their own entries: dte-sdk/node, dte-sdk/portal and dte-sdk/pdf.

TypeScript
import { createDocument, stampDocument, signDocument, createSiiClient, DteError } from 'dte-sdk'

Documents, stamps, signatures, envelopes and books have not been sent to the real SII yet, and the verification of received documents has not met a document a supplier sent. Of the web services client, only the seed and token over SOAP and the acceptance and claim registry have met the real SII, and only in production; uploads, status queries and the receipts REST API have not run in either environment yet (issue 8), and the registry of authorized issuers has no run on record. All of it is tested against synthetic SII answers. See Status and the conventions shared by the whole API.

Errors#

Every failure the SDK raises is a DteError with a stable code. Branch on error.code, never on the message. The message is generic and carries only safe keys (field names, codes, numbers); the offending value, if any, lives in details, so no RUT or free text reaches your logs. Every entry point throws this class. What each code means is in Errors.

DTE_ERROR_CODES has 46 codes:

INVALID_RUT, INVALID_DOCUMENT_TYPE, INVALID_FOLIO, INVALID_DATE, INVALID_AMOUNT, MISSING_FIELD, FIELD_TOO_LONG, CAF_INVALID, CAF_EXPIRED, CAF_TYPE_MISMATCH, CAF_ISSUER_MISMATCH, FOLIO_OUT_OF_RANGE, CERT_INVALID, CERT_PASSWORD_WRONG, CERT_EXPIRED, CERT_NOT_YET_VALID, XML_PARSE_FAILED, SIGNATURE_NOT_FOUND, ENCODING_UNSUPPORTED_CHAR, ENVELOPE_EMPTY, ENVELOPE_KIND_MISMATCH, INVALID_OPTION, TRANSPORT_UNAVAILABLE, TRANSPORT_FAILED, TRANSPORT_TLS, REQUEST_TIMEOUT, REQUEST_ABORTED, SII_HTTP_ERROR, SII_RESPONSE_INVALID, SII_SOAP_FAULT, SII_SEED_FAILED, SII_TOKEN_FAILED, SII_TOKEN_INVALID, SII_UPLOAD_REJECTED, SII_QUERY_ERROR, WAIT_TIMEOUT, BOOK_TOTAL_MISMATCH, SII_PORTAL_LOGIN_FAILED, SII_PORTAL_CERT_NOT_ENABLED, SII_PORTAL_SESSION_LIMIT, SII_PORTAL_SESSION_EXPIRED, SII_PORTAL_BLOCKED, SII_PORTAL_REJECTED, SII_PORTAL_UNEXPECTED_PAGE, DEPENDENCY_UNAVAILABLE, PDF_RENDER_FAILED.

TypeScript
// Typed error thrown by dte-sdk. The message is generic (code + safe keys such as the field name);
// the offending value, if any, lives in `details` so no RUT or free text leaks into logs.
class DteError extends Error {
  readonly code: DteErrorCode
  readonly details: DteErrorDetails
  constructor(code: DteErrorCode, details?: DteErrorDetails)
}
 
// Stable error codes thrown by dte-sdk. Branch on `error.code`, never on the message text.
const DTE_ERROR_CODES: {
  readonly INVALID_RUT: "INVALID_RUT"
  readonly INVALID_DOCUMENT_TYPE: "INVALID_DOCUMENT_TYPE"
  readonly INVALID_FOLIO: "INVALID_FOLIO"
  readonly INVALID_DATE: "INVALID_DATE"
  readonly INVALID_AMOUNT: "INVALID_AMOUNT"
  readonly MISSING_FIELD: "MISSING_FIELD"
  // ... 40 more members
}
 
// The code of a thrown value when it is a `DteError`, else undefined. For results that report
// failures as data.
function errorCode(error: unknown): DteErrorCode | undefined
 
// Type guard for `DteError`.
function isDteError(value: unknown): value is DteError
TypeDescription
DteErrorCodeUnion of every DTE_ERROR_CODES value.
DteErrorDetailsStructured context of an error. May hold the offending value; it is never copied into message. Defined as Readonly<Record<string, unknown>>.

Document types and code catalogs#

Closed catalogs of the codes the SII schemas use, keyed by English names, with the predicates and type guards that go with them. The supported document types are 33, 34, 39, 41, 43, 46, 52, 56 and 61. See Documents.

TypeScript
// SII document type codes supported by dte-sdk, keyed by their English name.
const DOCUMENT_TYPES: {
  readonly invoice: 33
  readonly exemptInvoice: 34
  readonly receipt: 39
  readonly exemptReceipt: 41
  readonly settlementInvoice: 43
  readonly purchaseInvoice: 46
  readonly dispatchGuide: 52
  readonly debitNote: 56
  readonly creditNote: 61
}
 
// Every supported code, ascending.
const DOCUMENT_TYPE_VALUES: readonly DocumentType[] = [33, 34, 39, 41, 43, 46, 52, 56, 61]
 
// Type guard: true when `value` is one of the supported `TipoDTE` codes.
function isDocumentType(value: unknown): value is DocumentType
 
// True for receipts (39, 41): no identified receiver required, no `TasaIVA`, REST channel.
function isReceipt(type: DocumentType): boolean
 
// True for the VAT-exempt types (34, 41): every line is exempt.
function isExemptType(type: DocumentType): boolean
 
// True for debit and credit notes (56, 61), which must reference another document.
function isNote(type: DocumentType): boolean
 
// True when the type needs an identified receiver (everything but receipts).
function requiresReceiver(type: DocumentType): boolean
 
// True when the printed document carries a transferable copy (cedible) and the Ley 19.983
// acknowledgement box.
function isTransferable(type: DocumentType): boolean
 
// Official Spanish name of a document type: `long` (default), `short` (uppercase, no accents) or
// `printed` (uppercase per the SII printed-samples manual).
function documentTypeName(type: DocumentType, variant?: keyof NameVariants): string
 
// SII environments: `certification` (maullin, test) and `production` (palena).
const ENVIRONMENTS: { readonly certification: "certification"; readonly production: "production" }
 
// Type guard for `Environment`.
function isEnvironment(value: unknown): value is Environment
 
// Reference codes used in `Referencia/CodRef` by credit and debit notes.
const REFERENCE_CODES: {
  readonly cancels: 1
  readonly correctsText: 2
  readonly correctsAmounts: 3
}
 
// Transfer reasons for dispatch guides (`IdDoc/IndTraslado`).
const TRANSFER_TYPES: {
  readonly sale: 1
  readonly pendingSale: 2
  readonly consignment: 3
  readonly freeDelivery: 4
  readonly internalTransfer: 5
  readonly otherNonSale: 6
  readonly return: 7
  readonly exportTransfer: 8
  readonly exportSale: 9
}
 
// Who dispatches the goods (`IdDoc/TipoDespacho`).
const DISPATCH_TYPES: {
  readonly byReceiver: 1
  readonly byIssuerToReceiver: 2
  readonly byIssuerToOther: 3
}
 
// Service indicator (`IdDoc/IndServicio`), mandatory on receipts (3 is the common case).
const SERVICE_INDICATORS: {
  readonly periodicServices: 1
  readonly periodicHomeServices: 2
  readonly salesAndServices: 3
  readonly shows: 4
}
 
// Payment terms (`IdDoc/FmaPago`).
const PAYMENT_TERMS: { readonly cash: 1; readonly credit: 2; readonly free: 3 }
 
// Line exemption indicator (`Detalle/IndExe`).
const EXEMPT_INDICATORS: {
  readonly exempt: 1
  readonly nonBillable: 2
  readonly containerDeposit: 3
  readonly notASale: 4
  readonly deduction: 5
  readonly nonBillableNegative: 6
}
 
// Withholding tax codes used in `Totales/ImptoReten/TipoImp`.
const WITHHOLDING_TAX_CODES: { readonly totalVatWithholding: 15 }
 
// VAT rate in force, percent.
const VAT_RATE = 19
 
// RUT of the SII itself, the receiver of every envelope.
const SII_RUT = '60803000-K'
 
// Generic final-consumer RUT used on receipts without an identified buyer.
const FINAL_CONSUMER_RUT = '66666666-6'
 
// `IDK` value that marks a certification-environment CAF.
const CERTIFICATION_KEY_ID = 100
TypeDescription
DocumentTypeUnion of the supported TipoDTE codes.
EnvironmentUnion of the environment names.
ReferenceCodeUnion of REFERENCE_CODES values.
TransferTypeUnion of TRANSFER_TYPES values.
DispatchTypeUnion of DISPATCH_TYPES values.
ServiceIndicatorUnion of SERVICE_INDICATORS values.
PaymentTermsUnion of PAYMENT_TERMS values.
ExemptIndicatorUnion of EXEMPT_INDICATORS values.

Model types#

The English domain model. You pass a DocumentInput to createDocument and get back an immutable Document, with validated RUTs, sanitized text and computed totals. Where a type has an Input twin, the Input one is what you write and the other is its normalized form. The table lists every model type; DocumentInput and Totals are expanded below it. See Documents and Totals.

TypeDescription
IssuerParty that issues the document (Emisor).
IssuerInputIssuer as the caller provides it: the RUT may come in any shape.
ReceiverParty that receives the document (Receptor).
ReceiverInputReceiver as the caller provides it.
ItemCodeItem code (CdgItem): a code system and the code itself.
LineItemA normalized detail line (Detalle).
LineItemInputA detail line as the caller provides it; amounts are computed unless amount is given.
WithholdingWithholding tax entry (ImptoReten), e.g. total VAT withholding on purchase invoices.
CommissionTotalsCommission totals of a settlement invoice (Totales/Comisiones).
TotalsDocument totals (Totales). Integer pesos.
ReceiptReferenceNormalized reference of a receipt.
ReceiptReferenceInputReference on a receipt (39, 41) as the caller provides it. The receipts schema gives Referencia its own shape: no date, and a code that is the company's own text.
ReferenceNormalized reference.
ReferenceInputReference to another document as the caller provides it (Referencia).
GlobalAdjustmentNormalized global adjustment.
GlobalAdjustmentInputGlobal discount or surcharge as the caller provides it (DscRcgGlobal).
CommissionLineCommission or other charge line of a settlement invoice (Comisiones).
CommissionLineInputCommission line as the caller provides it. Defined as Omit<CommissionLine, 'lineNumber'>.
DriverDriver of the transport (Chofer).
TransportTransport data of a dispatch guide (Transporte).
TransportInputTransport as the caller provides it.
PaymentA payment installment (MntPagos).
HeaderOptionsOptional IdDoc fields. Only the ones you set are emitted, in schema order.
SubtotalInfoInformative subtotal (SubTotInfo).
HeaderDocument header (Encabezado).
DocumentA normalized document, ready to be rendered, stamped and signed. Produced by createDocument.
DocumentInputWhat the caller passes to createDocument.

Fields of Totals

FieldTypeDescription
netAmount?numberNet amount: VAT-affected lines before tax; omitted when 0.
exemptAmount?numberExempt amount (IndExe=1 lines).
vatRate?numberVAT rate percent (19); never on receipts.
vatAmount?numberVAT amount.
ownVatAmount?numberOwn VAT (settlement invoices).
thirdPartyVatAmount?numberThird-party VAT (settlement invoices).
withholdings?readonly Withholding[]Withholdings.
commissions?CommissionTotalsCommission totals (43).
totalAmountnumberDocument total: net + VAT + exempt (VAT excluded when withheld).
nonBillableAmount?numberNon-billable amount (lines with IndExe 2-6).
periodAmount?numberPeriod amount.
previousBalance?numberPrevious balance.
amountDue?numberAmount due.

Fields of DocumentInput

FieldTypeDescription
typeDocumentTypeDocument type.
folionumberFolio authorized by the CAF.
issueDate?stringIssue date YYYY-MM-DD; defaults to today in Chile.
issuerIssuerInput
receiver?ReceiverInputReceiver; optional on receipts (anonymous final consumer).
itemsreadonly LineItemInput[]
references?readonly ReferenceInput[]
receiptReferences?readonly ReceiptReferenceInput[]References of a receipt (39, 41); references is for every other type.
globalAdjustments?readonly GlobalAdjustmentInput[]
subtotals?readonly SubtotalInfo[]
commissions?readonly CommissionLineInput[]
transport?TransportInput
options?HeaderOptions
pricesIncludeVat?booleanUnit prices already include VAT: emits MntBruto=1 and derives net/VAT from the gross.
withholdVat?booleanWithhold the whole VAT (ImptoReten 15, total without VAT); true by default on purchase invoices, settable on the notes that affect one.
totals?TotalsExplicit totals (advanced); computed when omitted.

Codec: English model and SII tags#

The model uses English names; the SII schemas use their own tags (MntTotal, RznSoc). toSiiDocument and fromSiiDocument convert between the two, with the keys in schema order. The Sii* types describe the official tags.

TypeScript
// Maps a domain `Document` to the SII-shaped structure (official tags, schema order). This is the
// only place that knows the tag names; the XML is always rendered from its output.
function toSiiDocument(doc: Document): SiiDocumento
 
// Maps a SII-shaped document back to the domain model (for received DTEs and interop). RUTs are
// validated with rut.ts on the way in.
function fromSiiDocument(sii: SiiDocumento): Document
TypeDescription
SiiDocumentoThe document body with official tags, in the order Documento/Liquidacion require. TED and TmstFirma are added when rendering.
SiiEncabezadoEncabezado, SII shape.
SiiIdDocIdDoc with the official tags, in schema order.
SiiMntPagosPayment installment, SII shape.
SiiEmisorEmisor, SII shape (receipts use RznSocEmisor/GiroEmisor).
SiiReceptorReceptor, SII shape.
SiiTransporteTransporte, SII shape.
SiiTotalesTotales, SII shape, schema order.
SiiImptoRetenImptoReten, SII shape.
SiiComisionesTotalesTotales/Comisiones, SII shape.
SiiDetalleDetalle, SII shape, schema order.
SiiCdgItemCdgItem, SII shape.
SiiSubTotInfoSubTotInfo, SII shape.
SiiDscRcgGlobalDscRcgGlobal, SII shape.
SiiReferenciaReferencia, SII shape.
SiiReferenciaBoletaReferencia of a receipt (39, 41), SII shape: the receipts schema has no date and a free-text code.
SiiComisionesComisiones line (43), SII shape.

RUT helpers#

RUT handling is delegated to rut.ts. toSiiRut accepts dotted, hyphenated or compact input, validates it (Modulo 11) and returns the branded SiiRut string in the shape the SII schemas expect (12345678-5: no dots, hyphen, uppercase K).

TypeScript
// Validates a RUT with rut.ts (Modulo 11) and returns it in SII shape. Accepts dotted, hyphenated
// or compact input.
function toSiiRut(value: string, field?: string): SiiRut
 
// Type guard: true when `value` is already a valid RUT in SII shape.
function isSiiRut(value: unknown): value is SiiRut
 
// Splits a SII RUT into body and verifier (what the SII multipart fields `rutSender`/`dvSender`
// need).
function splitSiiRut(rut: SiiRut): { readonly body: string; readonly verifier: string; }
TypeDescription
SiiRutA RUT already validated with rut.ts and formatted the way the SII schemas expect: no dots, hyphen, uppercase K (12345678-5). The brand is phantom: the only way to mint one is toSiiRut.

Text, encoding and time#

Text sanitizing, the ISO-8859-1 encoding the SII requires, and the Chile clock (America/Santiago, DST-aware). The time functions take an optional now so tests do not depend on the real clock.

Text and encoding#

TypeScript
// Normalizes free text for a DTE field: drops apostrophes and double quotes (they break the SII
// signature checks), maps typographic dashes and ellipsis to ASCII, removes anything outside
// ISO-8859-1 (emoji, curly quotes) and trims.
function sanitizeText(text: string | null | undefined): string
 
// Folds text to printable ASCII for the TED (`RSR`, `IT1`): strips diacritics (á→a, ñ→n), expands
// ligatures and special letters (ß→ss, Æ→AE, Þ→TH), then drops every remaining non-ASCII
// character.
function foldToAscii(text: string | null | undefined): string
 
// Sanitizes and cuts text to `maxLength`; with `preserveWords`, backs up to the last space when it
// sits past 70 % of the limit.
function truncateText(
  text: string | null | undefined,
  maxLength: number,
  preserveWords?: boolean,
): string
 
// Throws `FIELD_TOO_LONG` when the (already sanitized) text exceeds the `xs:maxLength` of the SII
// schema. The SII rejects the WHOLE envelope when one document fails the schema, so this fails
// early instead of truncating silently.
function assertMaxLength(value: string, maxLength: number, field: string): void
 
// Encodes text as ISO-8859-1 bytes (what the SII upload endpoints expect). Throws instead of
// truncating a code point above U+00FF to its low byte, which is how corrupted control characters
// used to reach the SII.
function encodeLatin1(text: string): Uint8Array
 
// Decodes ISO-8859-1 bytes to a string (one char per byte).
function decodeLatin1(bytes: Uint8Array): string

Time#

TypeScript
// Today's date in Chile as `YYYY-MM-DD` (the SII `FchEmis`/`FchResol` format).
function chileDate(now?: Date): string
 
// Chile-local timestamp `YYYY-MM-DDTHH:MM:SS` without zone or milliseconds (`TmstFirma`,
// `TmstFirmaEnv`, `TSTED`). Never built with `toISOString()`, which is always UTC and put
// envelopes ~3 h in the future ("Error en Carátula").
function chileTimestamp(now?: Date): string
 
// Breaks an instant (default: now) into Chile-local components using `Intl`, never the process
// time zone.
function chileDateTimeParts(now?: Date): ChileDateTimeParts
 
// Normalizes `DD-MM-YYYY`, `DD/MM/YYYY` or `YYYY-MM-DD` (as the SII portal and resolutions show
// dates) to ISO.
function toIsoDate(value: string, field?: string): string
 
// True when `value` is a real calendar date in `YYYY-MM-DD`.
function isIsoDate(value: string): boolean
TypeDescription
ChileDateTimePartsZero-padded date and time components of an instant in Chile (America/Santiago, DST-aware).

Totals#

Line amounts and document totals with the SII rounding rules. See Totals.

TypeScript
// Computes a detail line amount with per-line rounding (the SII compares `MontoItem` against
// `QtyItem × PrcItem`).
function calculateLineAmount(input: LineAmountInput): LineAmount
 
// Computes `Totales` from detail lines: net, exempt, VAT (derived from the gross when
// `pricesIncludeVat`), non-billable, withholding for purchase invoices and the total.
function calculateTotals(
  items: readonly Pick<LineItem, "amount" | "exemptIndicator">[],
  options: TotalsOptions,
): Totals
TypeDescription
LineAmountInputInputs of a line amount.
LineAmountResult of a line amount computation, integer pesos.
TotalsOptionsOptions of calculateTotals.

Fields of LineAmountInput

FieldTypeDescription
quantity?numberQuantity (default 1).
unitPrice?numberUnit price (default 0).
discountPercent?numberDiscount percent.
surchargePercent?numberSurcharge percent.

Fields of LineAmount

FieldTypeDescription
basenumberround(quantity × unitPrice).
discountAmountnumberDiscount in pesos.
surchargeAmountnumberSurcharge in pesos.
amountnumberbase − discount + surcharge.

Fields of TotalsOptions

FieldTypeDescription
typeDocumentTypeDocument type (drives receipts, withholding).
pricesIncludeVat?booleanLine amounts include VAT.
vatRate?numberVAT rate percent (default 19).
globalAdjustments?readonly GlobalAdjustment[]Global discounts/surcharges.
withholdVat?booleanWithhold the whole VAT (default: true for purchase invoices).

Documents#

Create, render, sign and issue documents. createDocument validates and normalizes a DocumentInput; issueDocument runs the whole pipeline (create, stamp with the CAF, sign with the certificate). See Documents and Sign.

TypeScript
// Builds a normalized `Document` from caller input: validates type, folio and dates, normalizes
// RUTs with rut.ts, sanitizes text and enforces schema lengths (fails early instead of letting the
// SII reject the whole envelope), numbers lines, computes amounts and totals, applies receipt
// defaults (final consumer, `IndServicio=3`) and sets `MntBruto=1` when prices include VAT.
function createDocument(input: DocumentInput, options?: CreateDocumentOptions): Document
 
// `xs:maxLength` of the SII schema per element; `createDocument` enforces them on sanitized text.
const FIELD_LIMITS: {
  readonly RznSoc: 100
  readonly GiroEmis: 80
  readonly DirOrigen: 70
  readonly CmnaOrigen: 20
  readonly CiudadOrigen: 20
  readonly Sucursal: 20
  // ... 29 more members
}
 
// Renders the unsigned `<DTE>` XML: namespaces on the root (the digest inherits them), `ID` on the
// signed element, sections in schema order, the TED verbatim and a line break between sections.
function buildDocumentXml(doc: Document, options?: BuildDocumentXmlOptions): string
 
// Name of the signed element: `Liquidacion` for settlement invoices (43), `Documento` otherwise.
function documentElementName(type: DocumentType): "Documento" | "Liquidacion"
 
// Signs a stamped document with the issuer certificate (enveloped XMLDSig over
// `Documento`/`Liquidacion`). `TmstFirma` is the Chile time of `now`, or `signedAt` as given.
function signDocument(
  doc: StampedDocument,
  certificate: Certificate,
  options?: { readonly now?: Date; readonly signedAt?: string; },
): SignedDocument
 
// Verifies the signature of a `<DTE>` XML (own or received).
function verifyDocumentSignature(xml: string): SignatureVerification
 
// The whole pipeline: create (if needed) → stamp with the CAF → sign with the certificate.
function issueDocument(input: IssueDocumentInput): SignedDocument
TypeDescription
CreateDocumentOptionsOptions of createDocument.
BuildDocumentXmlOptionsOptions of buildDocumentXml.
SignedDocumentA stamped document that has been signed: carries the final XML.
IssueDocumentInputInput of issueDocument.

Fields of CreateDocumentOptions

FieldTypeDescription
now?DateClock for the default issue date (tests).

Fields of BuildDocumentXmlOptions

FieldTypeDescription
ted?TedTED to embed.
signedAt?stringTmstFirma value.

Fields of SignedDocument

FieldTypeDescription
idstringID attribute of the signed element: DTE_T{type}F{folio}.
headerHeader
itemsreadonly LineItem[]
subtotalsreadonly SubtotalInfo[]
globalAdjustmentsreadonly GlobalAdjustment[]
referencesreadonly Reference[]
receiptReferencesreadonly ReceiptReference[]References of a receipt (39, 41), which has its own shape; empty on every other type.
commissionsreadonly CommissionLine[]Commission lines (settlement invoices only).
tedTed
xmlstringSigned <DTE> XML (no prolog).
signedAtstringTmstFirma, Chile time.
signatureXmlSignatureDigest and signature values.

Fields of IssueDocumentInput

FieldTypeDescription
documentDocumentInput | DocumentRaw input or an already created document.
cafCafCAF covering the folio.
certificateCertificateIssuer certificate.
now?DateClock for dates and timestamps.
checkCafExpiry?booleanCheck CAF expiry (default true).
timestamp?stringTSTED and TmstFirma as given, instead of the Chile time of now.

XML#

Small XML helpers the rest of the SDK is built on: serializing, parsing, escaping and Base64 layout.

TypeScript
// Serializes a plain object to compact XML. Keys become elements in insertion order, `@_name` keys
// become attributes, arrays repeat the element and values are entity-escaped.
function buildXml(value: Readonly<Record<string, unknown>>): string
 
// Parses XML into a plain object (values as strings). Throws `XML_PARSE_FAILED` when not
// well-formed.
function parseXml(xml: string): ParsedXml
 
// Like `parseXml` but drops namespace prefixes (`SII:RESPUESTA` → `RESPUESTA`), handy for SOAP
// responses.
function parseXmlWithoutNamespaces(xml: string): ParsedXml
 
// Text of the first `<tag>…</tag>` occurrence, or `null`. Regex-based, for flat SII responses.
function extractTagContent(xml: string, tag: string): string | null
 
// Decodes the five XML entities (SOAP responses often embed escaped XML).
function decodeXmlEntities(xml: string): string
 
// Escapes a text node value with the five XML entities (`& < > " '`).
function escapeXmlText(value: string): string
 
// Escapes an attribute value quoted with double quotes.
function escapeXmlAttribute(value: string): string
 
// Removes whitespace from a base64 string and wraps it at `width` columns.
function wrapBase64(value: string, width?: number): string
 
// Rewraps `SignatureValue`, `Modulus` and `X509Certificate` at 64 columns, the layout the SII
// expects.
function formatBase64Columns(xml: string): string
TypeDescription
ParsedXmlResult of parsing XML into a plain object: elements become keys, repeated elements become arrays, attributes are @_name keys and every value stays a string. Defined as Readonly<Record<string, unknown>>.

Every DOM the SDK parses (received documents, signatures, CAFs, the SII's answers) refuses elements nested deeper than 100 levels with XML_PARSE_FAILED, before anything walks them. No document the SII or an issuer writes comes close; before 0.7.0 a file of a few thousand nested elements overflowed the stack with a RangeError.

Crypto#

The primitives behind the TED and the XMLDSig signature: SHA-1, RSA-SHA1 and X.509 parsing.

TypeScript
// Base64 SHA-1 of `data` encoded as `encoding` (default UTF-8). Used for XMLDSig `DigestValue`.
function sha1Base64(data: string, encoding?: TextEncoding): string
 
// SHA1withRSA (PKCS#1 v1.5) signature of `data`, base64. Deterministic: same key and bytes, same
// signature.
function rsaSha1SignBase64(privateKeyPem: string, data: string, encoding?: TextEncoding): string
 
// Verifies a SHA1withRSA base64 signature against a public key given as modulus/exponent. Never
// throws: malformed input is `false`.
function rsaSha1VerifyBase64(
  publicKey: RsaPublicKeyParts,
  data: string,
  encoding: TextEncoding,
  signatureBase64: string,
): boolean
 
// Public modulus and exponent of a PEM private key (PKCS#1 or PKCS#8).
function rsaPublicKeyParts(privateKeyPem: string): RsaPublicKeyParts
 
// Public modulus and exponent of a PEM certificate.
function rsaPublicKeyPartsFromCertificatePem(certificatePem: string): RsaPublicKeyParts
 
// Parses a PEM certificate into the fields dte-sdk needs.
function parseCertificatePem(certificatePem: string): ParsedCertificate
 
// Base64 body of a PEM certificate (no headers, no whitespace).
function certificateBase64(certificatePem: string): string
TypeDescription
TextEncodingHow a JS string is turned into bytes before hashing or signing. Defined as 'utf8' | 'latin1'.
RsaPublicKeyPartsRSA public key as the big-endian unsigned base64 integers XMLDSig RSAKeyValue and the CAF RSAPK use.
ParsedCertificateWhat dte-sdk reads from an X.509 certificate.

Certificates#

Load the digital certificate that signs documents, envelopes and the SII seed, from PKCS#12 (.pfx) or PEM. Passwords come from your own configuration (for example process.env.PFX_PASSWORD). See Sign.

TypeScript
// True when `now` is past `notAfter` minus `marginDays`.
function isCertificateExpired(
  certificate: Pick<Certificate, "notAfter">,
  options?: { readonly now?: Date; readonly marginDays?: number; },
): boolean
 
// Whole days until `notAfter` (negative once expired).
function daysUntilExpiry(
  certificate: Pick<Certificate, "notAfter">,
  options?: { readonly now?: Date; },
): number
 
// Builds a `Certificate` from PEM strings (e.g. after `openssl pkcs12 -nodes`). Verifies the key
// matches the certificate and that it is valid now: not expired (`CERT_EXPIRED`) and not before
// its `notBefore` (`CERT_NOT_YET_VALID`, `details.validFrom`). `allowExpired` loads both.
function loadCertificateFromPem(
  input: PemCertificateInput,
  options?: LoadCertificateOptions,
): Certificate
 
// Loads a PKCS#12 (`.pfx`/`.p12`) as a `Certificate`: legacy (3DES/RC2) and modern (PBES2/AES)
// files, shrouded or plain key bags, leaf detection by key, chain ordered leaf → root, RUT from
// the certificate. Like the PEM loader, it throws `CERT_EXPIRED` past `notAfter` and
// `CERT_NOT_YET_VALID` before `notBefore`; `allowExpired` loads both.
function loadCertificateFromPkcs12(
  bytes: Uint8Array,
  password: string,
  options?: LoadCertificateOptions,
): Certificate
TypeDescription
CertificateA signing certificate loaded from PKCS#12 or PEM: private key, leaf certificate, chain for mTLS and the identity fields the SII cares about.
LoadCertificateOptionsOptions shared by the certificate loaders.
PemCertificateInputPEM material for loadCertificateFromPem.

Fields of Certificate

FieldTypeDescription
privateKeyPemstringPrivate key PEM.
certificatePemstringLeaf certificate PEM (XML signing).
chainPemstringLeaf → intermediates → root PEM (TLS client auth); equals certificatePem when there is no chain.
certificateBase64stringLeaf DER in base64 (X509Certificate).
publicKeyRsaPublicKeyPartsPublic modulus/exponent (RSAKeyValue).
rutSiiRut | nullHolder RUT or null.
commonNamestring | nullCommon name.
subjectReadonly<Record<string, string>>Subject fields.
notBeforeDateValidity start.
notAfterDateValidity end.

Fields of LoadCertificateOptions

FieldTypeDescription
now?DateClock for the validity checks (tests).
allowExpired?booleanLoad a certificate outside its validity period instead of throwing CERT_EXPIRED (expired) or CERT_NOT_YET_VALID (notBefore still ahead).

Fields of PemCertificateInput

FieldTypeDescription
privateKeyPemstringPrivate key PEM (PKCS#1 RSA PRIVATE KEY or PKCS#8 PRIVATE KEY, unencrypted).
certificatePemstringLeaf certificate PEM.
chainPem?stringFull chain PEM for TLS; defaults to the leaf.

CAF#

The CAF (Código de Autorización de Folios): parse the file the SII gives you, check the folio range and the expiry, and sign with its private key. The CAF XML holds a private key: treat it as a secret. See Stamp.

TypeScript
// Parses a CAF XML file as downloaded from the SII. Validates structure, type, range and keys (the
// private key `RSASK` must be the pair of the public key `RSAPK` the SII signed), and that the text
// holds one `<CAF` and one `</CAF`, so the `<CAF>` block kept for the TED is the CAF its fields are
// read from. Numeric character references (`&#209;`, `&#xD1;`) in its fields decode as a DOM
// decodes them. Throws `CAF_INVALID`, also for keys that are not a pair, a DOCTYPE or another
// `<CAF` or `</CAF` anywhere in the text, such as in a comment.
function parseCaf(xml: string): Caf
 
// Expiry instant of a CAF: six months after `authorizationDate` (Res. Ex. SII 58/2017) for
// invoices and notes (33, 46, 56, 61), at midnight continental Chile (UTC-4). A day the sixth
// month does not have is its last day: a CAF authorized on 2026-08-31 expires on 2027-02-28, not
// in March. `null` for types that never expire or without a date.
function cafExpiresAt(caf: Pick<Caf, "documentType" | "authorizationDate">): Date | null
 
// True when the CAF has expired or expires within `marginMs` (default one day: the SII rejects
// every document stamped with an expired CAF with `CAF-3-517`, and the envelope may be received
// later than it was stamped).
function isCafExpired(
  caf: Pick<Caf, "documentType" | "authorizationDate">,
  options?: { readonly now?: Date; readonly marginMs?: number; },
): boolean
 
// True when `folio` is an integer inside the CAF range.
function isFolioInRange(caf: Pick<Caf, "range">, folio: number): boolean
 
// Throws `FOLIO_OUT_OF_RANGE` unless `folio` is inside the CAF range.
function assertFolioInRange(caf: Pick<Caf, "range" | "documentType">, folio: number): void
 
// Number of folios the CAF authorizes.
function availableFolios(caf: Pick<Caf, "range">): number
 
// SHA1withRSA signature (base64) of `data` with the CAF private key over its ISO-8859-1 bytes, the
// encoding the TED is transmitted and printed in.
function signWithCaf(caf: Pick<Caf, "privateKeyPem">, data: string): string
 
// Verifies a TED-style signature with the CAF public key (`RSAPK`).
function verifyWithCaf(caf: Pick<Caf, "publicKey">, data: string, signatureBase64: string): boolean
 
// The SII keys that sign the `DA` of every CAF, by `IDK`: 100 for the certification environment
// and 300 for production. Each is the 512-bit RSA key of a self-signed certificate of the SII whose
// serial number is the `IDK`, from CryptoSys and LibreDTE, the same bytes in both.
const SII_CAF_KEYS: SiiCafKeys
 
// The environment of the SII key a CAF names in its `IDK`: `certification` for 100, `production`
// for 300, null for another.
function cafEnvironment(keyId: number): Environment | null
 
// Verifies the SII signature of a CAF (`FRMA`, SHA1withRSA over the `DA`) with the SII key its
// `IDK` names. Takes a CAF file as the SII issues it or the `<CAF>` block a TED carries.
// `unchecked` when no key is known for that `IDK`; `invalid` for a CAF of the other environment
// than `environment` (production by default), whatever its signature, and for an empty `FRMA`,
// whatever its key. Throws `CAF_INVALID` when the text is not XML, holds a DOCTYPE, or has no
// single `CAF` with one `DA` and one `FRMA`.
function verifyCafSignature(cafXml: string, options?: CafSignatureOptions): VerificationStatus
TypeDescription
CafA parsed CAF (Código de Autorización de Folios): the SII authorization of a folio range plus the private key that signs each TED. Keep privateKeyPem secret.
SiiCafKeysSII public keys that verify the FRMA of a CAF, by the IDK the CAF names. Defined as Readonly<Record<number, RsaPublicKeyParts>>.
CafSignatureOptionsOptions of verifyCafSignature.
VerificationStatusOutcome of a check that may have to be skipped: unchecked when what it needs is missing, such as the SII key of a CAF. Defined as 'valid' | 'invalid' | 'unchecked'.

Fields of Caf

FieldTypeDescription
issuerRutSiiRutAuthorized issuer.
issuerNamestringIssuer business name.
documentTypeDocumentTypeDocument type the range is for.
range{ readonly from: number; readonly to: number }Inclusive folio range.
authorizationDatestring | nullAuthorization date YYYY-MM-DD, or null when absent.
publicKeyRsaPublicKeyPartsPublic key that verifies TED signatures.
keyIdnumberKey id; 100 marks the certification environment.
siiSignaturestringSII signature over the authorization data.
privateKeyPemstringPrivate key PEM used to sign the TED, the pair of publicKey.
xmlstringThe <CAF>…</CAF> block exactly as the SII issued it (whitespace between tags removed), copied verbatim into every TED.

Fields of CafSignatureOptions

FieldTypeDescription
environment?EnvironmentThe environment whose CAFs are accepted, production by default: a CAF of the other environment's SII key (100 in certification, 300 in production) is invalid.
siiKeys?SiiCafKeysThe SII keys by IDK, in place of SII_CAF_KEYS (spread it to add one).

TED#

The electronic stamp (timbre electrónico, TED) of a document, signed with the CAF key. See Stamp.

TypeScript
// Stamps a document with a CAF: checks type, issuer, folio range and expiry, builds the exact `DD`
// and signs it with the CAF key (SHA1withRSA over Latin-1 bytes).
function stampDocument(doc: Document, caf: Caf, options?: StampOptions): StampedDocument
 
// Verifies a `TED` XML against the CAF public key: true only when the `<DD>` bytes match the
// `FRMT` signature.
function verifyTed(tedXml: string, caf: Pick<Caf, "publicKey">): boolean
 
// The exact `<DD>…</DD>` string that gets signed and printed in the PDF417.
function buildDdString(fields: Omit<Ted, "signature" | "xml">): string
 
// Wraps a `DD` and its signature in the `TED` element.
function buildTedXml(dd: string, signature: string): string
 
// Folds text to ASCII and then cuts it to 40, the way `RSR` and `IT1` need it (folding may
// lengthen the text).
function tedText(text: string): string
TypeDescription
TedThe electronic stamp (TED): the DD fields, the CAF they embed and the signature made with the CAF key.
StampedDocumentA document with its TED.
StampOptionsOptions of stampDocument.

Fields of Ted

FieldTypeDescription
issuerRutSiiRutIssuer RUT.
documentTypeDocumentTypeDocument type.
folionumberFolio.
issueDatestringIssue date.
receiverRutstringReceiver RUT.
receiverNamestringReceiver name folded to ASCII, max 40.
totalAmountnumberDocument total.
firstItemNamestringFirst item name folded to ASCII, max 40.
cafstringExact <CAF>…</CAF> block.
stampedAtstringStamp timestamp, Chile time.
signaturestringSHA1withRSA signature of <DD>, base64.
xmlstringFull <TED version="1.0">…</TED> XML.

Fields of StampedDocument

FieldTypeDescription
idstringID attribute of the signed element: DTE_T{type}F{folio}.
headerHeader
itemsreadonly LineItem[]
subtotalsreadonly SubtotalInfo[]
globalAdjustmentsreadonly GlobalAdjustment[]
referencesreadonly Reference[]
receiptReferencesreadonly ReceiptReference[]References of a receipt (39, 41), which has its own shape; empty on every other type.
commissionsreadonly CommissionLine[]Commission lines (settlement invoices only).
tedTed

Fields of StampOptions

FieldTypeDescription
now?DateClock for TSTED and the expiry check.
checkExpiry?booleanCheck CAF expiry (default true).
stampedAt?stringTSTED as given, instead of the Chile time of now.

XMLDSig#

Enveloped XML signatures (C14N 1.0, RSA-SHA1), the kind the SII validates. See Sign.

TypeScript
// Builds `SignedInfo`. `referenceId` is the `ID` of the signed element, or `''` for a
// whole-document reference (`URI=""`).
function buildSignedInfo(
  referenceId: string,
  digestValue: string,
  options?: { readonly expandTags?: boolean; readonly includeXsi?: boolean; },
): string
 
// Builds the `Signature` element from a stored `SignedInfo`, the wrapped signature and the key
// material.
function buildSignatureXml(
  signedInfo: string,
  signatureValue: string,
  keyInfo: { readonly modulus: string; readonly exponent: string; readonly certificate: string; },
): string
 
// Signs `elementTag` with an enveloped XMLDSig signature (C14N 1.0, RSA-SHA1) and returns the XML
// with the `Signature` inserted right before `</rootTag>`.
function signEnveloped(
  input: SignEnvelopedInput,
): { readonly xml: string; readonly signature: XmlSignature; }
 
// Signs the whole root element with an enveloped XMLDSig signature (`Reference URI=""`,
// enveloped-signature transform, C14N 1.0, RSA-SHA1) and inserts `Signature` right before the
// closing root tag.
function signRootElement(
  input: SignRootElementInput,
): { readonly xml: string; readonly signature: XmlSignature; }
 
// Verifies the enveloped signature that is a direct child of `rootTag`: locates the signed element
// by the `ID` named in `Reference/@URI` (see `referencedElement`), recomputes its digest and
// checks `SignatureValue` with the `X509Certificate` carried in `KeyInfo`. Only the signature this
// computes passes: one `Reference`, holding the only `DigestValue`, with SHA-1 and no transform but
// enveloped-signature or C14N 1.0 (else `digestValid: false`), under C14N 1.0 and RSA-SHA1 (else
// `signatureValid: false`).
function verifyEnveloped(
  xml: string,
  target: { readonly elementTag: string; readonly rootTag: string; },
): SignatureVerification
TypeDescription
XmlSignatureThe two values that identify a signature.
SignEnvelopedInputInput of signEnveloped.
SignRootElementInputInput of signRootElement.
SignatureVerificationOutcome of verifying an enveloped signature.

Fields of XmlSignature

FieldTypeDescription
digestValuestringBase64 SHA-1 of the canonical signed element.
signatureValuestringBase64 RSA signature, single line.

Fields of SignEnvelopedInput

FieldTypeDescription
xmlstringUnsigned XML.
elementTagstringTag of the element with the ID to sign (Documento, SetDTE, EnvioLibro…).
rootTagstringRoot tag whose closing tag follows the signed element (DTE, EnvioDTE…).
certificatePick<Certificate, 'privateKeyPem' | 'publicKey' | 'certificateBase64'>Signing certificate.
includeXsiInStoredSignedInfo?booleanWrite xmlns:xsi in the stored SignedInfo (default true; false for the DTE).

Fields of SignRootElementInput

FieldTypeDescription
xmlstringUnsigned XML whose root element is signed as a whole (Reference URI="").
rootTagstringExpected root tag (getToken).
certificatePick<Certificate, 'privateKeyPem' | 'publicKey' | 'certificateBase64'>Signing certificate.

Fields of SignatureVerification

FieldTypeDescription
referenceIdstring | nullReference/@URI without #, or null when SignedInfo carries no reference, or more than one.
digestValidbooleanSignedInfo holds one Reference, with SHA-1, no transform but enveloped-signature or C14N 1.0, and the only DigestValue; the element it references is unique, sits next to Signature under the root, has the expected tag and still hashes to that DigestValue.
signatureValidbooleanSignedInfo declares C14N 1.0 and RSA-SHA1, and SignatureValue verifies with the embedded certificate.
validbooleanBoth checks passed.

Envelopes#

Envelopes for the SII: EnvioDTE and EnvioBOLETA. See Envelopes.

TypeScript
// Groups signed documents under a cover: validates the kind, normalizes RUTs and the resolution
// date, counts documents per type (`SubTotDTE`, with 33/61/56 first on `EnvioDTE`) and generates
// the set id.
function createEnvelope(input: CreateEnvelopeInput): Envelope
 
// `PREFIX_dd_mm_yyyy_hh_mm_ss_mmm` in Chile time.
function generateSetId(prefix: string, now?: Date): string
 
// Renders the unsigned envelope: ISO-8859-1 prolog, root with schema location, `SetDTE` with
// `Caratula` and the signed documents one per line (their namespaces stay: the digests depend on
// them).
function buildEnvelopeXml(envelope: Envelope): string
 
// Root element of an envelope kind.
function envelopeRootName(kind: Envelope["kind"]): "EnvioDTE" | "EnvioBOLETA"
 
// Signs the `SetDTE` with the sender certificate.
function signEnvelope(envelope: Envelope, certificate: Certificate): SignedEnvelope
 
// Verifies the `SetDTE` signature of an `EnvioDTE`/`EnvioBOLETA` XML.
function verifyEnvelopeSignature(xml: string): SignatureVerification
TypeDescription
EnvelopeCoverNormalized envelope cover.
EnvelopeCoverInputEnvelope cover as the caller provides it (Caratula).
EnvelopeSubtotalCount of documents per type inside an envelope (SubTotDTE).
EnvelopeAn envelope ready to render and sign.
EnvelopeKinddte → EnvioDTE (invoices, guides, notes…); receipt → EnvioBOLETA (39, 41). Defined as 'dte' | 'receipt'.
CreateEnvelopeInputInput of createEnvelope.
SignedEnvelopeAn envelope with its signed XML, ready to encode as ISO-8859-1 and upload.

Fields of EnvelopeCoverInput

FieldTypeDescription
issuerRutstringIssuer company RUT.
senderRutstringRUT of the certificate holder who signs the envelope.
receiverRut?stringReceiver RUT; defaults to the SII (always the SII on receipt envelopes).
resolutionDatestringSII resolution date (YYYY-MM-DD or DD-MM-YYYY).
resolutionNumbernumberResolution number (0 in certification).
signedAt?stringExplicit signing timestamp; defaults to now in Chile.
setId?stringExplicit SetDTE ID; generated when omitted.

Fields of Envelope

FieldTypeDescription
kindEnvelopeKind
setIdstringSetDTE/@ID.
coverEnvelopeCover
documentsreadonly SignedDocument[]

Fields of CreateEnvelopeInput

FieldTypeDescription
kindEnvelopeKind
documentsreadonly SignedDocument[]
coverEnvelopeCoverInput
now?DateClock for the set id and TmstFirmaEnv.

Fields of SignedEnvelope

FieldTypeDescription
kindEnvelopeKind
setIdstringSetDTE/@ID.
coverEnvelopeCover
documentsreadonly SignedDocument[]
xmlstringSigned XML with prolog.
signatureXmlSignature

Received documents#

Check what a supplier sent you: the envelope's own signature and, for each document, its XMLDSig signature, its stamp (TED), the CAF the stamp carries and the SII's signature over that CAF, with SII_CAF_KEYS (see CAF). A document that fails a check is a result, not an error. No clock and no network. See Sign.

TypeScript
// Verifies the documents of a `DTE`, `EnvioDTE` or `EnvioBOLETA` as received from a supplier, and
// the envelope's own signature. Each document is read from its element in the parsed input, never
// from a cut of the text: its signature is checked over forms written from that element, and its
// fields and stamp are read from it. It is checked for: its XMLDSig signature; its TED, whose
// `FRMT` must verify with the key of the CAF the TED carries and whose `DD` must agree with the
// header; that CAF against the document (the issuer, the type, the folio inside the range); and
// the SII's signature over the CAF (`FRMA`) with the SII key of its `IDK` (`SII_CAF_KEYS`, or
// `siiKeys`), for the CAFs of `environment` only (production by default).
function verifyReceivedDocuments(
  xml: string,
  options?: VerifyReceivedDocumentsOptions,
): ReceivedDocumentsVerification

It throws XML_PARSE_FAILED for empty or malformed XML, a DOCTYPE, another root, an envelope without exactly one SetDTE, a DTE out of place or prefixed, a DTE without one unprefixed Documento or Liquidacion, or elements nested deeper than 100 levels, and ENVELOPE_EMPTY for an envelope without documents. A CAF whose IDK has no known key leaves the document unchecked. A CAF with an empty FRMA is found and fails its SII signature, and the stamp is checked with the CAF's key like any other. Not checked: who owns the signing certificate, and whether the CAF had expired.

TypeDescription
VerifyReceivedDocumentsOptionsOptions of verifyReceivedDocuments.
ReceivedDocumentsVerificationResult of verifyReceivedDocuments.
ReceivedDocumentOne received document with its checks. The header fields are null when absent, and the numbers when they are not whole numbers.
ReceivedSignatureCheckAn XMLDSig signature, checked: a SignatureVerification plus found. valid proves the signed element is intact with respect to the certificate in KeyInfo; whether that certificate is the issuer's is not checked.
ReceivedTedCheckThe electronic stamp, checked.
ReceivedCafCheckThe CAF the TED carries, checked against the document and against the SII's signature.
TedMismatchA field of the TED's DD compared with the document's header. Defined as 'issuerRut' | 'documentType' | 'folio' | 'issueDate' | 'receiverRut' | 'totalAmount'.
CafMismatchWhat the CAF must match: issuerRut (RE against RUTEmisor), documentType (TD against TipoDTE), folio (Folio inside RNG) and environment (the environment of the SII key its IDK names against the environment option). Defined as 'issuerRut' | 'documentType' | 'folio' | 'environment'.

Fields of VerifyReceivedDocumentsOptions

FieldTypeDescription
environment?EnvironmentThe environment whose CAFs are accepted, production by default: a CAF signed with the other environment's SII key (100 in certification, 300 in production) is invalid, with the mismatch environment.
siiKeys?SiiCafKeysThe SII keys that verify each CAF's FRMA, by IDK, in place of SII_CAF_KEYS (spread it to add one).

Fields of ReceivedDocumentsVerification

FieldTypeDescription
root'DTE' | 'EnvioDTE' | 'EnvioBOLETA'Root of the input: one document or an envelope.
envelopeReceivedSignatureCheck | nullThe envelope's own signature over SetDTE; null for a single DTE.
documentsreadonly ReceivedDocument[]Every document, in the order of the input.
statusVerificationStatusThe worst of the envelope and the documents.

Fields of ReceivedDocument

FieldTypeDescription
xmlstringThe <DTE> written from its element: the elements, attributes, own namespace declarations, text, comments and instructions of the input, which read back and verify the same, but not the input byte for byte (a CDATA section becomes escaped text, a character reference the character, an empty element <X/>); the namespaces it inherits from the envelope are not added. To archive a received document, keep the input's own bytes.
idstring | nullID of the signed element.
typenumber | nullDocument type, any SII code.
folionumber | nullFolio.
issueDatestring | nullIssue date as written.
issuerRutstring | nullIssuer RUT as written.
receiverRutstring | nullReceiver RUT as written.
totalAmountnumber | nullTotal amount.
signatureReceivedSignatureCheckThe document's XMLDSig signature over its signed element.
tedReceivedTedCheckThe electronic stamp.
cafReceivedCafCheckThe CAF the stamp carries.
statusVerificationStatusinvalid when a check fails; unchecked when none fails but the CAF's FRMA could not be checked; valid otherwise.

Fields of ReceivedSignatureCheck

FieldTypeDescription
foundbooleanA Signature with a SignedInfo sits under the root; when false every other field is false or null.
referenceIdstring | nullAs in SignatureVerification.
digestValidbooleanAs in SignatureVerification.
signatureValidbooleanAs in SignatureVerification.
validbooleanBoth checks passed.

Fields of ReceivedTedCheck

FieldTypeDescription
foundbooleanOne TED in the document, by local name, sits in the signed element, is plain (no prefix, no namespace declaration, no comment, CDATA or instruction) and holds exactly a DD and then an FRMT, with no other DD or FRMT inside.
signatureValidbooleanFRMT verifies with the RSAPK of the CAF the TED carries, over the DD written from its element as ISO-8859-1 bytes: flattened, its texts escaped the SII's way or with only &, < and > escaped.
mismatchesreadonly TedMismatch[]The DD fields that differ from the header, or that one of the two lacks. RSR and IT1 are free text each issuer folds and cuts its own way, and are not compared.
validbooleanFound, its signature verifies and nothing differs.

Fields of ReceivedCafCheck

FieldTypeDescription
foundbooleanThe stamp was found and its DD holds one CAF, DA and FRMA by local name, the CAF a direct child of the DD with the other two as its direct children, and the DA has RE, TD, RNG, RSAPK and IDK; when false every other field is null or empty and the status is invalid.
keyIdnumber | nullId of the SII key that signed it; 100 marks certification and 300 production.
environmentEnvironment | nullThe environment of that SII key: certification for 100, production for 300, null for another.
issuerRutstring | nullThe issuer the CAF authorizes, as written.
documentTypenumber | nullThe type the CAF authorizes.
range{ readonly from: number; readonly to: number } | nullThe folios the CAF authorizes, inclusive.
authorizationDatestring | nullAuthorization date as written, YYYY-MM-DD in the SII's CAFs.
mismatchesreadonly CafMismatch[]What the CAF does not cover of the document: another issuer, another type, a folio outside its range, or a CAF of the other environment than the environment option.
siiSignatureVerificationStatusThe SII's signature over DA (FRMA): unchecked when no SII key is known for keyId.
statusVerificationStatusinvalid when not found, a mismatch or an FRMA that fails; unchecked when only the FRMA could not be checked.

Books#

The SII books: the purchase and sales book (IECV, LibroCompraVenta), the guide book (LibroGuia) and the folio consumption report (RCOF, ConsumoFolios). Each has a create*, build*Xml, sign* and verify*Signature function. See Books.

Catalogs#

TypeScript
// Side of the purchase and sales book, with its SII value.
const BOOK_OPERATIONS: { readonly sale: "VENTA"; readonly purchase: "COMPRA" }
 
// Kind of purchase and sales book, with its SII value.
const BOOK_KINDS: {
  readonly monthly: "MENSUAL"
  readonly special: "ESPECIAL"
  readonly rectification: "RECTIFICA"
}
 
// How a book reaches the SII: in one go, in segments, the closing of the segments, or a later
// adjustment.
const BOOK_SUBMISSIONS: {
  readonly total: "TOTAL"
  readonly partial: "PARCIAL"
  readonly final: "FINAL"
  readonly adjustment: "AJUSTE"
}
 
// Document types the book schema admits (`DoctoType` of `LibroCV_v10.xsd`), electronic or not.
const BOOK_DOCUMENT_TYPES: readonly [
  29, 30, 32, 33, 34, 35, 38, 39, 40, 41, 43, 45, 46, 48, 53, 55, 56, 60, 61, 101, 102, 103, 104,
  105, 106, 108, 109, 110, 111, 112, 175, 180, 185, 500, 501, 900, 901, 902, 903, 904, 905, 906,
  907, 909, 910, 911, 914, 918, 919, 920, 921, 922, 924
]
 
// Type guard for `BookDocumentType`.
function isBookDocumentType(value: unknown): value is BookDocumentType
 
// Types the format excludes from the detail: report them in `summaryOnlyTotals` (receipts,
// exchange rate adjustments, tickets without invoice, other unregistered records).
const SUMMARY_ONLY_DOCUMENT_TYPES: readonly [35, 38, 39, 41, 48, 105, 500, 501, 919, 920, 922, 924]
 
// Why VAT on a purchase cannot be recovered.
const NON_RECOVERABLE_VAT_CODES: {
  readonly nonTaxableOperations: 1
  readonly lateRegistration: 2
  readonly rejectedExpenses: 3
  readonly freeDeliveries: 4
  readonly other: 9
}
 
// Operation of a guide line in the guide book. `TpoOper` stops at 7 in the schema, so values 8 and
// 9 of `IndTraslado` cannot be reported on a line.
const GUIDE_TRANSFER_TYPES: {
  readonly sale: 1
  readonly pendingSale: 2
  readonly consignment: 3
  readonly demonstration: 4
  readonly internalTransfer: 5
  readonly otherTransfer: 6
  readonly returnGuide: 7
}
 
// Why a guide line is marked: voided before reaching the SII, voided afterwards, or goods partly
// received.
const GUIDE_VOID_CODES: { readonly folio: 1; readonly guide: 2; readonly partialReceipt: 3 }
TypeDescription
BookOperationUnion of the book sides. Defined as keyof typeof BOOK_OPERATIONS.
BookKindUnion of the book kinds. Defined as keyof typeof BOOK_KINDS.
BookSubmissionUnion of the submission kinds. Defined as keyof typeof BOOK_SUBMISSIONS.
BookAdjustmentWhat an adjustment does with a line: add is Operacion 1, remove is Operacion 2. Defined as 'add' | 'remove'.
BookDocumentTypeUnion of the book document types. Defined as (typeof BOOK_DOCUMENT_TYPES)[number].
NonRecoverableVatCodeUnion of the non-recoverable VAT codes.
GuideTransferTypeUnion of the guide operations.
GuideVoidCodeUnion of the guide void reasons. Defined as keyof typeof GUIDE_VOID_CODES.

Model types#

TypeDescription
BookCoverInputCover fields common to the purchase and sales book and the guide book, as the caller provides them.
BookCoverNormalized cover fields common to the purchase and sales book and the guide book.
PurchaseSalesCoverInputCover of a purchase and sales book, as the caller provides it.
PurchaseSalesCoverNormalized cover of a purchase and sales book.
BookNonRecoverableVatNon-recoverable VAT of a line.
BookOtherTaxAdditional tax, retention or surcharge of a line.
BookForeignReceiverForeign receiver of an export document.
BookSettlementInputCommissions and other charges of a settlement invoice (40, 43, 103), as the caller provides them.
BookTaxKindTax kind of a line: vat is TpoImp 1, freeZone (Law 18.211) is 2. Defined as 'vat' | 'freeZone'.
BookEntryInputOne line of the purchase and sales book, as the caller provides it.
BookEntryA normalized line of the purchase and sales book. A voided line has only type, folio, voided and adjustment.
BookTotalMismatchAn explicit line total that differs from the SII formula. Reported, not thrown, unless strictTotals is set.
BookNonRecoverableVatTotalNon-recoverable VAT of a document type in a summary.
BookOtherTaxTotalAdditional tax of a document type in a summary.
BookSettlementTotalsSettlement commissions of a document type in a summary.
BookTotalsTotals of one document type in a summary. A plain JSON value: persist book.periodTotals and pass it back as previousTotals.
BookTotalsInputTotals of a document type as the caller provides them: anything absent counts as 0.
PurchaseSalesBookInputInput of createPurchaseSalesBook.
PurchaseSalesBookA normalized purchase and sales book, ready to render and sign.
GuideBookCoverInputCover of a guide book, as the caller provides it. The schema only admits TipoLibro ESPECIAL and requires the notification folio.
GuideBookCoverNormalized cover of a guide book.
GuideEntryInputOne line of the guide book, as the caller provides it.
GuideEntryA normalized line of the guide book.
GuideTransferTotalNon-sale guides of one operation in a summary.
GuideTotalsSummary of a guide book. A plain JSON value: persist book.periodTotals and pass it back as previousTotals.
GuideBookInputInput of createGuideBook.
GuideBookA normalized guide book, ready to render and sign.
FolioConsumptionCoverInputCover of a folio consumption report, as the caller provides it.
FolioConsumptionCoverNormalized cover of a folio consumption report.
FolioConsumptionTypeDocument types of the report: 39 and 41, per the 2020 format. Defined as 39 | 41.
FolioConsumptionEntryOne receipt issued.
VoidedFolioA folio voided in the system before reaching the SII, not one voided through a credit note.
FolioRangeA range of consecutive folios; a single folio has from equal to to.
FolioConsumptionSummarySummary of one document type in the report.
FolioConsumptionInputInput of createFolioConsumption.
FolioConsumptionA normalized folio consumption report, ready to render and sign. Used today in the receipts certification; the SII probably no longer requires it in production.

SII tags#

TypeDescription
SiiCaratulaLibroCover of a purchase and sales book.
SiiTotIVANoRecNon-recoverable VAT in a summary row.
SiiTotOtrosImpAdditional tax in a summary row. FctImpAdic and TotCredImp exist only in TotalesPeriodo.
SiiTotLiquidacionesSettlement commissions in a summary row.
SiiTotalesSegmentoSummary row of a segment, in schema order. Values may be negative.
SiiTotalesPeriodoSummary row of a period. Adds to the segment row the proportionality factor, the credit and the vehicle tax.
SiiDetalleLibroOne line of the purchase and sales book, in schema order.
SiiEnvioLibroThe signed part of a purchase and sales book, in schema order.
SiiCaratulaLibroGuiaCover of a guide book.
SiiResumenLibroGuiaSummary of a guide book, in schema order.
SiiDetalleLibroGuiaOne line of the guide book, in schema order.
SiiEnvioLibroGuiaThe signed part of a guide book, in schema order.
SiiCaratulaConsumoFoliosCover of a folio consumption report. The version attribute travels as @_version when it is serialized.
SiiResumenConsumoFoliosSummary of one document type of the report, in schema order.
SiiDocumentoConsumoFoliosThe signed part of a folio consumption report, in schema order.

Codec and accumulation#

TypeScript
// The `EnvioLibro` of a purchase and sales book with the official tags, in schema order.
function toSiiPurchaseSalesBook(book: PurchaseSalesBook): SiiEnvioLibro
 
// The `EnvioLibro` of a guide book with the official tags, in schema order.
function toSiiGuideBook(book: GuideBook): SiiEnvioLibroGuia
 
// The `DocumentoConsumoFolios` of a report with the official tags, in schema order.
function toSiiFolioConsumption(report: FolioConsumption): SiiDocumentoConsumoFolios
 
// Adds summaries by document type, and inside each type adds non-recoverable VAT and other taxes
// by code. Rows keep the order of their first appearance, and a row present on one side only is
// kept.
function accumulateBookTotals(
  base: readonly BookTotals[],
  delta: readonly BookTotals[],
): readonly BookTotals[]

Purchase and sales book#

TypeScript
// Builds a purchase and sales book (IECV): validates the cover and the zones of its submission,
// normalizes the lines and computes the summaries.
function createPurchaseSalesBook(input: PurchaseSalesBookInput): PurchaseSalesBook
 
// Renders the unsigned `LibroCompraVenta` XML.
function buildPurchaseSalesBookXml(book: PurchaseSalesBook): string
 
// Signs the `EnvioLibro` with the sender certificate (enveloped XMLDSig, `URI="#ID"`).
function signPurchaseSalesBook(
  book: PurchaseSalesBook,
  certificate: Certificate,
): SignedPurchaseSalesBook
 
// Verifies the signature of a `LibroCompraVenta` XML.
function verifyPurchaseSalesBookSignature(xml: string): SignatureVerification
TypeDescription
SignedPurchaseSalesBookA purchase and sales book with its signed XML, ready for uploadBook.

Guide book#

TypeScript
// Builds a guide book: validates the cover and the zones of its submission, normalizes the lines
// and computes the summaries. `TasaImp` and `IVA` are always emitted, 0 when absent.
function createGuideBook(input: GuideBookInput): GuideBook
 
// Renders the unsigned `LibroGuia` XML.
function buildGuideBookXml(book: GuideBook): string
 
// Signs the `EnvioLibro` with the sender certificate (enveloped XMLDSig, `URI="#ID"`).
function signGuideBook(book: GuideBook, certificate: Certificate): SignedGuideBook
 
// Verifies the signature of a `LibroGuia` XML.
function verifyGuideBookSignature(xml: string): SignatureVerification
 
// Adds two guide book summaries, the transfers by operation. Use it to carry the period totals of
// earlier submissions forward.
function accumulateGuideTotals(base: GuideTotals, delta: GuideTotals): GuideTotals
TypeDescription
SignedGuideBookA guide book with its signed XML, ready for uploadBook.

Folio consumption#

TypeScript
// Builds a folio consumption report (RCOF, now Resumen de Ventas Diarias): one summary per receipt
// type present, 39 first, or one of type 39 in zeros for a day without sales.
function createFolioConsumption(input: FolioConsumptionInput): FolioConsumption
 
// Renders the unsigned `ConsumoFolios` XML.
function buildFolioConsumptionXml(report: FolioConsumption): string
 
// Signs the `DocumentoConsumoFolios` with the sender certificate (enveloped XMLDSig, `URI="#ID"`).
function signFolioConsumption(
  report: FolioConsumption,
  certificate: Certificate,
): SignedFolioConsumption
 
// Verifies the signature of a `ConsumoFolios` XML.
function verifyFolioConsumptionSignature(xml: string): SignatureVerification
 
// Sorts folios and groups the consecutive ones into ranges; a lone folio has `from` equal to `to`.
function compactFolioRanges(folios: readonly number[]): readonly FolioRange[]
TypeDescription
SignedFolioConsumptionA folio consumption report with its signed XML, ready for uploadFolioConsumption.

Entries from documents#

TypeScript
// Derives a book line from a document. The counterparty is the receiver when the book owner issued
// the document and the issuer otherwise, which covers sales, purchases received and purchase
// invoices (46) on either side.
function bookEntryFromDocument(
  document: Document,
  options: BookEntryFromDocumentOptions,
): BookEntryInput
 
// Derives a guide book line from a dispatch guide (52). The transfer defaults to a sale, and the
// receiver and the amounts travel only on sales; a non-sale guide reports its total alone.
function guideEntryFromDocument(document: Document): GuideEntryInput
 
// Derives a folio consumption line from a receipt (39 or 41).
function folioConsumptionEntryFromDocument(document: Document): FolioConsumptionEntry
TypeDescription
BookEntryFromDocumentOptionsOptions of bookEntryFromDocument.

Fields of BookEntryFromDocumentOptions

FieldTypeDescription
bookRutstringRUT of the book owner: decides who the counterparty is.
operationBookOperationBook side.
creditNoteSign?'positive' | 'negative'negative negates exempt, net, VAT and total of a credit note (61). positive by default, as the format has it.

SII web services client#

createSiiClient returns a frozen data object; every operation is a free function that takes it as its first argument. The last argument of each operation is an optional CallOverrides (signal, timeoutMs, retry). The transport, token cache, logger, capture and archive are ports you can replace. See SII web services.

Hosts and endpoints#

TypeScript
// Base hosts of the DTE web services per environment.
const SII_HOSTS: Readonly<Record<Environment, string>> = {
  certification: 'maullin.sii.cl',
  production: 'palena.sii.cl',
}
 
// SOAP / CGI endpoints per environment (seed, token, upload, status).
const SOAP_ENDPOINTS: Readonly<Record<Environment, SoapEndpoints>>
 
// REST endpoints of the receipts API per environment.
const REST_ENDPOINTS: Readonly<Record<Environment, RestEndpoints>>
 
// Service URLs of the acceptance/claim registry web service (WSRECLAMO v1.2); SOAP calls are
// POSTed here.
const CLAIM_WS_ENDPOINTS: Readonly<Record<Environment, string>>
 
// WSDL of the acceptance/claim registry web service.
const CLAIM_WSDL_ENDPOINTS: Readonly<Record<Environment, string>>
 
// User-Agent the SII upload CGI expects (it rejects modern browser strings).
const UPLOAD_USER_AGENT = 'Mozilla/4.0 ( compatible; PROG 1.0; Windows NT)'
TypeDescription
SoapEndpointsSOAP / CGI endpoints of one environment.
RestEndpointsREST endpoints of the receipts API for one environment.

Logger#

TypeScript
// Default logger: discards everything.
const silentLogger: Logger
TypeDescription
LoggerLogger port. dte-sdk logs operation names, attempts, HTTP statuses, SII codes and durations; never tokens, XML or RUTs in the message.
LogFnOne log level. Defined as (message: string, context?: LogContext) => void.
LogContextStructured context attached to a log line. May carry RUTs or codes; the message itself never does. Defined as Readonly<Record<string, unknown>>.

Fields of Logger

FieldTypeDescription
debugLogFnPer-exchange detail.
infoLogFnOperation milestones.
warnLogFnRecoverable problems (a failed capture, a retry).
errorLogFnFailures surfaced to the caller.

Token cache#

TypeScript
// Cache key `${environment}:${channel}:${fingerprint}`: two companies, two environments or two
// channels never share a token.
function tokenCacheKey(
  environment: Environment,
  channel: TokenChannel,
  certificate: Pick<Certificate, "certificateBase64">,
): string
 
// In-memory token cache (per process).
function createMemoryTokenCache(): TokenCache
TypeDescription
TokenChannelAuthentication channel: soap (DTEWS seed/token: DTEUpload, QueryEst*, WSRECLAMO) or rest (receipts API). Defined as 'soap' | 'rest'.
CachedTokenA cached token with its expiry instant (epoch milliseconds).
TokenCacheToken cache port. createDirectoryTokenCache from dte-sdk/node keeps tokens on disk; implement it over Redis to share them between machines.

Fields of CachedToken

FieldTypeDescription
tokenstringThe SII token.
expiresAtnumberExpiry, epoch ms.

Fields of TokenCache

FieldTypeDescription
get(key: string) => Promise<CachedToken | null>Cached entry or null.
set(key: string, value: CachedToken) => Promise<void>Stores an entry.
delete(key: string) => Promise<void>Removes an entry.

Retry#

TypeScript
// Defaults measured against the SII: 6 attempts, 2 s growing ×1.8, capped at 15 s, ±20 % jitter.
const DEFAULT_RETRY_POLICY: RetryPolicy = {
  maxAttempts: 6,
  initialDelayMs: 2000,
  maxDelayMs: 15000,
  backoffMultiplier: 1.8,
  jitterRatio: 0.2,
}
 
// True for errors worth retrying: transport failures, timeouts, unreadable SII pages, `QueryEst*`
// query errors, HTTP 429/405/5xx and the "system blocked" upload status.
function isRetryableError(error: unknown): boolean
TypeDescription
RetryPolicyRetry policy: exponential backoff with jitter.
RetryOptionsRuntime hooks of withRetry: the injectable sleep, the caller's signal, the jitter random, a per-call retryOn and an onRetry observer.

Fields of RetryPolicy

FieldTypeDescription
maxAttemptsnumberTotal attempts including the first (1 = no retry).
initialDelayMsnumberDelay before the second attempt, ms.
maxDelayMsnumberCap for any delay, ms.
backoffMultipliernumberGrowth factor between attempts.
jitterRationumberJitter as a fraction of the delay (0.2 → ±20 %).
retryOn?(error: DteError) => booleanWhich errors to retry; defaults to isRetryableError.

Fields of RetryOptions

FieldTypeDescription
sleep(ms: number, signal?: AbortSignal) => Promise<void>Wait between attempts.
signal?AbortSignalCaller cancellation, handed to sleep.
random?() => numberJitter source, 0 to 1; Math.random by default.
retryOn?(error: DteError) => booleanNarrows which errors are retried; the policy must accept them too.
onRetry?(error: DteError, attempt: number, delayMs: number) => voidObserver called before each wait.

Transport#

TypeScript
// Default transport over `globalThis.fetch` (Node ≥ 20, Deno, Bun) or an injected `fetch`.
// Redirects are not followed: the SII never redirects a well-formed call and following one would
// hide an error page.
function createFetchTransport(options?: { readonly fetch?: FetchLike; }): HttpTransport
TypeDescription
HttpMethodHTTP methods the SII services use. Defined as 'GET' | 'POST'.
HttpRequestOne HTTP request as the client hands it to the transport: bytes, never text.
HttpResponseOne HTTP response: status, lower-cased header names and body bytes. Any status is a response; only network, TLS, timeout and abort failures are thrown.
HttpTransportTransport port: fetch by default (createFetchTransport), Node https as an adapter (createNodeHttpsTransport), or anything the consumer injects (tests use a route-based fake). Defined as (request: HttpRequest) => Promise<HttpResponse>.
BodyEncodingCharset of a body: latin1 for DTEWS SOAP and the DTEUpload CGI, utf8 for the REST API and WSRECLAMO. Defined as 'latin1' | 'utf8'.
FetchLikeThe slice of fetch the transport uses, so consumers and tests can inject their own.

Fields of HttpRequest

FieldTypeDescription
methodHttpMethodHTTP method.
urlstringAbsolute URL.
headersReadonly<Record<string, string>>Header names as the SII expects them (User-Agent, Cookie…).
body?Uint8ArrayBody bytes (POST only).
timeoutMsnumberPer-request timeout, ms.
signal?AbortSignalCaller cancellation.

Fields of HttpResponse

FieldTypeDescription
statusnumberHTTP status; 4xx and 5xx are returned, not thrown.
headersReadonly<Record<string, string>>Lower-cased names; repeated headers joined with , .
bodyUint8ArrayBody bytes; the caller decodes them.

HTTP capture#

TypeScript
// Pure redaction of a whole exchange (URL, headers, bodies and the error reason); the client
// applies it before calling the port, and adapters may reuse it.
function redactExchange(exchange: HttpExchange): HttpExchange
 
// In-memory capture: `exchanges()` returns a copy of everything captured so far.
function createMemoryCapture(): { readonly capture: HttpCapture; readonly exchanges: () => readonly HttpExchange[]; }
TypeDescription
HttpChannelChannel of a captured exchange: the two token channels of the web services, or the certificate portal. Defined as TokenChannel | 'portal'.
HttpExchangeOne HTTP attempt as handed to the capture port, already redacted.
HttpExchangeRequestThe request half of a captured exchange, bodies already decoded to text.
HttpExchangeResponseThe response half of a captured exchange.
HttpExchangeErrorWhy an exchange produced no response.
HttpCaptureCapture port: receives every attempt. Failures inside it are logged and never fail the operation. Defined as (exchange: HttpExchange) => Promise<void>.

Fields of HttpExchange

FieldTypeDescription
operationstringOperation name (getSeed, uploadEnvelope, registerClaim…).
channelHttpChannelChannel of the call.
attemptnumberAttempt number within the retry loop (1-based).
requestHttpExchangeRequestThe request as sent, redacted.
responseHttpExchangeResponse | nullThe response, or null when none arrived.
errorHttpExchangeError | nullThe failure, or null when a response arrived.
startedAtstringISO 8601 UTC.
durationMsnumberDuration of the attempt, ms.

Upload archive#

TypeScript
// In-memory archive: `records()` returns a copy of everything archived so far.
function createMemoryUploadArchive(): { readonly archive: UploadArchive; readonly records: () => readonly UploadRecord[]; }
TypeDescription
UploadKindWhat was uploaded: EnvioDTE, EnvioBOLETA, a book (IECV / guides) or the folio consumption report (RCOF). Defined as 'dte' | 'receipt' | 'book' | 'folioConsumption'.
UploadRecordOne upload that got an SII answer, as handed to the archive port.
UploadArchiveArchive port. Defined as (record: UploadRecord) => Promise<void>.

Fields of UploadRecord

FieldTypeDescription
environmentEnvironmentEnvironment the upload went to.
kindUploadKindWhat was uploaded.
channelTokenChannelChannel used for the upload.
trackIdstring | nullTrackID, or null when the SII rejected the upload.
duplicatebooleanThe SII reported the file as already uploaded.
companyRutSiiRutCompany RUT.
senderRutSiiRutSender RUT.
fileNamestringMultipart file name.
sentAtstringISO 8601 UTC instant of the send.
xmlUint8ArrayThe exact bytes sent.
response{ readonly httpStatus: number; readonly code: string; readonly raw: string }HTTP status, SII code and body of the answer, with tokens and seeds redacted (redactText).

Client#

TypeScript
// Validates and completes the options into a frozen `SiiClient`. RUTs go through rut.ts; numbers
// must be positive; the default transport is `fetch`, the default cache is in memory, the default
// logger is silent.
function createSiiClient(options: SiiClientOptions): SiiClient
TypeDescription
SiiClientA configured SII client: frozen data, no methods, no hidden state. Pass it as the first argument of every operation (uploadEnvelope(sii, …)).
SiiClientOptionsOptions of createSiiClient.
SiiTimeoutsTimeouts per channel, ms.
SiiEndpointsResolved endpoints of a client.
CallOverridesPer-call overrides accepted by every operation.
SleepFnInjectable wait used between retries and status polls. Defined as (ms: number, signal?: AbortSignal) => Promise<void>.

Fields of SiiClientOptions

FieldTypeDescription
environmentEnvironmentTarget environment.
certificateCertificateCertificate that signs the seed; its holder is the default sender.
companyRut?stringCompany RUT used by every operation unless overridden per call.
senderRut?stringSender RUT; defaults to the certificate holder.
transport?HttpTransportHTTP transport; createFetchTransport() by default.
tokenCache?TokenCacheToken cache; memory by default. createDirectoryTokenCache from dte-sdk/node keeps tokens on disk.
tokenTtlMs?numberToken lifetime in the cache; 55 min by default.
retry?Partial<RetryPolicy> | falseRetry policy overrides, or false to disable retries.
timeouts?Partial<SiiTimeouts>Timeout overrides per channel.
receiptsChannel?TokenChannelChannel for EnvioBOLETA; rest in production, soap (DTEUpload) in certification.
logger?LoggerLogger; silent by default.
capture?HttpCaptureHTTP capture port; off by default.
archive?UploadArchiveUpload archive port; off by default.
endpoints?Partial<SiiEndpoints>Endpoint overrides (tests, proxies).
now?() => DateClock.
sleep?SleepFnWait function.

Fields of SiiTimeouts

FieldTypeDescription
soapnumberDTEWS SOAP and WSRECLAMO calls (30 000).
restnumberReceipts REST API calls (15 000).
uploadnumberUploads on either channel (60 000).

Fields of SiiEndpoints

FieldTypeDescription
soapSoapEndpointsDTEWS SOAP and DTEUpload URLs.
restRestEndpointsReceipts REST API URLs.
claimsstringWSRECLAMO service URL.

Fields of CallOverrides

FieldTypeDescription
signal?AbortSignalCancellation.
timeoutMs?numberTimeout for this call, ms.
retry?Partial<RetryPolicy> | falseRetry policy for this call, or false.

SOAP and multipart#

TypeScript
// Builds a SOAP 1.1 envelope (UTF-8 text) with one rpc operation and its parameters as unqualified
// children.
function buildSoapEnvelope(input: SoapEnvelopeInput): string
 
// Parses a SOAP reply without a full XML parse: the SII answers are flat and sometimes carry stray
// entities.
function parseSoapResponse(xml: string): SoapResponse
 
// `multipart/form-data` bytes: the fields in order, then the file part, as the SII's upload CGI
// expects them.
function buildMultipartBody(input: MultipartBodyInput): Uint8Array
TypeDescription
SoapParamOne rpc parameter, in the order the WSDL declares them (Axis matches by position).
SoapEnvelopeInputInput of buildSoapEnvelope.
SoapFaultA SOAP 1.1 fault.
SoapResponseWhat a SOAP reply carried: a fault, the unescaped XML inside <…Return> (DTEWS) or the inner XML of <return> (WSRECLAMO), prefixes stripped.
MultipartFieldA plain multipart field (rutSender, dvSender, rutCompany, dvCompany).
MultipartFileThe file part (archivo): bytes already encoded in the charset the XML declares.
MultipartBodyInputInput of buildMultipartBody.

Fields of SoapEnvelopeInput

FieldTypeDescription
methodstringOperation name (getSeed, getEstUp, ingresarAceptacionReclamoDoc…).
params?readonly SoapParam[]Parameters; text is escaped with &, < and > only: quotes and apostrophes travel as they are.
namespace?stringOperation namespace (WSRECLAMO, prefix ws); omitted for DTEWS, which accepts unqualified operations.

Fields of MultipartFile

FieldTypeDescription
namestringPart name.
fileNamestringFile name sent in the part.
contentTypestringContent type of the part.
bytesUint8ArrayFile bytes, copied untouched.

Fields of MultipartBodyInput

FieldTypeDescription
boundarystringBoundary; must not occur in any field or in the file.
fieldsreadonly MultipartField[]Text fields, in order.
fileMultipartFileThe file part, sent last.

Authentication#

TypeScript
// Asks the SII for a seed on the given channel (SOAP `CrSeed` or REST
// `boleta.electronica.semilla`). The seed is a 12-digit string valid for two minutes; it is never
// cached.
function getSeed(sii: SiiClient, channel: TokenChannel, overrides?: CallOverrides): Promise<string>
 
// Signs a seed for `GetTokenFromSeed` / the REST token endpoint: XML declaration, one newline,
// then `<getToken><item><Semilla>…</Semilla></item><Signature…/></getToken>` with no trailing
// newline (the REST endpoint is byte-strict about this layout).
function signSeed(
  seed: string,
  certificate: Pick<Certificate, "privateKeyPem" | "publicKey" | "certificateBase64">,
): string
 
// Returns a valid token for the channel: the cached one while it has not expired, otherwise seed →
// signed seed → token, stored in the cache for `tokenTtlMs`. The DTEWS token and the REST token
// are different things.
function getToken(sii: SiiClient, channel: TokenChannel, overrides?: CallOverrides): Promise<string>
 
// Forgets the cached token of a channel (the next operation authenticates again).
function invalidateToken(sii: SiiClient, channel: TokenChannel): Promise<void>

Uploads#

TypeScript
// Uploads a signed envelope: `EnvioDTE` through `DTEUpload` (ISO-8859-1 multipart), `EnvioBOLETA`
// through the receipts REST API in production or `DTEUpload` in certification (`channel`
// overrides).
function uploadEnvelope(
  sii: SiiClient,
  input: UploadEnvelopeInput,
  overrides?: CallOverrides,
): Promise<UploadReceipt>
 
// Uploads a signed book through `DTEUpload`, as `LibroGuia.xml` for a `LibroGuia` and
// `LibroCV.xml` otherwise unless `fileName` says differently; the XML must declare ISO-8859-1, as
// for `uploadEnvelope` (`INVALID_OPTION { field: 'xml' }` otherwise).
function uploadBook(
  sii: SiiClient,
  input: UploadXmlInput,
  overrides?: CallOverrides,
): Promise<UploadReceipt>
 
// Uploads a signed folio consumption report (RCOF, `ConsumoFolios`) through `DTEUpload` as
// `ConsumoFolios.xml`, unless `fileName` says differently; the XML must declare ISO-8859-1, as for
// `uploadEnvelope` (`INVALID_OPTION { field: 'xml' }` otherwise).
function uploadFolioConsumption(
  sii: SiiClient,
  input: UploadXmlInput,
  overrides?: CallOverrides,
): Promise<UploadReceipt>
TypeDescription
UploadReceiptWhat the SII returns when it takes a file.
UploadableEnvelopeA signed envelope, or just its kind and XML (for XML produced elsewhere, which must open with an XML declaration naming ISO-8859-1, as the SDK's own envelopes do). Defined as SignedEnvelope | { readonly kind: EnvelopeKind; readonly xml: string }.
UploadEnvelopeInputInput of uploadEnvelope.
UploadXmlInputInput of uploadBook and uploadFolioConsumption: the signed XML.
ReceptionOutcomeInterpreted RECEPCIONDTE: received and duplicate always carry a TrackID made of digits only; the other outcomes carry none.

Fields of UploadReceipt

FieldTypeDescription
trackIdstringSII tracking id of the upload (digits only).
receivedAtstringSII reception timestamp, YYYY-MM-DDTHH:MM:SS Chile time (client clock when the SII omits it).
kindUploadKindWhat was uploaded.
channelTokenChannelChannel used.
fileNamestringFile name sent in the multipart part.
duplicatebooleantrue when the SII reported the file as already uploaded and returned the original TrackID.
rawstringRaw SII response, as received (the archive port gets a redacted copy).

Fields of UploadEnvelopeInput

FieldTypeDescription
envelopeUploadableEnvelopeThe envelope to upload.
companyRut?stringCompany RUT; defaults to the client's.
senderRut?stringSender RUT; defaults to the client's.
channel?TokenChannelForce a channel for receipts (rest or soap); EnvioDTE always uses soap.

Fields of UploadXmlInput

FieldTypeDescription
xmlstringThe signed XML document; it must open with an XML declaration naming ISO-8859-1 (leading whitespace is dropped).
companyRut?stringCompany RUT; defaults to the client's.
senderRut?stringSender RUT; defaults to the client's.
fileName?stringName of the multipart file; letters, digits, _, . and -, ending in .xml. Defaults to LibroGuia.xml for a guide book, LibroCV.xml for any other book and ConsumoFolios.xml for a report.

Status queries#

TypeScript
// Status of an upload by TrackID: `QueryEstUp` on the `soap` channel (default) or the receipts
// REST envelope status on `rest`.
function queryUploadStatus(
  sii: SiiClient,
  input: QueryUploadStatusInput,
  overrides?: CallOverrides,
): Promise<UploadStatus>
 
// Polls `queryUploadStatus` every `intervalMs` until the status is no longer `pending`, up to
// `timeoutMs`.
function waitForUploadStatus(
  sii: SiiClient,
  input: WaitForUploadStatusInput,
  overrides?: CallOverrides,
): Promise<UploadStatus>
 
// Status of one document: `QueryEstDte` (SOAP, the default for every type except receipts) or the
// receipts REST per-document endpoint (the default for 39 and 41; the REST API answers about ten
// minutes after the upload).
function queryDocumentStatus(
  sii: SiiClient,
  input: QueryDocumentStatusInput,
  overrides?: CallOverrides,
): Promise<DocumentStatus>
 
// Whether the SII already holds a document with this type and folio: `QueryEstDte` (always SOAP),
// asked as the company itself, with the final-consumer receiver, today's date in Chile and amount
// 1, answers by folio existence first.
function folioReceived(
  sii: SiiClient,
  input: FolioReceivedInput,
  overrides?: CallOverrides,
): Promise<boolean | null>
TypeDescription
UploadStatusStatus of an upload.
UploadStatusCountsDocument counts of an envelope.
UploadStatusDocumentPer-document result in the REST envelope status.
UploadStatusDocumentErrorOne error of a document in the REST envelope status.
QueryUploadStatusInputInput of queryUploadStatus.
WaitForUploadStatusInputInput of waitForUploadStatus.
DocumentStatusStatus of one document.
QueryDocumentStatusInputInput of queryDocumentStatus.
FolioReceivedInputInput of folioReceived.

Fields of UploadStatus

FieldTypeDescription
codestringSII status code.
statusUploadStatusClassOutcome class of the code on this channel.
messagestringSpanish gloss from the SII, else from the catalog.
trackIdstringTrackID that was asked about.
channelTokenChannelChannel the answer came from.
countsUploadStatusCounts | nullCounts when the SII reports them.
documentTypestring | nullDocument type the counts refer to (SOAP).
documentsreadonly UploadStatusDocument[]Per-document detail (REST only).
rawstringRaw SII answer: the unescaped SII:RESPUESTA (SOAP) or the JSON text (REST).

Fields of UploadStatusCounts

FieldTypeDescription
reportednumberDocuments reported.
acceptednumberDocuments accepted.
rejectednumberDocuments rejected.
objectionsnumberDocuments accepted with objections.

Fields of QueryUploadStatusInput

FieldTypeDescription
trackIdstringTrackID of the upload, digits only.
companyRut?stringCompany RUT; defaults to the client's.
channel?TokenChannelsoap (default) or rest (receipts uploaded through the REST API).

Fields of WaitForUploadStatusInput

FieldTypeDescription
trackIdstringTrackID of the upload, digits only.
companyRut?stringCompany RUT; defaults to the client's.
channel?TokenChannelsoap (default) or rest (receipts uploaded through the REST API).
intervalMs?numberPoll interval, ms (5 000).
timeoutMs?numberGive up after, ms (600 000).

Fields of DocumentStatus

FieldTypeDescription
codestringDOK, DNK, FAU, FNA, FAN, EMP, TMD, TMC, MMD, MMC, AND, ANC.
statusDocumentStatusClassOutcome class of the code.
messagestringSpanish gloss from the SII, else from the catalog.
rawstringRaw SII answer: the unescaped SII:RESPUESTA (SOAP) or the JSON text (REST).

Fields of QueryDocumentStatusInput

FieldTypeDescription
companyRut?stringCompany (issuer) RUT; defaults to the client's.
receiverRutstringReceiver RUT.
consultantRut?stringRUT that asks (SOAP only); defaults to the client's sender.
typeDocumentTypeDocument type.
folionumberFolio.
issueDatestringIssue date YYYY-MM-DD.
totalAmountnumberTotal amount, rounded to a whole number.
channel?TokenChannelsoap (default for invoices) or rest (default for receipts).

Fields of FolioReceivedInput

FieldTypeDescription
companyRut?stringCompany (issuer) RUT; defaults to the client's.
typeDocumentTypeDocument type of the folio.
folionumberFolio to look up.

Acceptance and claims#

TypeScript
// Registers an action on a received document (`ingresarAceptacionReclamoDoc`): accept content,
// claim content, acknowledge goods, claim partial or total shortfall.
function registerClaim(
  sii: SiiClient,
  input: RegisterClaimInput,
  overrides?: CallOverrides,
): Promise<ClaimResult>
 
// Events registered on a document (`listarEventosHistDoc`).
function listClaimEvents(
  sii: SiiClient,
  input: ClaimDocumentInput,
  overrides?: CallOverrides,
): Promise<ClaimEventsResult>
 
// Whether a document is transferable (`consultarDocDteCedible`): `transferable` follows the 20–25
// codes, null when undetermined.
function queryTransferable(
  sii: SiiClient,
  input: ClaimDocumentInput,
  overrides?: CallOverrides,
): Promise<TransferabilityResult>
 
// When the SII received a document (`consultarFechaRecepcionSii`): the string it returned and that
// string as ISO when it is a date (`DD-MM-YYYY HH:MM:SS`).
function queryReceptionDate(
  sii: SiiClient,
  input: ClaimDocumentInput,
  overrides?: CallOverrides,
): Promise<ReceptionDateResult>
 
// What the receiver did, derived from the latest event of `listClaimEvents` (by date, else by
// position): `accepted` (ACD), `goodsReceived` (ERM), `claimed` (RCD/RFP/RFT), `paidInCash` (PAG),
// `none` (no events, NCA/ENC), `unknown` otherwise.
function receiverStatus(
  sii: SiiClient,
  input: ClaimDocumentInput,
  overrides?: CallOverrides,
): Promise<ReceiverStatusResult>
 
// The receiver's answer from the events of `listClaimEvents` and the reception date of
// `queryReceptionDate`, with no request: `NCA` comes first, then a claim (RCD/RFP/RFT), then
// `ACD`; then `PAG`, a document the SII marked paid in cash, which the registry takes no event on,
// so it has no deadline; past the deadline (the reception day plus eight, Ley 19.983) with none of
// them the document is accepted by law, and before it `ERM` is goods received and anything else
// pending. `ENC` changes nothing. Given the whole result of `listClaimEvents`, with no events and a
// `codResp` other than 15, 16 or 18 (the codes that list events or say there are none), the query
// failed and the answer is `unknown`, never pending or tacitly accepted, as `receiverStatus` reads
// it; events, when the SII sent some, speak whatever the code. Its events alone still work, but
// cannot tell a failed query. `receiverStatus` keeps reading the latest event only. Throws
// `INVALID_DATE` when `today` is not a date.
function receiverAnswer(
  listed:
    | readonly Pick<ClaimEvent, "code">[]
    | { readonly code: number; readonly events: readonly Pick<ClaimEvent, "code">[] },
  receivedAt: string | null,
  today: string,
): ReceiverAnswerResult
TypeDescription
ClaimDocumentTypeDocument types the registry accepts, derived from CLAIM_DOCUMENT_TYPES. Defined as (typeof CLAIM_DOCUMENT_TYPES)[number], that is 33 | 34 | 43.
ClaimDocumentInputA received document identified for the registry.
RegisterClaimInputInput of registerClaim.
ClaimResultOutcome of a registry operation. The SII answers business situations with a code instead of an error.
ClaimEventOne registered event. Its code is ACD, RCD, ERM, RFP, RFT, NCA, ENC or PAG.
ClaimEventsResultlistClaimEvents result.
TransferabilityResultqueryTransferable result.
ReceptionDateResultqueryReceptionDate result.
ReceiverStatusSummary of what the receiver did with a document, or paidInCash when the SII marked it paid in cash (PAG) and the registry takes no event on it. Defined as 'accepted' | 'goodsReceived' | 'claimed' | 'paidInCash' | 'none' | 'unknown'. An exhaustive switch on it needs the paidInCash case, new in 0.8.0.
ReceiverStatusResultreceiverStatus result.
ReceiverAnswerThe receiver's answer to a document, Ley 19.983 included. Defined as 'annulled' | 'claimed' | 'accepted' | 'paidInCash' | 'tacitlyAccepted' | 'goodsReceived' | 'pending' | 'unknown'. An exhaustive switch on it needs the unknown case, new in 0.7.0, and the paidInCash case, new in 0.8.0.
ReceiverAnswerResultreceiverAnswer result.

Fields of ClaimDocumentInput

FieldTypeDescription
issuerRutstringRUT of the document issuer (the supplier).
typeClaimDocumentType33, 34 or 43.
folionumberFolio.

Fields of RegisterClaimInput

FieldTypeDescription
issuerRutstringRUT of the document issuer (the supplier).
typeClaimDocumentType33, 34 or 43.
folionumberFolio.
actionClaimActionAction to register.

Fields of ClaimResult

FieldTypeDescription
codenumberSII response code (0 ok, 1–19 and 27 business, -1 internal).
descriptionstringSII description (≤ 70 chars).
okbooleantrue when code is 0.
rawstringInner XML of return.

Fields of ReceiverAnswerResult

FieldTypeDescription
answerReceiverAnswerThe answer: annulled (NCA), claimed (RCD, RFP, RFT), accepted (ACD), paidInCash (PAG: the SII marked it paid in cash, and the registry refuses any event on it with code 27), tacitlyAccepted (past the deadline with none of those), goodsReceived (ERM, with the eight days still running) or pending, in that order of precedence; unknown before all of them when the events query failed (no events and a codResp other than 15, 16 or 18), which only the whole result of listClaimEvents can say.
claimDeadlinestring | nullLast day to claim, YYYY-MM-DD: the day of the SII reception plus eight; null without a reception date, and for paidInCash, which takes no claim.

Authorized issuers#

TypeScript
// Asks the public registry of authorized electronic issuers (`ee_empresa_rut`) about a RUT: its
// business name, the resolution that authorizes it in this environment (the cover's `NroResol`
// and `FchResol`; number 0 in certification) and the document types it may issue. It asks for no
// certificate and no session, and changes nothing, so it follows the retry policy. A label that
// moved leaves its field null. Throws `INVALID_RUT`; `SII_PORTAL_REJECTED` with
// `rejection: 'companyNotAuthorized'` when the RUT is not an authorized issuer;
// `SII_PORTAL_UNEXPECTED_PAGE` when the answer has neither a name nor document types;
// `SII_HTTP_ERROR` and the transport codes.
function queryAuthorizedIssuer(
  sii: IssuerRegistryClient,
  input: { readonly rut: string },
  overrides?: CallOverrides,
): Promise<AuthorizedIssuer>
TypeDescription
IssuerRegistryClientWhat queryAuthorizedIssuer needs: an environment and the means to send. A SiiClient or a portal client fits, and so does a plain object, since the registry asks for no certificate. Defined as Pick<SiiClient, 'environment' | 'transport' | 'capture' | 'logger' | 'now' | 'retry' | 'sleep'>.
AuthorizedIssuerAn authorized issuer as the public registry lists it: an IssuerRegistryEntry plus the RUT asked for.
IssuerRegistryEntryWhat the registry says of an issuer. A label it cannot find leaves its field null instead of guessing.
AuthorizedDocumentTypeA document type the registry lists for an issuer.

Fields of AuthorizedIssuer

FieldTypeDescription
rutSiiRutThe RUT asked for.
(the fields of IssuerRegistryEntry)

Fields of IssuerRegistryEntry

FieldTypeDescription
businessNamestring | nullBusiness name.
resolutionNumbernumber | nullNumber of the resolution that authorizes the issuer in this environment, 0 in certification: the cover's NroResol.
resolutionDatestring | nullDate of that resolution, YYYY-MM-DD: the cover's FchResol.
regionalOfficestring | nullRegional office of the SII, as a Roman numeral; it is not the address of the company.
documentsreadonly AuthorizedDocumentType[]The document types listed, authorized now or before.

Fields of AuthorizedDocumentType

FieldTypeDescription
typenumberSII document type, 30 or more.
descriptionstringName as the registry shows it.
authorizedFromstring | nullDay it was authorized, YYYY-MM-DD, or null.
deauthorizedOnstring | nullDay it stopped being authorized, YYYY-MM-DD, or null while it still is.

Status code catalogs#

Catalogs that classify and explain what the SII answers to an upload, a status query or a claim. The messages are the SII wording, in Spanish.

TypeScript
// Classifies an envelope status code. Negative codes are errors of the query service, not of the
// envelope.
function classifyUploadStatus(code: string, channel?: UploadChannel): UploadStatusClass
 
// Spanish gloss of an envelope status code.
function uploadStatusMessage(code: string, channel?: UploadChannel): string
 
// True when the status is a transient query error (`-1` … `-14`) worth retrying.
function isRetryableStatus(code: string): boolean
 
// Classifies a `QueryEstDte` status code.
function classifyDocumentStatus(code: string): DocumentStatusClass
 
// Spanish gloss of a `QueryEstDte` status code.
function documentStatusMessage(code: string): string
 
// True when a `QueryEstUp`/`QueryEstDte` status means the token was rejected (renew it and retry
// once).
function isTokenErrorStatus(code: string): boolean
 
// `RECEPCIONDTE/STATUS` codes of the `DTEUpload` CGI with their Spanish gloss.
const RECEPTION_STATUS: Readonly<Record<string, ReceptionEntry>>
 
// Classifies a `RECEPCIONDTE/STATUS` code.
function classifyReceptionStatus(code: string): ReceptionStatusClass
 
// Spanish gloss of a `RECEPCIONDTE/STATUS` code.
function receptionStatusMessage(code: string): string
 
// Actions of the acceptance/claim registry, English name → SII code (`accionDoc`).
const CLAIM_ACTIONS: {
  readonly acceptContent: "ACD"
  readonly claimContent: "RCD"
  readonly acknowledgeGoods: "ERM"
  readonly claimPartialShortfall: "RFP"
  readonly claimTotalShortfall: "RFT"
}
 
// Document types the acceptance/claim registry accepts: invoices (33), exempt invoices (34) and
// settlement invoices (43). `ClaimDocumentType` is derived from this list.
const CLAIM_DOCUMENT_TYPES: readonly [33, 34, 43]
 
// Type guard: true when `value` is a document type the registry accepts, so a list of documents
// can be filtered by it.
function isClaimDocumentType(value: unknown): value is ClaimDocumentType
 
// Event codes the registry reports (`codEvento`), including the ones the receiver does not
// register: the credit-note events (`NCA`, `ENC`) and `PAG`, a cash payment the SII itself
// registers.
const CLAIM_EVENT_CODES: Readonly<Record<string, string>>
 
// `codResp` of the registry operations (0 ok, 1–19 and 27 business answers, -1 internal error).
// 27 is the SII refusing an event on a document paid in cash or free, seen in production on an
// acceptance of one listed with `PAG`.
const CLAIM_RESPONSE_CODES: Readonly<Record<string, string>>
 
// Spanish gloss of a `codResp`.
function claimResponseMessage(code: number): string
 
// `codResp` of `consultarDocDteCedible` with the transferability each one implies (`null` =
// undetermined).
const TRANSFERABILITY_CODES: Readonly< Record<string, { readonly message: string; readonly transferable: boolean | null }> >
 
// Spanish gloss of a `consultarDocDteCedible` code; falls back to the generic response codes.
function transferabilityMessage(code: number): string
TypeDescription
UploadStatusClassOutcome class of an envelope status code (QueryEstUp ESTADO or the receipts REST estado). Defined as | 'accepted' | 'acceptedWithObjections' | 'pending' | 'rejected' | 'queryError' | 'unknown'.
UploadChannelChannel the status came from: soap (QueryEstUp / DTEUpload) or rest (receipts API). RLV means success on REST and rejection on SOAP. Defined as 'soap' | 'rest'.
DocumentStatusClassOutcome class of a single-document status (QueryEstDte ESTADO). Defined as | 'received' | 'receivedWithMismatch' | 'notReceived' | 'notAuthorized' | 'modified' | 'cancelled' | 'queryError' | 'unknown'.
ReceptionStatusClassOutcome class of a DTEUpload reception STATUS. Defined as | 'received' | 'rejected' | 'notAuthenticated' | 'schemaInvalid' | 'alreadyUploaded' | 'unknown'.
ClaimActionEnglish name of a claim action. Defined as keyof typeof CLAIM_ACTIONS.
ClaimActionCodeSII code of a claim action. Defined as (typeof CLAIM_ACTIONS)[ClaimAction].