sendToSii()
Uploads signed documents to the SII in a signed envelope and returns the track id you use to follow them.
Basic Usage#
import { sendToSii } from 'dte-sdk'
const { trackId, receivedAt } = await sendToSii(signed, {
certificate,
environment: 'certification',
senderRut: '15.234.567-4',
resolution: { number: 0, date: '2026-09-01' },
})
trackId // '0234567890'
receivedAt // '2026-10-28T10:15:44-03:00'Type Signature#
function sendToSii(
docs: SignedDte | SignedDte[],
options: {
certificate: Certificate
environment: 'certification' | 'production'
senderRut: string // RUT of the person sending (certificate owner)
resolution: { number: number; date: string }
signal?: AbortSignal
},
): Promise<{ trackId: string; receivedAt: string }>Parameters#
docs(SignedDte | SignedDte[]) - One signed document, or several to send in a single envelope. Send documents from one issuer per call.optionscertificate(Certificate) - FromloadCertificate(). It signs the envelope and authenticates with the SII.environment('certification' | 'production') - Use'certification'while you go through the SII certification process, and'production'once you're authorized.senderRut(string) - The RUT of the person sending, who owns the certificate. This is not the company RUT.resolution({ number, date }) - Number and date (YYYY-MM-DD) of the SII resolution that authorizes the issuer to emit electronic documents. In certification the number is0.signal(AbortSignal, optional) - Cancels the upload, for example withAbortSignal.timeout(30_000).
Return Value#
Returns a promise of:
trackId(string) - The id the SII assigned to the upload. Persist it: it's how you ask for the result later.receivedAt(string) - When the SII received it, as an ISO 8601 timestamp.
A track id means the SII received the envelope, not that it accepted the documents. Acceptance comes later, through getStatus().
What It Does#
Wraps the documents
Puts every signed document into an EnvioDTE envelope and signs the envelope with your certificate.
Authenticates
Requests a seed from the SII, exchanges it for a token, and caches the token per certificate so consecutive calls don't authenticate again.
Uploads
Sends the envelope to the environment you chose.
Returns the track id
Resolves with trackId and receivedAt as soon as the SII confirms reception.
Errors#
| Code | When | What to do |
|---|---|---|
SII_UNAVAILABLE | The SII could not be reached, timed out, or is down | Retry later with backoff, using the same signed documents |
SII_REJECTED | The SII refused the upload, for example the authentication or the envelope | Don't retry as is: check the certificate, sender RUT and resolution |
getStatus()#
Asks the SII what happened to an upload.
import { getStatus } from 'dte-sdk'
const status = await getStatus('0234567890', {
certificate,
environment: 'certification',
issuerRut: '76.123.456-0',
})
status.state // 'accepted'
status.documents // [{ type: 33, folio: 1024, state: 'accepted' }]function getStatus(
trackId: string,
options: {
certificate: Certificate
environment: 'certification' | 'production'
issuerRut: string
},
): Promise<Status>
type Status = {
state: 'received' | 'accepted' | 'accepted_with_objections' | 'rejected'
documents: {
type: DteType
folio: number
state: 'received' | 'accepted' | 'accepted_with_objections' | 'rejected'
reason?: string
}[]
}trackId- The idsendToSii()returned.options.certificate,options.environment- The same ones you sent with.options.issuerRut- The RUT of the company that issued the documents.
Like sendToSii(), it throws SII_UNAVAILABLE when the SII can't be reached.
Acceptance States#
| State | Meaning | What to do |
|---|---|---|
received | The SII has the envelope and is still validating it. | Ask again later |
accepted | The documents are valid | Deliver them to the customer |
accepted_with_objections | Accepted, but the SII noted objections (reparos). reason explains each one. | The document is valid; fix the cause for future documents |
rejected | The SII rejected it. reason explains why. | Fix the cause and issue the document again |
state summarizes the whole envelope. When you send several documents at once, check documents for the outcome of each one.
Examples#
Send a Batch#
import { sendToSii } from 'dte-sdk'
const { trackId } = await sendToSii([invoice, creditNote], {
certificate,
environment: 'production',
senderRut: process.env.DTE_SENDER_RUT!,
resolution: {
number: Number(process.env.SII_RESOLUTION_NUMBER),
date: process.env.SII_RESOLUTION_DATE!,
},
})Time Out Slow Uploads#
const { trackId } = await sendToSii(signed, {
...siiOptions,
signal: AbortSignal.timeout(30_000),
})Retry When the SII Is Unavailable#
import { DteError, sendToSii, type SignedDte } from 'dte-sdk'
async function sendWithRetry(docs: SignedDte[], attempts = 3) {
for (let attempt = 1; ; attempt++) {
try {
return await sendToSii(docs, siiOptions)
} catch (error) {
const retryable = error instanceof DteError && error.code === 'SII_UNAVAILABLE'
if (!retryable || attempt === attempts) throw error
await new Promise((resolve) => setTimeout(resolve, 2_000 * 2 ** attempt))
}
}
}Wait for a Final State#
Validation usually takes a little while. Poll with a growing delay, and hand off to a background job if it's still received:
import { getStatus } from 'dte-sdk'
async function waitForSii(trackId: string) {
for (let attempt = 0; attempt < 5; attempt++) {
const status = await getStatus(trackId, {
certificate,
environment: 'production',
issuerRut: '76.123.456-0',
})
if (status.state !== 'received') return status
await new Promise((resolve) => setTimeout(resolve, 5_000 * 2 ** attempt))
}
return null // still processing: check again from a scheduled job
}See Issue an Invoice for a complete flow that persists the track id and polls from a job.
Related Functions#
signDte()- Produces theSignedDtedocuments you sendtoXml()- Keep a copy of exactly what you sentcreateDte()- Where every document starts