signDte()
Firma un documento timbrado con tu certificado digital usando XMLDSig, y produce el XML que envías al SII.
Uso básico#
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>'Firma de tipo#
function signDte(stamped: StampedDte, certificate: Certificate): Promise<SignedDte>
function loadCertificate(pfx: Uint8Array, password: string): Promise<Certificate>
// SignedDte = StampedDte + { xml: string; signedAt: string }Parámetros#
stamped(StampedDte) - Un documento timbrado constampDte(). Pasar unDtesin timbrar es un error de tipos: el SII no acepta documentos sin TED.certificate(Certificate) - El certificado digital cargado conloadCertificate(). Cárgalo una vez y reutilízalo para todos los documentos.
Valor de retorno#
Retorna una Promise<SignedDte>: el documento timbrado más dos campos.
xml(string) - El elemento<DTE>completo y firmado, con la<Signature>XMLDSig sobre el<Documento>.signedAt(string) - Cuándo se firmó, como marca de tiempo ISO 8601 con el desfase horario de Chile.
La firma usa Web Crypto, así que funciona igual en Node, Deno, Bun y el navegador. Por eso es asíncrona.
loadCertificate()#
Carga un certificado digital .pfx o .p12. El resultado es un Certificate opaco que pasas a signDte(), sendToSii() y getStatus().
pfx(Uint8Array) - Los bytes del archivo del certificado.password(string) - La contraseña que lo protege.
Lanza un DteError con código CERTIFICATE_INVALID cuando el archivo no se puede leer como certificado o la contraseña no lo abre. La contraseña nunca se registra en logs, no se guarda en el resultado y no aparece en los mensajes de error.
Todos los runtimes pueden producir un 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)Errores#
| Código | Cuándo |
|---|---|
CERTIFICATE_INVALID | loadCertificate() no puede leer el archivo, o la contraseña es incorrecta |
Ejemplos#
Cargar una vez, firmar muchas#
Leer el certificado es la parte costosa. Guarda la promesa en caché y compártela:
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())
}Firmar varios documentos#
import { signDte } from 'dte-sdk'
const signed = await Promise.all(stampedDocs.map((doc) => signDte(doc, certificate)))Manejar un certificado inválido#
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
}Protege el certificado#
El certificado identifica a una persona real ante el SII. Guarda el archivo y su contraseña en un gestor de secretos, nunca en tu repositorio ni en el bundle del cliente, y limita quién puede leerlos.
Funciones relacionadas#
stampDte()- Produce elStampedDteque firmassendToSii()- Siguiente paso: subir los documentos firmadostoXml()- Serializa el documento firmado