Skip to content

signDte()

Signs a stamped document with your digital certificate using XMLDSig, producing the XML you send to the SII.

Basic Usage#

TypeScript
import { readFile } from 'node:fs/promises'
import { loadCertificate, signDte } from 'dte-sdk'
 
const certificate = await loadCertificate(
  await readFile(process.env.DTE_CERT_PATH!),
  process.env.DTE_CERT_PASSWORD!,
)
 
const signed = await signDte(stamped, certificate)
 
signed.signedAt // '2026-10-28T10:15:42-03:00'
signed.xml      // '<DTE version="1.0"><Documento ID="F1024T33">…</Documento><Signature>…</Signature></DTE>'

Type Signature#

TypeScript
function signDte(stamped: StampedDte, certificate: Certificate): Promise<SignedDte>
 
function loadCertificate(pfx: Uint8Array, password: string): Promise<Certificate>
 
// SignedDte = StampedDte + { xml: string; signedAt: string }

Parameters#

  • stamped (StampedDte) - A document from stampDte(). Passing an unstamped Dte is a type error: the SII doesn't accept documents without a TED.
  • certificate (Certificate) - The digital certificate from loadCertificate(). Load it once and reuse it for every document.

Return Value#

Returns a Promise<SignedDte>: the stamped document plus two fields.

  • xml (string) - The complete signed <DTE> element, with the XMLDSig <Signature> over the <Documento>.
  • signedAt (string) - When it was signed, as an ISO 8601 timestamp with the Chilean offset.

Signing uses Web Crypto, so it works the same in Node, Deno, Bun and the browser. It is asynchronous for that reason.

loadCertificate()#

Loads a .pfx or .p12 digital certificate. The result is an opaque Certificate you pass to signDte(), sendToSii() and getStatus().

  • pfx (Uint8Array) - The bytes of the certificate file.
  • password (string) - The password that protects it.

It throws a DteError with code CERTIFICATE_INVALID when the file can't be read as a certificate or the password doesn't open it. The password is never logged, stored on the result, or echoed in error messages.

Every runtime can produce a Uint8Array:

TypeScript
import { readFile } from 'node:fs/promises'
import { loadCertificate } from 'dte-sdk'
 
// A Node Buffer is a Uint8Array
const certificate = await loadCertificate(await readFile('cert.pfx'), password)

Errors#

CodeWhen
CERTIFICATE_INVALIDloadCertificate() can't read the file, or the password is wrong

Examples#

Load Once, Sign Many#

Parsing a certificate is the expensive part. Cache the promise and share it:

TypeScript
import { readFile } from 'node:fs/promises'
import { loadCertificate, signDte, type Certificate, type StampedDte } from 'dte-sdk'
 
let certificate: Promise<Certificate> | undefined
 
function getCertificate(): Promise<Certificate> {
  certificate ??= readFile(process.env.DTE_CERT_PATH!).then((pfx) =>
    loadCertificate(pfx, process.env.DTE_CERT_PASSWORD!),
  )
  return certificate
}
 
export async function sign(stamped: StampedDte) {
  return signDte(stamped, await getCertificate())
}

Sign Many Documents#

TypeScript
import { signDte } from 'dte-sdk'
 
const signed = await Promise.all(stampedDocs.map((doc) => signDte(doc, certificate)))

Handle a Bad Certificate#

TypeScript
import { DteError, loadCertificate } from 'dte-sdk'
 
try {
  await loadCertificate(pfx, password)
} catch (error) {
  if (error instanceof DteError && error.code === 'CERTIFICATE_INVALID') {
    // The message is generic: it never contains the password
    console.error('Could not open the certificate. Check the file and password.')
  }
  throw error
}

Keep the Certificate Safe#

The certificate identifies a real person before the SII. Keep the file and its password in a secret store, never in your repository or client bundle, and limit who can read them.

  • stampDte() - Produces the StampedDte you sign
  • sendToSii() - Next step: upload the signed documents
  • toXml() - Serialize the signed document