signDte()
Signs a stamped document with your digital certificate using XMLDSig, producing the XML you send to the SII.
Basic Usage#
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#
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 fromstampDte(). Passing an unstampedDteis a type error: the SII doesn't accept documents without a TED.certificate(Certificate) - The digital certificate fromloadCertificate(). 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:
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#
| Code | When |
|---|---|
CERTIFICATE_INVALID | loadCertificate() 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:
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#
import { signDte } from 'dte-sdk'
const signed = await Promise.all(stampedDocs.map((doc) => signDte(doc, certificate)))Handle a Bad Certificate#
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.
Related Functions#
stampDte()- Produces theStampedDteyou signsendToSii()- Next step: upload the signed documentstoXml()- Serialize the signed document