Skip to content

Portal API (dte-sdk/portal)

The certificate-authenticated SII portal: session, company data, folios and CAF requests, the purchase and sales register, the MIPYME backup and the activity verification; plus the certification sets and the certification runner. It runs on Node only, because fetch cannot present a client certificate.

TypeScript
import { createPortalClient, openPortalSession, queryFolioQuota } from 'dte-sdk/portal'

What has met the real portal: in production, on 9 and 10 November 2026, the certificate login with the session reused between reads, for a company not enrolled as an issuer, and the register's reads (fetchRegisterSummary, listPeriodDocuments, fetchPurchaseDocument, listPurchaseTypes) with the rows of one received invoice; in earlier runs whose environment wasn't written down, login, logout, taxpayer data and the refusal pages, for a company not enrolled as an issuer, and the register's read-only requests for a company with no documents. The folio and CAF pages of an enrolled company have not been seen yet, because they need one, and neither have the register's writes or the MIPYME backup's downloads. The activity verification was read for a pending verification and, on 9 November, for a conditioned one pending accreditation; an approved one has not been seen yet, so its read stays unstable. The certification (sets, runner, exchange, upload of the samples) and the certification of receipts have not been run yet. All of it is tested against synthetic answers. See Status.

The groups below follow the guides: Portal, Register, Test sets, Runner, Exchange and samples and Receipts. The portal functions take a PortalClient first and a CallOverrides last; the certification steps take a CertificationDependencies and a CertificationState.

Catalogs and rejections#

The portal reports a refusal as a DteError with code SII_PORTAL_REJECTED and details.rejection, one of the PortalRejection values. PORTAL_REJECTIONS and portalRejectionMessage give the Spanish text for the operator. The composite flows return refusals as data instead of throwing. Guide: Portal.

TypeScript
// What each rejection means and what to do about it, in Spanish, for the operator.
const PORTAL_REJECTIONS: Readonly<Record<PortalRejection, string>>
 
// The Spanish message of a rejection.
function portalRejectionMessage(rejection: PortalRejection): string
TypeDescription
AccountingStatusAccounting status of a document in the register. Defined as 'registered' | 'pending' | 'notIncluded' | 'claimed'. Which ones each side can hold is in REGISTER_ACCOUNTING_STATUSES.
DocumentDirectionWhich side of a document the taxpayer is on. Defined as 'issued' | 'received'.
PortalRejectionWhy the SII refused a portal request.
RegisterOperationWhich book of the register. Defined as 'purchase' | 'sale'.

Client, lock and session#

createPortalClient returns a frozen client; the portal operations are free functions that take it first and accept a trailing CallOverrides (signal, timeoutMs, retry). The portal runs on Node only, because fetch cannot present a client certificate: the default transport is node:https with the certificate and TLS verification on. The certificate must be enabled as a login method at sii.cl, or the login throws SII_PORTAL_CERT_NOT_ENABLED. Sessions open on demand; openPortalSession and closePortalSession do it explicitly. sessionCache and lock are ports for deployments with several replicas. Guide: Portal.

Client#

TypeScript
// Validates and completes the options into a frozen `PortalClient`.
function createPortalClient(options: PortalClientOptions): PortalClient
 
// Retry policy of the portal: 4 attempts at 2, 4 and 8 s, no jitter, repeating what
// `isRetryablePortalError` accepts.
const DEFAULT_PORTAL_RETRY_POLICY: RetryPolicy
 
// True for what is worth repeating at the portal: transport failures, timeouts, HTTP 502/503/504,
// and the TLS failures the SII produces intermittently with a client certificate (`EPROTO …
// rsa_pss`), which are not a sign of a bad certificate.
function isRetryablePortalError(error: unknown): boolean
TypeDescription
PortalClientThe portal client: plain frozen data, every field resolved. Pass it to the portal functions.
PortalClientOptionsOptions of createPortalClient.

Fields of PortalClientOptions

FieldTypeDescription
environmentEnvironmentTarget environment: selects maullin or palena for the CGI pages.
certificateCertificateCertificate presented at login; its holder is the portal user.
companyRut?stringCompany RUT used by every operation unless overridden per call.
transport?HttpTransportHTTP transport; Node https with the client certificate and a TLS 1.2 cap by default.
sessionCache?TokenCacheWhere the session lives; in memory by default. createDirectoryTokenCache({ dir }) from dte-sdk/node keeps it on disk, one owner-only file per certificate.
sessionTtlMs?numberSession lifetime in the cache; 90 min by default, refreshed on each use.
lock?PortalLockWho may use the session now; a mutex in the process by default, which holds within one process only: processes that share a session on disk need a shared lock.
retry?Partial<RetryPolicy> | falseRetry policy overrides, or false to disable retries.
timeoutMs?numberTimeout per request, ms; 20 000 by default.
closePreviousSessions?booleanClose earlier sessions when the SII reports the limit and offers it; true by default.
logger?LoggerLogger; silent by default.
capture?HttpCaptureHTTP capture port; off by default.
now?() => DateClock.
sleep?SleepFnWait between retries and between steps.
randomId?() => stringSource of the transaction ids of the RCV; crypto.randomUUID by default.

Lock#

TypeScript
// Mutex per key inside one process.
function createMemoryPortalLock(): PortalLock
TypeDescription
PortalLockWho may use a portal session now: run starts only when the lock is held and the lock is released when it settles, even if it fails. Defined as <T>(key: string, run: () => Promise<T>) => Promise<T>.

Session#

TypeScript
// Opens a session explicitly, reusing a cached one that is still alive, as the company page of the
// client's environment (`ad_empresa1`) says. The other operations do not need this: they log in
// on demand.
function openPortalSession(
  portal: PortalClient,
  overrides?: CallOverrides,
): Promise<PortalSessionInfo>
 
// Closes the session to give its slot back, and always removes the cached session. A failed logout
// is only logged: the SII expires the session on its own anyway.
function closePortalSession(portal: PortalClient, overrides?: CallOverrides): Promise<void>
TypeDescription
PortalSessionInfoWhat openPortalSession learned.

Company data#

The resolution of the company (per environment), its taxpayer data, and the issuer profile that combines both. Guide: Portal.

TypeScript
// Reads the resolution of a company. It is per environment: certification and production answer
// different dates and numbers for one RUT, and the wrong pair gets an envelope rejected with
// "Error en Carátula".
function fetchCompanyResolution(
  portal: PortalClient,
  input?: { readonly companyRut?: string; readonly environment?: Environment; },
  overrides?: CallOverrides,
): Promise<CompanyResolution>
 
// Reads taxpayer data: name, address split in its parts, activities and branches.
function fetchTaxpayerData(
  portal: PortalClient,
  input?: { readonly companyRut?: string; },
  overrides?: CallOverrides,
): Promise<TaxpayerData>
 
// Reads the resolution and the taxpayer data in sequence and combines them. In parallel, one reply
// overwrites the balancer cookie the other needs and `ad_empresa2` answers empty.
function fetchIssuerProfile(
  portal: PortalClient,
  input?: { readonly companyRut?: string; readonly environment?: Environment; },
  overrides?: CallOverrides,
): Promise<IssuerProfile>
TypeDescription
IssuerProfileWhat a company needs to fill an Issuer and an envelope cover.
CompanyResolutionWhat ad_empresa2 says about a company in one environment.
TaxpayerDataWhat ce_consulta_muestra_e says about a taxpayer. It only answers on the certification host.
TaxpayerActivityOne economic activity.
TaxpayerBranchOne registered branch.

Fields of IssuerProfile

FieldTypeDescription
rutSiiRutCompany RUT.
businessNamestringBusiness name.
businessActivitystringLine of business: the first activity, else the description.
activityCodenumber | nullCode of the first activity, or null.
addressstringStreet address.
communestringCommune.
citystringCity; the commune when absent.
resolutionDatestringResolution date of the environment asked for.
resolutionNumbernumberResolution number of the environment asked for.

Fields of CompanyResolution

FieldTypeDescription
rutstring | nullCompany RUT as shown.
businessNamestring | nullBusiness name.
resolutionDatestring | nullResolution date, YYYY-MM-DD.
resolutionNumbernumber | nullResolution number.
authorizationDatestring | nullAuthorization date, as sent.

Fields of TaxpayerData

FieldTypeDescription
rutstring | nullRUT.
businessNamestring | nullBusiness name.
businessActivitystring | nullDescription of the first activity.
activityCodenumber | nullCode of the first activity.
addressstring | nullStreet part of the address.
neighborhoodstring | nullNeighbourhood.
citystring | nullCity.
communestring | nullCommune.
portalAddressstring | nullAddress cell, verbatim.
regionalOfficestring | nullSII regional office.
activitiesreadonly TaxpayerActivity[]Economic activities.
branchesreadonly TaxpayerBranch[]Registered branches.
descriptionstring | nullFree description.

Certification sets query#

Reads the state of each test set and book on the certification host. It only reads; declaring progress is declareProgress. Guide: Test sets.

TypeScript
// Reads the state of each test set and book, on the certification host. It only reads: declaring
// progress is `declareProgress`.
function queryCertificationSets(
  portal: PortalClient,
  input?: { readonly companyRut?: string; },
  overrides?: CallOverrides,
): Promise<CertificationSets>
TypeDescription
CertificationSetsThe certification state of a company.
CertificationSetOne test set or book of the certification, and its state.

Stamping: quota and CAF requests#

List the document types the company can stamp, read the folio quota (this stamps nothing) and request a CAF. The SII may grant less than you ask for: read granted. The CAF XML holds a private key: treat it as a secret. Guide: Portal.

TypeScript
// Lists the document types the portal offers for stamping with this company. An error page is not
// "no types": a page with no selector and no stated rejection throws.
function listStampableTypes(
  portal: PortalClient,
  input?: { readonly companyRut?: string; },
  overrides?: CallOverrides,
): Promise<readonly StampableType[]>
 
// Reads how many folios the SII authorizes for a type, stopping at the form that shows it: nothing
// is stamped and the quota does not move. `MAX_AUTOR` and `FOLIOS_DISP` appear only while the SII
// rations the type. The form is the one whose selector has the type chosen: the company's page, with
// none chosen, is reloaded with it, and a last page that is not that form throws
// `SII_PORTAL_SESSION_EXPIRED` or `SII_PORTAL_UNEXPECTED_PAGE` instead of reading as an unrationed type.
function queryFolioQuota(
  portal: PortalClient,
  input: { readonly type: DocumentType; readonly companyRut?: string; },
  overrides?: CallOverrides,
): Promise<FolioQuota>
 
// Requests a range of folios and downloads its CAF through the five portal steps. A rejection can
// arrive at any step. With the effective maximum exceeded and no `minQuantity`, it asks once more
// for one folio. When the SII answers the request with the request form again, nothing is sent a
// second time: it throws `SII_PORTAL_REJECTED` with `stampingUncertain`, since the folios may have
// been granted, and `listReobtainableRanges` says whether they were.
function requestCaf(
  portal: PortalClient,
  input: CafRequestInput,
  overrides?: CallOverrides,
): Promise<ObtainedCaf>
TypeDescription
CafRequestInputInput of requestCaf.
FolioQuotaThe stamping quota of a document type.
ObtainedCafA CAF obtained from the portal. xml holds the CAF private key: store it as a secret.
QuotaFieldsThe quota of a form: both null when the SII is not rationing this type, because only then it publishes them.
StampableTypeA document type the portal offers for stamping.

Fields of CafRequestInput

FieldTypeDescription
typeDocumentTypeDocument type.
quantitynumberFolios wanted.
minQuantity?numberLeast acceptable: below it nothing is stamped, because a short range goes unused and lowers the next maximum.
companyRut?stringCompany RUT; the client's by default.

Fields of FolioQuota

FieldTypeDescription
maxAuthorizednumber | nullMost folios the SII authorizes now.
availableFoliosnumber | nullFolios stamped and unused.
unrestrictedbooleanThe SII is not rationing this type.
blockedbooleanThe SII authorizes nothing: "NO SE AUTORIZA TIMBRAJE".

Fields of ObtainedCaf

FieldTypeDescription
xmlstringThe file as the SII served it.
cafCafThe file parsed.
grantednumberFolios it covers.
maxAuthorizednumber | nullMost folios the SII authorized, or null when it was not rationing.
availableFoliosnumber | nullStamped and unused folios, or null when it was not rationing.
recoveredbooleanIt came back through "ya fue autorizado" or the re-download flow.

Annulment#

Annulling unused folios is irreversible and needs an explicit scope. List the unused ranges first. Guide: Portal.

TypeScript
// Lists the unused ranges of a document type, following the pages of the listing. It changes
// nothing.
function listFolioRanges(
  portal: PortalClient,
  input: { readonly type: DocumentType; readonly companyRut?: string; },
  overrides?: CallOverrides,
): Promise<FolioRanges>
 
// Annuls unused folios: up to four passes over the listing, by range and folio by folio when the
// part of the range was annulled or received before, stopping a pass after two real refusals in a
// row. A single folio keeps the SII's answer. Once the SII has answered for some folios, a
// `DteError` that ends the walk (an expired session, a block, the caller's abort, a later listing
// refused or not understood) comes back in `failure`, with what was done until then; a range that
// never got through (`transport`) is no answer, and before any answer the error is thrown. A range
// answered folio by folio comes back in as few pieces as its answers allow, and a walk cut short at
// one folio keeps the folios answered before it.
function annulFolios(
  portal: PortalClient,
  input: AnnulFoliosInput,
  overrides?: CallOverrides,
): Promise<AnnulmentResult>
TypeDescription
AnnulFoliosInputInput of annulFolios. One of range, withinDays or all is required: annulment cannot be undone and annulled folios count against the stamping quota for six months.
AnnulmentResultWhat an annulment did, even when a later step cut it short.
FolioRangesThe unused ranges of a document type.
FolioSpanSome folios and how many they are.
AnnulmentRejectionReasonWhy folios were not annulled. alreadyAnnulled and received are what the SII said about them and are final; siiError, transport and unknown (an answer in no known words) are not, since the SII may have annulled them all the same. Defined as 'alreadyAnnulled' | 'received' | 'siiError' | 'transport' | 'unknown'.
UnusedFolioRangeA stamped range with unused folios, as the annulment page lists it. Annulled ranges stay on this list forever.

Fields of AnnulFoliosInput

FieldTypeDescription
typeDocumentTypeDocument type.
range?{ readonly from: number; readonly to: number }Only these folios.
withinDays?numberOnly ranges stamped within these days; a range with no readable date is skipped.
all?booleanEvery unused range, up to maxRanges.
reason?stringReason; "Folios no utilizados" by default.
maxRanges?numberMost ranges tried in EACH pass, taken from the end of the listing; 50 by default. It is not a limit on the call: there are up to four passes, so one call can annul up to four times this many ranges (200 by default).
exclude?readonly { readonly from: number; readonly to: number }[]Folios never to touch, such as a CAF still in use.
knownAnnulled?readonly string[]knownAnnulled of the previous run: a listed range whose folios these keys cover, in one key or several, is not tried again.
companyRut?stringCompany RUT; the client's by default.

Fields of AnnulmentResult

FieldTypeDescription
annulledreadonly FolioSpan[]Folios annulled. Folios next to each other with the same answer are one span.
rejectedreadonly (FolioSpan & { readonly reason: AnnulmentRejectionReason })[]Folios not annulled, and why, folios next to each other with the same answer in one span. alreadyAnnulled and received are expected results, not refusals; unknown is an answer the SII gave in no known words, so those folios may be annulled or not.
totalAnnullednumberSum of annulled.
totalRejectednumberSum of rejected.
knownAnnulledreadonly string[]from-to keys that are final (annulled, alreadyAnnulled or received): persist it and pass it back, because the portal keeps listing them forever. A range answered folio by folio comes in as few keys as its answers allow, one for each run of folios with the same answer, so read the keys as spans of folios, not as the listing's ranges. Nothing the SII answered in unknown words goes here.
failureFolioFlowFailure | nullWhat stopped the walk once the SII had answered for some folios, or null: a DteError of a later listing (listFolioRanges) or of a later range (annulFolios), a refusal included. Annulling cannot be undone, so what was done until then comes back: persist knownAnnulled whether failure is set or not. Null on a walk that finishes.

Reobtain#

Download again the CAF of a range the SII already authorized. It costs no quota. Guide: Portal.

TypeScript
// Lists the authorized ranges the SII lets download again. Annulled ranges appear there unmarked,
// so learning which are costs one request per range. The procedure is entered like the others, with
// a login on demand and the representation screen. Only a listing gives a list, empty when it has
// no ranges: a page that states a refusal throws `SII_PORTAL_REJECTED`, a login page
// `SII_PORTAL_SESSION_EXPIRED` and any other page `SII_PORTAL_UNEXPECTED_PAGE`.
function listReobtainableRanges(
  portal: PortalClient,
  input: { readonly type: DocumentType; readonly companyRut?: string; },
  overrides?: CallOverrides,
): Promise<readonly ReobtainableRange[]>
 
// Downloads the CAF of an already authorized range. It costs no quota. The procedure is entered
// first, as `listReobtainableRanges` enters it, with a login on demand, so a cached session that
// expired since the listing logs in again instead of posting the range with it. A page that states
// a refusal at the entry throws `SII_PORTAL_REJECTED` and any other page that is not the procedure
// `SII_PORTAL_UNEXPECTED_PAGE`, before anything is posted; a login page at any step throws
// `SII_PORTAL_SESSION_EXPIRED`, never the refusal of a step.
function reobtainCaf(
  portal: PortalClient,
  input: { readonly type: DocumentType; readonly range: ReobtainableRange; },
  overrides?: CallOverrides,
): Promise<ObtainedCaf>
TypeDescription
ReobtainableRangeAn authorized range the SII lets download again. The list also holds ranges already issued, which the SII does not mark at all: re-using one gets each document rejected with DTE-3-101.

Entering the procedure makes reobtainCaf one GET more, of rf_reobtencion1_folios, than before 0.7.0. A caller that took reobtainDownloadMissing or reobtainCafMissing for an expired session now gets SII_PORTAL_SESSION_EXPIRED.

Flows#

Composite flows built on the operations above. They return refusals as data and, once they hold something the caller must not lose (CAFs, or folios the SII annulled), any other DteError too, in failure. The original error goes first to the client's logger, as the warning sii portal flow stopped, keeping what it holds, with the error's details, flow, code and stoppedAt, and every text detail redacted. The warning leaves out what a page said (portalMessage, body) and the url it came from, which can name the company and its RUT; the thrown errors keep them. Guide: Portal.

TypeScript
// Requests one CAF that covers the whole quantity; below it nothing is stamped. With `allowAnnul`,
// once the SII has answered the annulment, a `DteError` that cuts it short, or one of the request
// asked once more after it, ends the flow with `rejection: null`, the first request's quota, the
// failure in `failure` and what was annulled in `knownAnnulled`; a cut-short annulment is not
// followed by another request. Before the annulment's first answer it throws.
function requestCafExact(
  portal: PortalClient,
  input: RequestCafExactInput,
  overrides?: CallOverrides,
): Promise<RequestCafExactResult>
 
// Covers a quantity across several CAFs, for when `FOLIOS_DISP` is 0 and `MAX_AUTOR` is small: the
// SII rations by history, there is nothing to annul or download again, and waiting does not move
// it. A refusal comes back with its own kind and `portalMessage`, on the first trip or a later one;
// after a grant, only one folio over the maximum (`quotaExceeded`) reads as `quotaCapReached`. Once
// a CAF is in hand, a later trip that fails with a `DteError` other than
// a refusal (a transport failure, a timeout, an expired session, a block, `CAF_INVALID`, the
// caller's abort) ends the flow with the CAFs obtained, the last quota seen and the failure in
// `failure`; with no CAF in hand it throws. `quantity` must be a whole number of at least 1, or it
// throws `INVALID_OPTION` before anything goes out.
function requestCafInBatches(
  portal: PortalClient,
  input: RequestCafInBatchesInput,
  overrides?: CallOverrides,
): Promise<FolioFlowResult>
 
// Covers a quantity from authorized ranges without spending quota, oldest folio first. It is what
// lifts a stamping block, since the SII asks for folios to be issued. The listing logs in on demand,
// and whatever fails while listing (a refusal, an expired session, a page that is not the listing)
// reads as no ranges, with the failure in `reason`: it does not throw. A refused download is logged
// and the walk moves on. Once a CAF is in hand, a download that fails with any other `DteError` (a
// transport failure, a timeout, an expired session, a block, the caller's abort) ends the walk with
// the CAFs downloaded, the failure's message in `reason` and the failure in `failure`; with no CAF
// in hand it throws. A login page in answer to the range or to the file is an expired session, not
// a refused download.
function reobtainFolios(
  portal: PortalClient,
  input: ReobtainFoliosInput,
  overrides?: CallOverrides,
): Promise<ReobtainResult>
TypeDescription
FolioFlowFailureThe DteError that stopped a folio flow already holding something the caller must not lose: CAFs, or folios the SII has annulled. Only its code is kept, with the kind of a refusal, since its other details may carry what a page said; the logger gets the rest of them, never what a page said or its address.
FolioFlowResultThe outcome of a composite flow. Refusals come back as data, because the flow may already hold CAFs: those must reach the caller, and a CAF cannot travel in an error's details, which get logged. For the same reason, once a CAF is in hand, or folios were annulled, any other DteError comes back as data too, in failure.
ReobtainFoliosInputInput of reobtainFolios.
ReobtainResultWhat reobtainFolios obtained. What was downloaded comes back even when it falls short or a later download fails, so the caller asks only for the difference.
RequestCafExactInputInput of requestCafExact.
RequestCafExactResultThe outcome of requestCafExact, plus the memory of annulled ranges. Its failure is set once the SII has answered its annulment and a later step fails, and knownAnnulled then keeps what was annulled.
RequestCafInBatchesInputInput of requestCafInBatches.

Fields of FolioFlowFailure

FieldTypeDescription
codeDteErrorCodeThe error code.
operation'queryFolioQuota' | 'requestCaf' | 'reobtainCaf' | 'listFolioRanges' | 'annulFolios'The step that failed. Reading the quota or listing ranges changes nothing; a request may have been granted all the same, and listReobtainableRanges says whether it was; an annulment may have gone through, and the next one hears it from the SII as "already annulled".
rejection?PortalRejectionThe kind of refusal when code is SII_PORTAL_REJECTED, as a listing the SII refuses after an annulment; absent otherwise.

Fields of FolioFlowResult

FieldTypeDescription
completebooleanThe quantity asked for was covered.
cafsreadonly ObtainedCaf[]Every CAF obtained, even when falling short.
grantednumberFolios covered.
maxAuthorizednumber | nullLast MAX_AUTOR seen, or null.
availableFoliosnumber | nullLast FOLIOS_DISP seen, or null.
rejectionPortalRejection | nullWhy it fell short, or null.
portalMessagestring | nullWhat the portal said, with its secrets redacted, or null.
failureFolioFlowFailure | nullWhat stopped the flow while it held something the caller must not lose, or null; rejection is then null. requestCafInBatches sets it with CAFs in hand, when it was not a refusal; requestCafExact once the SII has answered its annulment, with what cut the annulment short or the request after it, and knownAnnulled keeps what was annulled.

Fields of ReobtainFoliosInput

FieldTypeDescription
typeDocumentTypeDocument type.
quantitynumberFolios to cover.
isIssued?(range: { readonly from: number; readonly to: number }) => boolean | Promise<boolean>The caller's record of ranges already sent to the SII, which the portal does not mark.
isFolioFree?(folio: number) => boolean | Promise<boolean>Confirms a folio at the SII, typically with folioReceived.
maxChecksPerRange?numberMost checks per range; 30 by default.
companyRut?stringCompany RUT; the client's by default.

Fields of ReobtainResult

FieldTypeDescription
completebooleanThe quantity was covered.
cafsreadonly ObtainedCaf[]The CAFs downloaded.
rangesreadonly { readonly from: number; readonly to: number; readonly freeFolios: readonly number[] }[]Each range used and its free folios.
expiredreadonly { readonly from: number; readonly to: number; readonly authorizationDate: string | null }[]Ranges whose CAF already expired: they do not count and should be annulled.
availablenumberFree folios covered.
reasonstring | nullWhy it fell short, in words, or null; when the listing or a download failed, the message of that failure.
failureFolioFlowFailure | nullWhat stopped the downloads with CAFs in hand when it was not a refusal, or null; operation is then reobtainCaf.

Fields of RequestCafExactInput

FieldTypeDescription
typeDocumentTypeDocument type.
quantitynumberFolios needed in one CAF.
allowAnnul?booleanAnnul unused folios to lift the limit, and ask once more. Off by default: it cannot be undone and counts against the quota for six months.
exclude?readonly { readonly from: number; readonly to: number }[]Folios annulling never touches, such as a CAF still in use.
knownAnnulled?readonly string[]knownAnnulled of the previous run: a listed range whose folios these keys cover, in one key or several, is not tried again.
companyRut?stringCompany RUT; the client's by default.

Fields of RequestCafInBatchesInput

FieldTypeDescription
typeDocumentTypeDocument type.
quantitynumberFolios to cover in total: a whole number of at least 1.
maxBatches?numberMost trips to the portal; 4 by default.
initialQuota?FolioQuotaA quota already read, to skip the first reading.
companyRut?stringCompany RUT; the client's by default.

Purchase and sales register (RCV)#

The register runs on the portal session. The reads give typed fields (null when absent) and a raw copy of the row. The writes (changePurchaseType, moveVatToCommonUse, moveVatToRecoverable) change the real register on a production client. What the register does with each document code is data in the package: see Register document codes and statuses. Guide: Register.

TypeScript
// Changes the type of purchase of a document. In production this changes the real register.
function changePurchaseType(
  portal: PortalClient,
  input: ChangePurchaseTypeInput,
  overrides?: CallOverrides,
): Promise<void>
 
// One purchase as the register holds it, including its current type of purchase.
function fetchPurchaseDocument(
  portal: PortalClient,
  key: PurchaseDocumentKey,
  overrides?: CallOverrides,
): Promise<PurchaseDocument | null>
 
// The official totals of a period by document type and accounting status, including what the SII
// aggregates, such as receipts. Response codes are not looked at, so a month the SII refuses to
// show reads as an empty one.
function fetchRegisterSummary(
  portal: PortalClient,
  input: RegisterSummaryInput,
  overrides?: CallOverrides,
): Promise<RegisterSummary>
 
// Every document of a period, with no XML: the summary per type, then one detail call per row, at
// the same time. This is not the official register. Response codes are not looked at, so a month
// the SII refuses to show reads as an empty one.
function listPeriodDocuments(
  portal: PortalClient,
  input: ListPeriodDocumentsInput,
  overrides?: CallOverrides,
): Promise<PeriodDocuments>
 
// The types of purchase the SII lets a document have.
function listPurchaseTypes(
  portal: PortalClient,
  overrides?: CallOverrides,
): Promise<readonly PurchaseType[]>
 
// Moves the VAT of a document from recoverable to common use. In production this changes the real
// register.
function moveVatToCommonUse(
  portal: PortalClient,
  input: MoveVatInput,
  overrides?: CallOverrides,
): Promise<void>
 
// Moves the VAT of a document from common use back to recoverable: the inverse of
// `moveVatToCommonUse`, with the same rules. Moving it all back leaves `commonUseVat` at 0 and
// `recoverableVat` with the total.
function moveVatToRecoverable(
  portal: PortalClient,
  input: MoveVatInput,
  overrides?: CallOverrides,
): Promise<void>
TypeDescription
ChangePurchaseTypeInputWhat changePurchaseType needs.
ListPeriodDocumentsInputWhat listPeriodDocuments needs.
MoveVatInputWhat the functions that move VAT need: the final amount of each bucket after the change, not a delta. An absent amount goes empty.
PurchaseDocumentKeyWhich purchase of the register.
RegisterSummaryInputWhat fetchRegisterSummary needs.
PeriodDocumentOne document of a period: no time of day and no XML. The field names are not measured, as in PeriodSummaryRow.
PeriodDocumentsThe documents of a period.
PeriodSummaryRowOne row of the summary of a period, per document type and section.
PurchaseDocumentA purchase as the register holds it. The field names are not measured, as in PeriodSummaryRow.
PurchaseTypeA type of purchase the SII lets a document have. Measured.
RcvObjectAn object of an RCV answer, as the SII sent it. Defined as Readonly<Record<string, unknown>>.
RegisterHeaderThe header of the official register. The field names are not measured, as in PeriodSummaryRow. proportionalityFactor is a number from 0 to 1, read also from a text with spaces and a decimal comma (" 1,0000"); a value outside that range is null and stays in raw.
RegisterSummaryThe official register of a period.
RegisterSummaryRowOne row of the official register. The field names are not measured, as in PeriodSummaryRow.

Fields of ChangePurchaseTypeInput

FieldTypeDescription
typenumberDocument type.
folionumberFolio.
periodstringTax period, YYYY-MM.
counterpartyRutstringRUT of the issuer.
companyRut?stringCompany, when it is not the client's.
purchaseTypestringAn id from listPurchaseTypes.

Fields of ListPeriodDocumentsInput

FieldTypeDescription
periodstringPeriod, YYYY-MM.
direction?DocumentDirectionIssued or received documents; issued by default.
companyRut?stringCompany, when it is not the client's.

Fields of MoveVatInput

FieldTypeDescription
typenumberDocument type.
folionumberFolio.
periodstringTax period, YYYY-MM.
counterpartyRutstringRUT of the issuer.
companyRut?stringCompany, when it is not the client's.
commonUseVat?numberFinal common use VAT.
recoverableVat?numberFinal recoverable VAT.

Fields of RegisterSummaryInput

FieldTypeDescription
periodstringPeriod, YYYY-MM.
operationRegisterOperationPurchases or sales.
accountingStatus?AccountingStatusAccounting status; registered by default.
companyRut?stringCompany, when it is not the client's.

Register document codes and statuses#

What the register does with each document code, and which accounting statuses each side can hold. They are data in the package, added in 0.2.0: nothing here calls the SII. Use them when you read the totals of fetchRegisterSummary: which codes subtract, which never reach the register, which the register lists document by document, and where the buyer withholds the VAT. Guide: Register.

TypeScript
import { REGISTER_ACCOUNTING_STATUSES, REGISTER_DOCUMENT_CODES, registerDocumentCode } from 'dte-sdk/portal'
 
registerDocumentCode(61)?.sign // -1: a credit note subtracts from the totals
registerDocumentCode(52)?.inRegister // false: dispatch guides never reach the register
registerDocumentCode(71) // undefined: not one of the 49 codes
REGISTER_DOCUMENT_CODES.length // 49
REGISTER_ACCOUNTING_STATUSES.sale // ['registered']
TypeScript
// The 49 document codes of the purchase and sales register, sorted by code.
const REGISTER_DOCUMENT_CODES: readonly RegisterDocumentCode[]
 
// What the register does with a document code, or `undefined` when the code is not one of the 49.
function registerDocumentCode(code: number): RegisterDocumentCode | undefined
 
// The accounting statuses each side of the register can hold: all four for purchases, only
// `registered` for sales, since no SII source describes other states of a sale.
const REGISTER_ACCOUNTING_STATUSES: Readonly<Record<RegisterOperation, readonly AccountingStatus[]>>
TypeDescription
RegisterDocumentCodeOne document code of the register, with what the register does with it.

Fields of RegisterDocumentCode

FieldTypeDescription
codenumberSII document code, the tax document type number.
namestringOfficial SII label, in Spanish, as the SII's code tables write it.
operationsreadonly RegisterOperation[]Sides of the register where the code appears, purchase before sale; empty when the code is not in the register.
electronicbooleanIssued as a DTE, in the SII XML format. Codes 47 and 48 are not DTEs.
inRegisterbooleanFalse when the code never reaches the register: the dispatch guides 50 and 52. Inferred.
sign1 | -1-1 when the code subtracts from the register's totals (credit notes and decreases), 1 otherwise. Inferred from the F29. The amounts of codes 40, 43 and 103 may arrive negative and carry their own sign.
perDocumentbooleanFalse when the register shows only a monthly summary line for the code, with no document by document detail.
buyerWithholdsVatbooleanThe buyer withholds the VAT (cambio de sujeto). Debit and credit notes tied to a purchase invoice may carry the withholding per document, not per code, so this flag does not cover them.

The codes, by what the catalog says of them

GroupCodes
Purchases and sales29, 30, 32, 33, 34, 40, 43, 45, 46, 55, 56, 60, 61, 108, 901, 904
Sales only35, 38, 39, 41, 47, 48, 101, 102, 103, 104, 105, 106, 109, 110, 111, 112, 500, 501, 902, 903, 905, 906, 907, 919, 920, 922, 924
Purchases only909, 910, 911, 914
Outside the register (inRegister: false)50, 52
Subtract from the totals (sign: -1)60, 61, 106, 112, 501, 922
Summary line only (perDocument: false)35, 38, 39, 41, 47, 48, 105, 500, 501, 906, 919, 920, 922, 924
The buyer withholds the VAT (buyerWithholdsVat: true)29, 45, 46
DTEs (electronic: true)33, 34, 39, 41, 43, 46, 52, 56, 61, 110, 111, 112

The catalog follows the SII's public sources: the "Información Electrónica de Compras y Ventas" format v3.0 (the code tables of each side and their "solo en resumen" column), the register's upload formats for purchases, sales and the sales summary, its FAQ, Resolución Exenta SII N° 12 of 2011 (the buyer of a factura de inicio withholds the whole VAT) and the F29 instructions (credit notes subtract). What the SII does not state, the catalog infers, and its JSDoc says so: the dispatch guides 50 and 52 appear in no code table of the register, so they are marked as outside it; the sign of each code is the F29's, not one the register states; code 906 is summary only; and codes 500 and 501 come from the older book format. It has not been checked against a real register with documents in it yet.

The four accounting statuses: registered is a document in the register; pending, a purchase still missing the buyer's receipt acknowledgement; claimed, a purchase claimed within 8 days, which cannot move to another status; notIncluded, a purchase the taxpayer chose to leave out.

MIPYME backup#

Downloads the XML of the issued or received documents of a date range from the MIPYME backup. Guide: Register.

TypeScript
// Downloads the XML of the issued or received documents of a date range from the MIPYME backup,
// splitting the range until each piece fits the 20 documents the SII allows per download.
function downloadMipymeBackup(
  portal: PortalClient,
  input: MipymeBackupInput,
  overrides?: CallOverrides,
): Promise<MipymeBackup>
TypeDescription
MipymeBackupWhat a backup downloaded.
MipymeBackupChunkOne piece of a backup.
MipymeBackupInputWhat downloadMipymeBackup needs.
MipymeDownloadedChunkOne downloaded piece, as onChunk receives it.

Fields of MipymeBackupInput

FieldTypeDescription
fromstringFirst day, YYYY-MM-DD.
tostringLast day, YYYY-MM-DD.
direction?DocumentDirectionIssued or received documents; issued by default.
type?numberOnly this document type; all by default.
attempts?numberTries per listing and per download; 3 by default.
onChunk?(chunk: MipymeDownloadedChunk) => Promise<void> | voidReceives each piece as it arrives, so a long history does not stay in memory: then the result holds no xml.
companyRut?stringCompany, when it is not the client's.

Activity verification#

To issue electronic documents with VAT, the SII asks for more than being a VAT taxpayer: the company needs a positive on-site verification of its activities, or one in progress (the SII's requirements). Without it, a CAF request for a type that needs it is refused with activityVerificationPending. unstable_fetchActivityVerification reads that verification from the SII's "Consulta estado de verificación y acreditación", and listAccreditationDocuments the catalog of the documents that accredit an activity, from the same app. Both run on the same session as the rest of the portal and were added in 0.3.0. Both read production whatever the client's environment, because the app exists only there. Guide: Portal.

unstable_ means the shape may change in any release, a patch included. unstable_fetchActivityVerification has been read against the real SII on 8 November 2026, for a company whose verification was pending, and on 9 November, for a conditioned verification pending accreditation. The SII's codes for an approved verification are not known yet, so nothing in the result says by itself whether the company may issue documents with VAT. Once an approved verification has been read, the function becomes fetchActivityVerification. Until then, pin the version and read the changelog before every upgrade, patches too. listAccreditationDocuments is not marked unstable.

TypeScript
import { listAccreditationDocuments, unstable_fetchActivityVerification } from 'dte-sdk/portal'
 
const { requests, messages } = await unstable_fetchActivityVerification(portal)
requests.length // 0 when the company never asked for the verification
requests[0]?.status // 'PAC', described as 'PENDIENTE DE ACREDITACIÓN'
requests[0]?.preliminaryResult // 'CONDICIONADA'
requests[0]?.finalResult // null while there is none
requests[0]?.requestedOn // 'YYYY-MM-DD'
messages.filter((message) => message.blocking) // the messages the SII's own page stops at
 
const documents = await listAccreditationDocuments(portal)
documents[0] // { category: 'general', code: 1, description: '…' }
TypeScript
// Unstable: its shape may change in any release, a patch included. The company's activity
// verification, the SII's "Consulta estado de verificación y acreditación". It sends the company's
// RUT, not the session's, and a request of another RUT throws instead of passing as the company's.
// It reads production whatever the client's environment. Officials, comments and the address
// never come out.
function unstable_fetchActivityVerification(
  portal: PortalClient,
  input?: ActivityVerificationInput,
  overrides?: CallOverrides,
): Promise<ActivityVerification>
 
// The kinds of document the SII takes to accredit an activity, as the SII orders them: a general
// list and a specific one, whose codes repeat. It reads production whatever the client's
// environment.
function listAccreditationDocuments(
  portal: PortalClient,
  overrides?: CallOverrides,
): Promise<readonly AccreditationDocument[]>
TypeDescription
ActivityVerificationInputWhat unstable_fetchActivityVerification needs.
ActivityVerificationThe verification of a company's activities. Officials, comments, the address and the procedure's internals are left out on purpose, and there is no raw. Unstable.
ActivityVerificationRequestOne request for the verification of the company's activities. Unstable.
ActivityVerificationMessageA message the SII adds to the verification.
AccreditationDocumentA kind of document the SII takes to accredit an activity. The code repeats across categories: the pair is the key.
AccreditationDocumentCategoryWhich list a document that accredits an activity belongs to. Defined as 'general' | 'specific'.

Fields of ActivityVerificationInput

FieldTypeDescription
companyRut?stringCompany, when it is not the client's.

Fields of ActivityVerification

FieldTypeDescription
requestsreadonly ActivityVerificationRequest[]The requests; empty when the company never asked for the verification.
messagesreadonly ActivityVerificationMessage[]The SII's messages.

Fields of ActivityVerificationRequest

FieldTypeDescription
numbernumber | nullNumber of the verification.
kindstring | nullKind of verification, such as VIA.
reasonstring | nullWhy it was opened, as the SII words it.
preliminaryResultstring | nullPreliminary result, such as CONDICIONADA.
finalResultstring | nullFinal result; null while there is none.
statusstring | nullStatus code, such as PAC.
statusDescriptionstring | nullWhat the status means, such as PENDIENTE DE ACREDITACIÓN.
requestedOnstring | nullDate of the request, YYYY-MM-DD.
accreditationDeadlinestring | nullLast day to accredit the activity, YYYY-MM-DD; null when there is none.
procedureStatusstring | nullStatus of the accreditation procedure, as the SII words it.
hasCertificatebooleanTrue when the SII has issued the verification's certificate.

Fields of ActivityVerificationMessage

FieldTypeDescription
textstringThe message.
blockingbooleanTrue when the SII's own page stops at it.

Fields of AccreditationDocument

FieldTypeDescription
categoryAccreditationDocumentCategory | nullThe category; null for one dte-sdk does not know.
codenumber | nullCode within the category.
descriptionstring | nullName of the document.

What they throw:

  • An SII error code in the answer throws SII_PORTAL_REJECTED with rejection: 'activityVerificationRefused', and the SII's words in details.portalMessage when it said something.
  • A request whose RUT is not the company's throws SII_PORTAL_UNEXPECTED_PAGE with step: 'otherTaxpayer', and nothing of it is returned. The SII's own page shows the verification of whoever logged in; this function sends the company's RUT, and the SII answered a session of the company's legal representative.
  • An answer with no verification or no catalog in it throws SII_PORTAL_UNEXPECTED_PAGE. With no company on the call or the client, unstable_fetchActivityVerification throws MISSING_FIELD, and with an invalid one, INVALID_RUT. Session and transport codes are as elsewhere in the portal.

Like the reads of the register, each call to the SII's app is one request unless you opt in with retry, while the login and the visit to the app keep their retries. A read that meets an expired session or an unreadable page starts over once with a fresh session.

Folio registry#

Local control of folios: which were reserved, sent and annulled. createFolioRegistry works over a store you provide; createMemoryFolioRegistry keeps it in memory, and createDirectoryFolioRegistry (from dte-sdk/node) keeps it in a JSON file. Guide: Portal.

TypeScript
// First 12 hex characters of the SHA-256 of a CAF file, to tell apart two files for one range.
function cafFingerprint(xml: string): string
 
// A registry over a store. Calls run one after another inside this process, each reading the
// ledger fresh; several processes need a store or a registry of their own that takes care of it.
function createFolioRegistry(store: FolioLedgerStore, now?: () => Date): FolioRegistry
 
// A registry that lives in memory: for tests and short runs.
function createMemoryFolioRegistry(now?: () => Date): FolioRegistry
TypeDescription
FolioLedgerStoreWhere a ledger is kept.
FolioRegistryLocal control of folios: which were reserved, sent and annulled. A service with its own database implements these functions with its own transactions; the rest build one with createFolioRegistry.
FolioEntryOne entry of the ledger.
FolioLedgerThe whole registry as one JSON-friendly value.
FolioScopeThe folios of one CAF for one company in one environment.
FolioSentRecordWhat is recorded when a folio goes to the SII.
FolioStatsTotals of a company and document type.
ReserveOptionsHow a folio is chosen.

Fields of FolioLedgerStore

FieldTypeDescription
load() => Promise<FolioLedger | null>The stored ledger, or null.
save(ledger: FolioLedger) => Promise<void>Replaces the stored ledger.

Fields of FolioRegistry

FieldTypeDescription
reserve(scope: FolioScope, options?: ReserveOptions) => Promise<number>Reserves the next free folio: after the last one reserved, or from the lowest reserved and not sent; never one that is used or annulled.
markSent( scope: FolioScope, folio: number, sent?: { readonly trackId?: string; readonly sentAt?: string; readonly extra?: Readonly<Record<string, unknown>> }, ) => Promise<void>Records a folio as sent.
markAnnulled(scope: FolioScope, folios: readonly number[]) => Promise<void>Records folios as annulled at the SII.
release(scope: FolioScope, folios: readonly number[]) => Promise<void>Gives folios back.
remaining(scope: FolioScope) => Promise<number>Folios of the range still unused.
stats(query: { readonly companyRut: string readonly type: number readonly environment?: Environment }) => Promise<FolioStats>Totals of a company and type.

Fields of FolioStats

FieldTypeDescription
totalEntriesnumberCAFs tracked.
totalUsednumberFolios used.
totalSentnumberFolios sent.
rangesreadonly { readonly from: number; readonly to: number; readonly environment: Environment; readonly cafFingerprint: string | null; readonly used: number; readonly sent: number; readonly remaining: number }[]One per entry of the registry, that is per CAF file: its range, the environment of its scope and the cafFingerprint of the file it counts (null when its scope has none), and its folios used, sent and still unused. Two files of one range, or one range in both environments, are two entries, told apart by these two fields. A FolioRegistry of your own returns both in each range.

Fields of ReserveOptions

FieldTypeDescription
lowestFree?booleanHand out the lowest folio of the range that is neither used nor annulled, wherever the used ones lie: a folio given back, or left free below a folio marked sent, goes out again.

Certification: the deterministic half#

Everything that needs no portal: parse the SII test-set text, plan what each set issues, allocate folios, issue the documents and build the books. Nothing here sends anything; the runner does. Guide: Test sets.

Catalogs#

TypeScript
// Kinds of set the SII test-set text can hold, by their English name.
const TEST_SET_KINDS: {
  readonly basic: "basic"
  readonly exempt: "exempt"
  readonly guide: "guide"
  readonly purchase: "purchase"
  readonly export: "export"
  readonly settlement: "settlement"
  readonly salesBook: "salesBook"
  readonly purchaseBook: "purchaseBook"
  readonly exemptPurchaseBook: "exemptPurchaseBook"
  readonly guideBook: "guideBook"
  readonly other: "other"
}
 
// Names of the sets and books as the certification portal lists them (`pe_avance2`).
const TEST_SET_PORTAL_NAMES: Readonly<Partial<Record<TestSetKind, string>>>
 
// The reference document type every document of a test set carries on its first reference line.
const TEST_SET_REFERENCE_TYPE = 'SET'
 
// The counterparty written on every entry of the certification purchase books: the SII's own RUT
// and a placeholder name. The SII accepts it, it exists as a taxpayer and it is nobody's personal
// data.
const CERTIFICATION_COUNTERPARTY: { readonly rut: "60803000-K"; readonly name: "Razon Social" }
TypeDescription
TestSetKindUnion of the set kinds.

Test set text#

TypeScript
// Parses the text of the SII test set: sets, their cases with items and references, the supplier
// documents of the purchase-book sets and the proportionality factor.
function parseTestSetText(text: string): readonly TestSet[]
TypeDescription
TestSetOne set of the test-set text.
TestCaseOne case of a set: one document to issue.
TestCaseItemOne item row of a case.
TestBookDocumentOne supplier document of a purchase-book set.

Plan#

TypeScript
// The cases each set issues, with the folios every document type needs, from the parsed sets. For
// each kind the last set of the text wins.
function planCertificationSets(sets: readonly TestSet[]): CertificationPlan
TypeDescription
CertificationPlanWhat the certification issues, per set kind; a kind the text lacks is absent. The sales and guide books have no plan: they come from the issued basic and guide sets.
BasicSetPlanThe basic set: invoices 33, credit notes 61, debit notes 56.
ExemptSetPlanThe exempt set: invoices 34, credit notes 61, debit notes 56; every line exempt.
GuideSetPlanThe guide set: one 52 per case.
PurchaseSetPlanThe purchase set: one 46, at most one 61 and one 56.
PurchaseBookPlanA purchase-book set: the supplier documents and the proportionality factor (0.6 when the set gives none).
PlannedInvoiceAn invoice case (33, 34 or 46).
PlannedNoteA credit or debit note case.
PlannedGuideA dispatch guide case.
PlannedItemAn item of a case, ready to become a document line.
SetFoliosFolios each document type needs. Defined as Readonly<Record<number, number>>.

Folio allocator#

TypeScript
// A folio source over one or several CAFs: one counter per CAF, the first CAF of the type with a
// folio left wins, a folio is never given twice, and the CAF returned is the one whose range holds
// the folio, so it stamps with its own key.
function createFolioAllocator(cafs: readonly Caf[], options?: FolioAllocatorOptions): FolioSource
TypeDescription
FolioSourceWhere the next folio of a type comes from, with the CAF that stamps it. The in-memory allocator below is one implementation; the runner may implement it with the folio registry.
FolioAllocatorOptionsOptions of createFolioAllocator.

Fields of FolioAllocatorOptions

FieldTypeDescription
usedFolios?readonly { readonly type: number; readonly folio: number }[]Folios already used; the allocator starts after the highest used one of each CAF.

Issuing the sets#

TypeScript
// Issues every document of a set plan and signs its envelope.
function issueTestSet(plan: IssuableSetPlan, options: IssueSetOptions): Promise<IssuedSet>
 
// `SetDTE/@ID` of every certification envelope.
const TEST_SET_ENVELOPE_ID = 'DTE_SetDoc'
TypeDescription
IssueSetOptionsWhat issuing a set needs.
IssuableSetPlanThe plans issueTestSet accepts. Defined as BasicSetPlan | ExemptSetPlan | GuideSetPlan | PurchaseSetPlan.
IssuedCaseOne issued document of a set.
IssuedSetAn issued set: its documents in issue order and the signed envelope that carries them.

Fields of IssueSetOptions

FieldTypeDescription
issuerIssuerInputThe issuer, as for a document.
receiverReceiverInputThe customer every document names; purchase invoices and internal transfers name the issuer instead.
certificateCertificateThe signing certificate.
foliosFolioSourceWhere folios and their CAFs come from.
resolution{ readonly number: number; readonly date: string }The resolution of the certification environment: number 0 and its date.
now?() => DateClock, read once per document and once for the envelope.

Fields of IssuedCase

FieldTypeDescription
caseIdstringId of the case, for example 4256-1.
typeDocumentTypeDocument type.
folionumberFolio taken for the document.
documentSignedDocumentThe issued and signed document.

Fields of IssuedSet

FieldTypeDescription
kind'basic' | 'exempt' | 'guide' | 'purchase'Set kind.
attentionNumberstringNUMERO DE ATENCION of the set.
casesreadonly IssuedCase[]The issued documents, in issue order.
envelopeSignedEnvelopeThe signed envelope that carries the documents.

Simulation#

TypeScript
// Issues every case of the four set plans again with fresh folios, in the order basic, exempt,
// guide and purchase, and signs one envelope with all of them.
function issueSimulation(
  plan: CertificationPlan,
  options: IssueSetOptions,
): Promise<IssuedSimulation>
TypeDescription
IssuedSimulationThe simulation: every case of the four sets issued again, in one envelope.

Books of the sets#

TypeScript
// The sales book of the certification: only the basic set's invoices and notes, dated the 15th of
// the period, with the customer as counterparty, every amount present (0 when absent) and the VAT
// rate on every line.
function createCertificationSalesBook(
  set: IssuedSet | SalesBookSource,
  input: CertificationSalesBookInput,
): SignedPurchaseSalesBook
 
// A purchase book of the certification from a purchase-book set: one line per supplier document
// with the SII's placeholder counterparty, the VAT at 19 % of the affected amount, common-use VAT,
// non-recoverable VAT for free deliveries, the withholding of a purchase invoice, the referenced
// folio of a note from its observation, and, for the exempt taxpayers' book, non-recoverable VAT
// on every affected line, the paper exempt invoice as type 32 and notes inheriting the amounts of
// the document they reference.
function createCertificationPurchaseBook(
  plan: PurchaseBookPlan,
  input: CertificationBookInput,
): SignedPurchaseSalesBook
 
// The guide book of the certification: only the guide set's guides, with their transfer reason and
// issue date; by position the second guide carries `Operacion` 1 and the third is voided
// (`Anulado` 2, total 0 and nothing else), unless `caseFlags` says otherwise; a sale carries the
// customer, the net, the VAT rate and the VAT; every guide its total.
function createCertificationGuideBook(
  set: IssuedSet | GuideBookSource,
  input: CertificationGuideBookInput,
): SignedGuideBook
TypeDescription
CertificationBookInputWhat every certification book needs.
CertificationSalesBookInputOptions of createCertificationSalesBook.
CertificationGuideBookInputOptions of createCertificationGuideBook.
BookReceiverThe customer written on the sales and guide books.
GuideBookCaseFlagHow a guide enters the guide book. Defined as 'normal' | 'modified' | 'voided'.
BookCaseTotalsThe totals of one issued document, as the books read them.
SalesBookCaseOne document of the sales book: the issued set's case, or what a run kept of it.
GuideBookCaseOne guide of the guide book: the issued set's case, or what a run kept of it.
SalesBookSourceA sales-book source that is not the issued set itself: its kind and cases, as a resumed run holds them.
GuideBookSourceA guide-book source that is not the issued set itself.

Fields of CertificationBookInput

FieldTypeDescription
periodstringTax period YYYY-MM; the runner chooses it against the portal history.
issuerRutstringCompany the book belongs to.
senderRutstringAuthorized sender, normally the certificate holder.
resolution{ readonly number: number; readonly date: string }Resolution number (0 in certification) and date.
certificateCertificateThe signing certificate.
now?() => DateClock for the book id and signature timestamp.
submission?'total' | 'adjustment'total (default) or adjustment, for a period the SII already holds; any of the three books can adjust.
previousTotals?readonly BookTotals[]Period totals of the earlier submissions, carried forward on an adjustment of the sales or purchase book; the guide book ignores them.

Fields of CertificationSalesBookInput

FieldTypeDescription
periodstringTax period YYYY-MM; the runner chooses it against the portal history.
issuerRutstringCompany the book belongs to.
senderRutstringAuthorized sender, normally the certificate holder.
resolution{ readonly number: number; readonly date: string }Resolution number (0 in certification) and date.
certificateCertificateThe signing certificate.
now?() => DateClock for the book id and signature timestamp.
submission?'total' | 'adjustment'total (default) or adjustment, for a period the SII already holds; any of the three books can adjust.
previousTotals?readonly BookTotals[]Period totals of the earlier submissions, carried forward on an adjustment of the sales or purchase book; the guide book ignores them.
receiverBookReceiverThe customer written on every line.
creditNoteSign?'positive' | 'negative'Credit notes as positive amounts (default) or negative.

Fields of CertificationGuideBookInput

FieldTypeDescription
periodstringTax period YYYY-MM; the runner chooses it against the portal history.
issuerRutstringCompany the book belongs to.
senderRutstringAuthorized sender, normally the certificate holder.
resolution{ readonly number: number; readonly date: string }Resolution number (0 in certification) and date.
certificateCertificateThe signing certificate.
now?() => DateClock for the book id and signature timestamp.
submission?'total' | 'adjustment'total (default) or adjustment, for a period the SII already holds; any of the three books can adjust.
previousTotals?readonly BookTotals[]Period totals of the earlier submissions, carried forward on an adjustment of the sales or purchase book; the guide book ignores them.
receiverBookReceiverThe customer written on every guide line.
notificationFolio?numberFolioNotificacion; 3 by default.
caseFlags?readonly GuideBookCaseFlag[]One flag per guide, by position; by default the second is modified and the third voided.

Certification: the portal half#

The portal operations of the certification (download the set, declare progress, read progress, advance the stage, book history, declaration of compliance), the store that keeps the state of a run, the runtime every step shares, and one function per step. The runner chains them. Guide: Runner.

Catalogs#

TypeScript
// The sets in the order they are sent.
const SET_KEYS: readonly SetKey[] = ['basic', 'guide', 'exempt', 'purchase']
 
// The books in the order they are sent.
const BOOK_KEYS: readonly BookKey[] = ['purchaseBook', 'salesBook', 'guideBook', 'exemptPurchaseBook']
 
// The books every certification must get approved.
const MANDATORY_BOOK_KEYS: readonly BookKey[] = ['purchaseBook', 'salesBook', 'guideBook']
 
// The file name each book travels under in the upload, as the SII expects it.
const BOOK_FILE_NAMES: Readonly<Record<BookKey, string>> = {
  salesBook: 'LibroCV.xml',
  purchaseBook: 'LibroCV.xml',
  exemptPurchaseBook: 'LibroCVExentos.xml',
  guideBook: 'LibroGuia.xml',
}
 
// The artefact name of each book.
const BOOK_ARTEFACT_NAMES: Readonly<Record<BookKey, string>> = {
  salesBook: 'libro-ventas.xml',
  purchaseBook: 'libro-compras.xml',
  exemptPurchaseBook: 'libro-compras-exentos.xml',
  guideBook: 'libro-guias.xml',
}
 
// The artefact name of each set envelope.
const SET_ARTEFACT_NAMES: Readonly<Record<SetKey, string>>
 
// The optional sets ticked when downloading the test set: guides (03), exempt invoices (06), the
// sales (07), purchase (08) and guide (09) books, the purchase book for exempt taxpayers (15) and
// the purchase set (72).
const DEFAULT_OPTIONAL_SETS: readonly string[] = ['SET03', 'SET06', 'SET07', 'SET08', 'SET09', 'SET15', 'SET72']
 
// The stages of a certification, in order, as the runner keeps them.
const CERTIFICATION_STAGES: readonly [
  "testSets", "books", "simulation", "exchange", "printedSamples", "compliance", "done"
]
 
// The words the portal uses for a stage (`pe_avance6`, "paso <b>…</b>"), from the latest stage
// down. Any wording past the exchange lands in `printedSamples`: the compliance declaration tells
// whether the samples are approved.
const PORTAL_STAGE_WORDS: readonly { readonly stage: CertificationStage; readonly words: readonly string[] }[]
 
// The names of the progress events the steps emit.
const CERTIFICATION_STEPS: readonly [
  "SETS_DOWNLOADING", "SETS_LOADED", "SETS_REGENERATED", "CAF_REQUESTING", "CAF_OK", "SET_START",
  "SET_OK", "SET_ERROR", "SETS_DECLARING", "SETS_DECLARED", "POLLING", "SETS_APPROVED",
  "SETS_REJECTED", "BOOKS_START", "BOOK_SKIPPED", "BOOK_SENDING", "BOOK_OK", "BOOK_ERROR",
  "BOOK_PERIOD_RETRY", "BOOKS_DECLARING", "BOOKS_DONE", "ADVANCE_WAITING", "ADVANCE_DONE",
  "SIM_START", "SIM_SENDING", "SIM_OK", "SIM_DECLARING", "SIM_DONE", "INTERCAMBIO_START",
  "INTERCAMBIO_DESCARGADO", "INTERCAMBIO_DONE", "MUESTRAS_UPLOADING", "MUESTRAS_DONE", "CERT_DONE",
  "CERT_ERROR"
]
TypeDescription
SetKeyThe four sets the certification issues. Defined as 'basic' | 'exempt' | 'guide' | 'purchase'.
BookKeyThe books of the certification. Defined as 'salesBook' | 'purchaseBook' | 'exemptPurchaseBook' | 'guideBook'.
DeclarationKeyEvery row the declaration form (pe_avance2) can hold, by key. Defined as SetKey | BookKey | 'simulation' | 'export1' | 'export2' | 'settlement'.
CertificationStageUnion of the stages. Defined as (typeof CERTIFICATION_STAGES)[number].
CertificationStepUnion of the progress event names. Defined as (typeof CERTIFICATION_STEPS)[number].

Declarations and progress#

TypeScript
// Downloads the test set from `pe_generar`. Without a session in the cache the progress page is
// read first, which logs in and lets the SII refresh the application; whatever that read answers,
// the download goes on.
function downloadTestSet(
  portal: PortalClient,
  input?: DownloadTestSetInput,
  overrides?: CallOverrides,
): Promise<DownloadedTestSet>
 
// Declares the track id and date of envelopes on `pe_avance2`, posted to `pe_avance3`. The form is
// read for its hidden fields and for the index of each row's field, found by the row's label (the
// indexes move as sets are approved).
function declareProgress(
  portal: PortalClient,
  input: DeclareProgressInput,
  overrides?: CallOverrides,
): Promise<DeclarationResult>
 
// Reads the progress page: the entry sequence, `pe_avance5`, then `pe_avance6` with the company.
// No page on the way is searched for a refusal, and a page that names no stage and no state is
// still an answer.
function readProgress(
  portal: PortalClient,
  input?: { readonly companyRut?: string; },
  overrides?: CallOverrides,
): Promise<ProgressReport>
 
// Asks the portal to move the application to its next stage: `pe_avance4` with `TOTREG` and `PASO`
// as `pe_avance2` holds them (`PASO` changes with the stage; a fixed value makes the SII answer
// "ya se encuentra en el paso"), with `pe_avance2` as referer.
function advanceStage(
  portal: PortalClient,
  input?: { readonly companyRut?: string; },
  overrides?: CallOverrides,
): Promise<AdvanceResult>
 
// Lists the books the SII holds for a year (`QEstLibro`, after `DTEauth?7` binds the session to
// that CGI). Every period listed is occupied for a new total submission.
function listBookHistory(
  portal: PortalClient,
  input: { readonly year: number; readonly companyRut?: string; },
  overrides?: CallOverrides,
): Promise<BookHistory>
 
// The declaration of compliance: `pe_avance7`, `pe_avance8` with the company, once more with every
// input of the page when the portal asks to continue (`OK_MSG`), then the `pe_avance9` form with
// every input of the page, `Salir` apart, every `OPCn` at `S` and `CONFIRMAR`, both posts with
// `pe_avance8` as referer.
function declareCompliance(
  portal: PortalClient,
  input?: { readonly companyRut?: string; },
  overrides?: CallOverrides,
): Promise<ComplianceResult>
TypeDescription
DownloadTestSetInputInput of downloadTestSet.
DownloadedTestSetWhat downloadTestSet read. Downloading generates the set: the SII assigns the cases anew, so anything sent for an earlier set is void.
DeclarationEntryOne envelope to declare: its track id and the date it was sent, YYYY-MM-DD in Chile.
DeclarationEntriesThe entries of one declaration, by row key. Defined as Readonly<Partial<Record<DeclarationKey, DeclarationEntry>>>.
DeclareProgressInputInput of declareProgress.
DeclarationOutcomeHow a declaration ended, in a word. Defined as | 'accepted' | 'inReview' | 'contentErrors' | 'allRejected' | 'notSaved' | 'inconsistent' | 'declined' | 'failed'.
DeclarationResultWhat declareProgress did and what the portal answered, with the facts the declaration loop decides on.
ProgressReportThe progress of the application as pe_avance6 shows it.
AdvanceResultWhat advanceStage got. Defined as AdvanceAnswer.
BookHistoryWhat listBookHistory read for one year.
ComplianceResultWhat declareCompliance did.
SetGenerationStateOne row of the set table of pe_generar1: a set and whether the company obtained it.
OptionalSetOptionOne optional set the page offers as a checkbox.
SetGenerationPageWhat pe_generar1 shows before a set is generated.
DeclarationFormThe pe_avance2 form as the declaration reads it: only what a quoted attribute gives.
DeclarationAnswerWhat a pe_avance3 answer says, read on the page as it came.
DeclarationVerificationWhat the re-read form says of the rows just declared.
AdvanceAnswerWhat pe_avance4 answered.
ItemStateThe state of one set or book on the progress page. Defined as | 'approved' | 'inReview' | 'rejected' | 'objections' | 'pending' | 'annulled' | 'inconsistent' | 'unknown'.
ProgressPageThe progress page (pe_avance6) read.
BookHistoryEntryOne book the SII holds, as QEstLibro lists it.
ComplianceFormThe pe_avance9 form, ready to post: its action and its fields.

Fields of DownloadTestSetInput

FieldTypeDescription
companyRut?stringCompany RUT; the client's by default.
optionalSets?readonly string[]Optional sets to tick, SETnn; DEFAULT_OPTIONAL_SETS by default. Only those the page offers are sent.
download?booleanFalse to read the state table only, without generating a set.
previousAttentionNumber?stringThe attention number of the set in hand, to tell a regenerated set.

Fields of DeclareProgressInput

FieldTypeDescription
entriesDeclarationEntriesThe envelopes to declare.
companyRut?stringCompany RUT; the client's by default.

Store#

TypeScript
// A fresh state for a company.
function createCertificationState(companyRut: string, now?: Date): CertificationState
 
// A store in memory: for tests and short runs.
function createMemoryCertificationStore(): CertificationStore
 
// Throws unless the name is a relative path of safe segments: no empty segment, no `.`, no `..`,
// no absolute path, nothing outside `[A-Za-z0-9._-]`.
function assertArtefactName(name: string): void
 
// A store in a directory: `state.json` written atomically (temp file and rename), the artefacts as
// files, a `/` in a name as a sub-directory.
function createDirectoryCertificationStore(
  options: DirectoryCertificationStoreOptions,
): CertificationStore
TypeDescription
CertificationStateThe whole state of a certification run: what was downloaded, obtained, sent, declared and approved. A plain JSON value the store keeps between runs; the runner resumes from it.
CertificationStoreWhere the state and the artefacts of a run live. The names are relative paths with / as separator; a service may back this with its own storage.
SentEnvelopeAn envelope sent to the SII: its track id, the Chile date it was sent (what the declaration takes), the instant.
SentCaseOne case of a sent set.
SentSetA set sent, with its cases.
SentBookA book sent: its period, its submission kind, and whether the portal approved it.
BooksStateWhat the books phase keeps.
AccumulatedTotalsThe period totals accumulated per period and operation, for adjustment submissions. Defined as Readonly< Record<string, { readonly purchase?: readonly BookTotals[]; readonly sale?: readonly BookTotals[] }> >.
EnvelopeDiagnosisWhat the SOAP status of an envelope said, kept for diagnosis.
DirectoryCertificationStoreOptionsOptions of createDirectoryCertificationStore.

Fields of CertificationStore

FieldTypeDescription
load() => Promise<CertificationState | null>The stored state, or null.
save(state: CertificationState) => Promise<void>Replaces the stored state.
writeArtefact(name: string, content: string) => Promise<void>Writes an artefact, replacing it.
readArtefact(name: string) => Promise<string | null>Reads an artefact, or null.
listArtefacts() => Promise<readonly string[]>Every artefact name, sorted.

Fields of DirectoryCertificationStoreOptions

FieldTypeDescription
dirstringThe directory of state.json and the artefacts; created on first use. It holds CAF private keys: keep it out of version control.

Runtime#

TypeScript
// What the run fills in for an issuer that leaves it out: the line of business, the activity code,
// the commune and the city. The RUT, the name and the address have no default.
const DEFAULT_CERTIFICATION_ISSUER: Readonly<{ businessActivity: "ACTIVIDADES DE PROGRAMACION INFORMATICA"; activityCode: 620200...
 
// The test receiver the run uses when none is given.
const DEFAULT_CERTIFICATION_RECEIVER: ReceiverInput
TypeDescription
CertificationDependenciesWhat every step needs: the clients, the store, the registry, the company and the clock.
CertificationIssuerInputThe issuer as the run takes it: the line of business and the commune may be left out.
CertificationProgressEventThe progress events the steps emit, with their step names.
PollingLabelWhat a POLLING event waits for. Defined as 'sets' | 'declaration' | 'books' | 'simulation'.
StepResult<Outcome extends string>What a step returns: the state it saved, how it ended, and a word or sentence on why.

Fields of CertificationDependencies

FieldTypeDescription
portalPortalClientThe portal client on the certification environment.
siiSiiClientThe SII client on the certification environment.
storeCertificationStoreWhere the state and the artefacts live.
registryFolioRegistryThe folio registry.
issuerCertificationIssuerInputThe company that certifies; what it leaves out takes the defaults of DEFAULT_CERTIFICATION_ISSUER.
receiver?Partial<ReceiverInput>The receiver of the documents of the run; the test receiver of DEFAULT_CERTIFICATION_RECEIVER by default, field by field.
certificateCertificate
resolution?{ readonly number?: number; readonly date?: string }The resolution of the certification environment; number 0 and today's UTC date by default.
now?() => DateClock; dates are Chile dates of it.
sleep?(ms: number) => Promise<void>Wait function; a real timer by default.
onProgress?(event: CertificationProgressEvent) => voidProgress events.
contact?ExchangeContactThe contact the exchange answers name, when any.

Fields of CertificationIssuerInput

FieldTypeDescription
rutstring
businessNamestringLegal/business name (max 100).
activityCode?numberSII economic activity code.
phone?stringPhone.
email?stringEmail.
branch?stringBranch name (max 20).
siiBranchCode?numberSII branch code (1-999999999).
addressstringStreet address (max 70).
city?stringCity (max 20); defaults to the commune.
salespersonCode?stringSalesperson code.
businessActivity?stringLine of business; ACTIVIDADES DE PROGRAMACION INFORMATICA by default.
commune?stringCommune; Santiago by default.

Fields of StepResult

FieldTypeDescription
stateCertificationState
outcomeOutcome
detail?string

Steps#

TypeScript
// Downloads the test set, parses it, plans the sets and keeps the text and the plan as artefacts.
// Downloading generates the set anew at the SII, so a run that already had a plan starts over:
// everything sent is void.
function obtainTestSet(
  deps: CertificationDependencies,
  state: CertificationState,
  options?: { readonly optionalSets?: readonly string[]; },
): Promise<StepResult<"loaded" | "regenerated">>
 
// Sends one test set: issues it with the folios of the state's CAFs through the registry, keeps
// the envelope and every document as artefacts, uploads it, marks the folios sent whatever
// happened, and records the track id and the Chile date of the send.
function sendTestSet(
  deps: CertificationDependencies,
  state: CertificationState,
  options: { readonly kind: SetKey; },
): Promise<StepResult<"sent">>
 
// Declares the sets sent so far with today's date, with the declaration loop; the outcome and any
// diagnosis go to the state.
function declareTestSets(
  deps: CertificationDependencies,
  state: CertificationState,
): Promise<DeclarationStepResult>
 
// Waits for the sent sets to be approved: 5 attempts 10 s apart, sleeping first, reading the
// progress page. A read that fails only uses up its attempt.
function waitForTestSetsApproval(
  deps: CertificationDependencies,
  state: CertificationState,
): Promise<StepResult<"approved" | "rejected" | "timedOut">>
 
// Asks the portal for the next stage after the books: the progress page is read, up to 30 times 10
// s apart while it cannot be read; on the first page that reads the advance is asked for at once,
// whatever the page says of the books (the portal decides); then the page is read again for the
// stage, and the state's stage moves to the portal's when that is later.
function advanceToNextStage(
  deps: CertificationDependencies,
  state: CertificationState,
): Promise<StepResult<"advanced" | "unchanged" | "failed" | "timedOut">>
 
// Sends the simulation: fresh CAFs for one folio per case (never the sets' CAFs), every case of
// the four sets issued again in one envelope, the envelope and the documents kept as artefacts,
// the upload, the folios marked sent whatever happened, and the track id with the Chile date of
// the send.
function sendSimulation(
  deps: CertificationDependencies,
  state: CertificationState,
): Promise<StepResult<"sent">>
 
// Declares the simulation, unless the progress page names the exchange as the step the application
// is at: a later step is declared like any other, and so is a page that cannot be read.
function declareSimulation(
  deps: CertificationDependencies,
  state: CertificationState,
): Promise<DeclarationStepResult<DeclarationOutcome | "skipped">>
 
// Waits for the simulation: 30 polls 10 s apart of the progress page, polling first. A read that
// fails only uses up its attempt.
function waitForSimulationApproval(
  deps: CertificationDependencies,
  state: CertificationState,
): Promise<StepResult<"done" | "confirmed" | "rejected" | "timedOut">>
 
// The end of the certification: one more request to advance the stage, then the declaration of
// compliance.
function declareComplianceFinal(
  deps: CertificationDependencies,
  state: CertificationState,
): Promise<StepResult<"declared" | "blocked">>

Folios step#

TypeScript
// Makes sure the run holds the folios each type needs. The CAFs in hand first: an expired one is
// skipped, folios of this run the SII never received are given back, and folios the SII already
// received are marked used so they are skipped. Every CAF obtained is saved in the state at once.
// Still short it throws `FOLIO_OUT_OF_RANGE` or, when the batches stopped on a failure and not on
// the SII's answer, that failure's code. A re-obtaining or an annulment cut short by a failure ends
// the step with that failure's code too, once what it brought and was kept, or what it annulled, is
// in the state. Only a rationing refusal leads to annulling: a later batch refused for the company,
// the option or the person keeps its kind, and a block on the person is first lifted by re-obtaining.
function prepareFolios(
  deps: CertificationDependencies,
  state: CertificationState,
  options?: PrepareFoliosOptions,
): Promise<PrepareFoliosResult>
 
// The folios each type needs for the sets not yet sent: the sum of each set plan's `folios`, never
// more, because unused authorized folios make the SII ration the next request.
function setFolioNeeds(
  plan: CertificationPlan,
  sent: readonly string[],
): Readonly<Record<number, number>>
 
// The folios the simulation needs: one per case, by type.
function simulationFolioNeeds(plan: CertificationPlan): Readonly<Record<number, number>>
TypeDescription
PrepareFoliosOptionsOptions of prepareFolios.
PrepareFoliosResultWhat prepareFolios returns: the state, and the CAFs that cover the needs.

Fields of PrepareFoliosOptions

FieldTypeDescription
needs?Readonly<Record<number, number>>Folios needed per type; the sets not yet sent by default.
fresh?booleanIgnore the CAFs in hand and request new ones (the simulation never reuses the sets' CAFs).

Fields of PrepareFoliosResult

FieldTypeDescription
stateCertificationState
outcomeOutcome
detail?string
cafsreadonly string[]The CAF files to issue with: the ones in hand plus the new ones, or only the new ones with fresh; ranges obtained again that were kept take the place of the ones in hand of their type.

Books step#

TypeScript
// The books phase.
function runBooks(
  deps: CertificationDependencies,
  state: CertificationState,
): Promise<StepResult<BooksOutcome>>
 
// The month before a `YYYY-MM` period.
function previousPeriod(period: string): string
 
// The first period at or below `period` the SII does not hold, stepping down month by month, at
// most 400 times.
function nextFreePeriod(period: string, occupied: ReadonlySet<string>): string
TypeDescription
BooksOutcomeHow the books phase ended: every wanted book approved; a mandatory book never sent; a declaration the portal did not take or books the SII refused; the approval wait exhausted. Defined as 'approved' | 'incomplete' | 'rejected' | 'timedOut'.

Exchange and printed samples#

The exchange and the printed samples are answered on two portals that speak GWT-RPC. This group holds the GWT helpers, the operations of each portal, the exchange answers, and the two steps the runner uses. Guide: Exchange and samples.

Catalogs#

TypeScript
// The exchange portal (`pfeInternet`): the certification's exchange set is downloaded there and
// its answers uploaded.
const EXCHANGE_PORTAL: GwtPortal
 
// The printed samples portal (`pdfdteInternet`), the SII's automatic validator of the printed
// documents.
const SAMPLES_PORTAL: GwtPortal
 
// The file names of the exchange answers, as the portal's uploads name them: the reception
// response, the receipts and the commercial approval.
const EXCHANGE_ANSWER_FILES: Readonly<Record<ExchangeAnswerKey, string>> = {
  reception: 'respuesta-recepcion-envio.xml',
  receipts: 'envio-recibos.xml',
  approval: 'respuesta-aprobacion-comercial.xml',
}
 
// The exchange answers in upload order.
const EXCHANGE_ANSWER_KEYS: readonly ExchangeAnswerKey[] = ['reception', 'receipts', 'approval']
TypeDescription
GwtPortalA GWT portal of the SII: its module base, its RPC service path and interface, its module name and the hash pair known to work (captured in June 2026; the SII changes both when it redeploys the portal).
ExchangeAnswerKeyThe keys of the three exchange answers. Defined as 'reception' | 'receipts' | 'approval'.

GWT#

TypeScript
// The request body of a call: `7|0|N|` + the string table + the body, every item followed by `|`.
function gwtBody(call: GwtCall): string
 
// Reads an answer: `//OK`, the string table, the message, the Long tokens.
function gwtAnswer(body: string): GwtAnswer
 
// A number in the GWT base-64 alphabet, most significant digit first (`264872` is `BAqo`).
function encodeGwtLong(value: number): string
 
// The number a GWT base-64 token holds, or null when a character is not in the alphabet.
function decodeGwtLong(token: string): number | null
 
// The hashes of a GWT portal: the caller's pair when given; else the module's `nocache.js` is read
// (the 32-hex strings delimited by `=`, `'` or `,`): the known pair stands when its permutation is
// listed, else the first one listed is the permutation and its `cache.html` gives the policy, the
// first quoted 32-hex string that differs from it; any failure, empty page or missing candidate
// keeps the known pair.
function discoverGwtHashes(context: PortalContext, input: GwtDiscoveryInput): Promise<GwtHashes>
TypeDescription
GwtCallOne GWT-RPC call: where it goes and what it carries.
GwtParameterOne parameter of a GWT-RPC call, as the SII's portals serialize it: a string (interned in the table, 0 when null, or in a slot of its own when distinct), a boxed java.lang.Integer, a boxed java.lang.Long (a number, or a token already in the GWT base-64 alphabet), a primitive boolean (Z), null (a String unless it names its declared type), or an object with its fields in serialization order.
GwtAnswerA GWT-RPC answer, read.
GwtHashesThe two hashes a GWT portal requires on every call.
GwtDiscoveryInputWhat discoverGwtHashes needs: the module, the pair known to work, and a pair from the caller that wins.
GwtStageA stage of work on one GWT portal: one authenticated entry, one warm-up and one pair of hashes that every call of the stage shares. Its cookies live only as long as the stage.

Fields of GwtDiscoveryInput

FieldTypeDescription
moduleBasestringThe module base URL, with its trailing slash.
moduleNamestringThe module name (<name>.nocache.js).
knownGwtHashesThe pair known to work.
override?GwtHashesA pair the caller knows better; nothing is fetched then.

Exchange portal#

TypeScript
// Downloads the exchange set from the exchange portal: the warm-up, then `downloadFile` with the
// company in the query and an empty multipart body. The download does not change the application.
function downloadExchangeSet(
  portal: PortalClient,
  input?: ExchangeCompanyInput,
  overrides?: CallOverrides,
): Promise<ExchangeSetDownload>
 
// Validates the user on the exchange portal: the warm-up, then `validarUsuario` with the company
// and the certificate holder over the known hashes. The answer says whether the company stands in
// the exchange stage; `//OK` is not required.
function validateExchangeUser(
  portal: PortalClient,
  input?: ExchangeGwtInput,
  overrides?: CallOverrides,
): Promise<ExchangeUserValidation>
 
// Uploads the three exchange answers, in the portal's order: the reception response to
// `uploadFile1`, the receipts to `uploadFile2`, the commercial approval to `uploadFile3`, each a
// single `uploadFormElement` part.
function uploadExchangeAnswers(
  portal: PortalClient,
  input: UploadExchangeAnswersInput,
  overrides?: CallOverrides,
): Promise<ExchangeUploadResult>
 
// Confirms the exchange on the portal: `validarSetContriPostSeguimiento` with the company (its
// answer is kept, not judged), then `updatePostulacionSeguimiento` for the follow-up ids 40, 41
// and 43, one per uploaded answer, each of which must answer `//OK`.
function confirmExchange(
  portal: PortalClient,
  input?: ExchangeGwtInput,
  overrides?: CallOverrides,
): Promise<ExchangeConfirmation>
 
// Runs `run` in one stage of the exchange portal: the session made sure of, one warm-up, and every
// call that is given the stage sent once over it. The upload, the user validation and the
// confirmation share one stage.
function withExchangeStage<T>(
  portal: PortalClient,
  operation: string,
  overrides: CallOverrides | undefined,
  run: (stage: GwtStage) => Promise<T>,
  sessionChecked?: boolean,
): Promise<T>
TypeDescription
ExchangeCompanyInputInput of the exchange operations that only name the company.
ExchangeGwtInputInput of the exchange operations that call the portal's service.
ExchangeSetDownloadWhat downloadExchangeSet read.
ExchangeUserValidationWhat validateExchangeUser read: the state and the raw answer, with the hashes used, for the next calls.
UploadExchangeAnswersInputInput of uploadExchangeAnswers: the three answers as XML, signed.
ExchangeUploadAnswerWhat one upload page answered.
ExchangeUploadResultWhat uploadExchangeAnswers did.
ExchangeConfirmationAnswerWhat one follow-up confirmation answered.
ExchangeConfirmationWhat confirmExchange did.
ExchangeUserStateWhat the exchange portal said when the user was validated.

Fields of ExchangeCompanyInput

FieldTypeDescription
companyRut?stringCompany RUT; the client's by default.
stage?GwtStageThe stage to run in, from withExchangeStage; the call opens a stage of its own without one.

Fields of ExchangeGwtInput

FieldTypeDescription
companyRut?stringCompany RUT; the client's by default.
stage?GwtStageThe stage to run in, from withExchangeStage; the call opens a stage of its own without one.
gwt?GwtHashesThe portal's hashes, when the caller knows better than the pair known to work, which is the default; they are never looked up.

Fields of UploadExchangeAnswersInput

FieldTypeDescription
companyRut?stringCompany RUT; the client's by default.
stage?GwtStageThe stage to run in, from withExchangeStage; the call opens a stage of its own without one.
receptionstringThe reception response (respuesta-recepcion-envio.xml).
receiptsstringThe receipts (envio-recibos.xml).
approvalstringThe commercial approval (respuesta-aprobacion-comercial.xml).

Samples portal#

TypeScript
// Reads the company's printed samples review: `leeImpreso` with the company RUT. The portal
// answers HTTP 200 with a state, or with a sentence when the application is not in the printed
// samples stage (before it, and after it too).
function readSamplesReview(
  portal: PortalClient,
  input?: ReadSamplesReviewInput,
  overrides?: CallOverrides,
): Promise<SamplesReview>
 
// Creates a printed samples review: `creaLista` with the company as sender and provider. The
// portal only creates one when the current review is `RECHAZADO` or `APROBADO`, or there is none;
// a review in `INGRESO` is resumed instead.
function createSamplesReview(
  portal: PortalClient,
  input?: SamplesCompanyInput,
  overrides?: CallOverrides,
): Promise<SamplesReviewCreated>
 
// Uploads one PDF to a review: `POST upload` with the parts `Filedata` (the file), `id` (the
// review id in decimal) and `ambiente` (`false`), the referer the permutation's `cache.html`. HTTP
// 200 is success.
function uploadSample(
  portal: PortalClient,
  input: UploadSampleInput,
  overrides?: CallOverrides,
): Promise<SampleUploaded>
 
// Submits a review to the SII: `solicitaRevisionSII` with the review token. The answer is
// `//OK[0,[],0,7]` whether the SII accepts or rejects the samples: the state is read again
// afterwards.
function submitSamplesReview(
  portal: PortalClient,
  input: SamplesReviewInput,
  overrides?: CallOverrides,
): Promise<{ readonly body: string; }>
 
// Reads how the SII filed each PDF of a rejected review: `muestraMail` with the review token. A
// failure is logged and gives an empty detail: the rejection stands without it.
function readSamplesDetail(
  portal: PortalClient,
  input: SamplesReviewInput,
  overrides?: CallOverrides,
): Promise<SamplesDetail>
 
// Runs `run` in one stage of the samples portal: the session made sure of, one warm-up, the hashes
// looked up once, and every call that is given the stage sent once over it.
function withSamplesStage<T>(
  portal: PortalClient,
  operation: string,
  overrides: CallOverrides | undefined,
  run: (stage: GwtStage) => Promise<T>,
): Promise<T>
TypeDescription
SamplesCompanyInputInput of the samples operations that name the company.
ReadSamplesReviewInputInput of readSamplesReview.
SamplesReviewInputInput of the samples operations that name a review by its token.
SamplesReviewWhat readSamplesReview read.
SamplesReviewCreatedWhat createSamplesReview did.
UploadSampleInputInput of uploadSample.
SampleUploadedWhat uploadSample did.
SamplesDetailWhat readSamplesDetail read.
ReviewStateThe states a samples review can be in, as the portal writes them. Defined as 'APROBADO' | 'POR REVISAR' | 'EN REVISION' | 'RECHAZADO' | 'INGRESO' | 'ENVIADO AL SII'.
SampleDetailOne row of the rejection detail: how the SII filed one PDF.

Fields of SamplesCompanyInput

FieldTypeDescription
companyRut?stringCompany RUT; the client's by default.
gwt?GwtHashesThe portal's hashes, when the caller knows them; discovered otherwise.
stage?GwtStageThe stage to run in, from withSamplesStage; the call opens a stage of its own without one.

Fields of ReadSamplesReviewInput

FieldTypeDescription
companyRut?stringCompany RUT; the client's by default.
gwt?GwtHashesThe portal's hashes, when the caller knows them; discovered otherwise.
stage?GwtStageThe stage to run in, from withSamplesStage; the call opens a stage of its own without one.
anyStatus?booleanTrue to read the answer whatever its HTTP status; by default any status but 200 is unexpected.

Fields of SamplesReviewInput

FieldTypeDescription
revisionTokenstringThe review's Long token, as the portal wrote it.
gwt?GwtHashesThe portal's hashes, when the caller knows them.
stage?GwtStageThe stage to run in, from withSamplesStage.

Fields of UploadSampleInput

FieldTypeDescription
revisionIdnumberThe review id, in decimal.
fileNamestringThe PDF's file name, sent as is.
bytesUint8ArrayThe PDF bytes.
gwt?GwtHashesThe portal's hashes, when the caller knows them.
stage?GwtStageThe stage to run in, from withSamplesStage.

Exchange answers#

TypeScript
// Builds and signs the three answers to an exchange set, as the certification expects them: the
// reception response (the envelope received, every document received when its receiver is the
// company, else "error en RUT receptor"), the receipts of Ley 19.983 (one per document, signed by
// the certificate holder) and the commercial approval (accepted when the receiver is the company,
// else rejected with `CodRchDsc` -1).
function createExchangeAnswers(setXml: string, input: CreateExchangeAnswersInput): ExchangeAnswers
 
// Reads the exchange set loosely: the XML is not checked for well-formedness and its tags are read
// by their full name, so a prefixed envelope is no envelope; the root is `EnvioDTE`, `EnvioDTEB`,
// `EnvioDTETraslado` or `EnvioBOLETA`; the set id (the `ID` attribute, else an `ID` child, else
// `SetDTE`), the cover's RUTs and, per document, its type (`TipoDTE` or `TpoDoc`), folio, issue
// date, issuer and receiver (the cover's when the document names none) and total.
function parseExchangeSet(setXml: string): ExchangeSet
TypeDescription
ExchangeDocumentOne document of the exchange set, as the answers describe it.
ExchangeSetThe exchange set the SII sends: its id, its cover and its documents.
ExchangeContactThe contact the answers name, every field optional.
CreateExchangeAnswersInputInput of createExchangeAnswers.
ExchangeAnswerOne answer, ready to upload.
ExchangeAnswersThe three answers of the exchange and the set they answer.
ExchangeStateThe exchange stage: the set answered and how far the answers got.
SamplesStateThe printed samples stage: the review and what was uploaded to it.

Fields of CreateExchangeAnswersInput

FieldTypeDescription
companyRutstringThe company that answers: the receiver the SII expects on every document.
certificatePick<Certificate, 'privateKeyPem' | 'publicKey' | 'certificateBase64' | 'rut'>The signing certificate; its holder signs the receipts.
contact?ExchangeContactThe contact, when any.
now?DateThe clock; now by default.

Steps#

TypeScript
// The exchange stage: the set (given, kept from an earlier run, or downloaded), the three answers
// generated and kept as artefacts, the user validated on the portal, the answers uploaded and the
// exchange confirmed, which moves the application to the printed samples.
function runExchange(
  deps: CertificationDependencies,
  state: CertificationState,
  input?: RunExchangeInput,
): Promise<StepResult<ExchangeOutcome>>
 
// The artefact that holds the exchange set; the caller fills it by hand when the download fails.
const EXCHANGE_SET_ARTEFACT: "intercambio/set-intercambio.xml"
 
// The printed samples stage: the review read (a block or a review already sent end here; none yet
// is created), resumed when it stands in `INGRESO` with a readable id or created otherwise, every
// PDF uploaded in order (each name saved as it goes), the review submitted, and its state read
// again (a failed reading is warned about and leaves the state unknown): `RECHAZADO` brings the
// detail and its summary.
function uploadPrintedSamples(
  deps: CertificationDependencies,
  state: CertificationState,
  input: UploadPrintedSamplesInput,
): Promise<StepResult<SamplesOutcome>>
TypeDescription
RunExchangeInputInput of runExchange.
ExchangeOutcomeHow runExchange ended: done with the answers uploaded and confirmed; alreadyDone when the state or the portal says the exchange was completed; setUnavailable when the set could not be downloaded (the artefact named in the detail must be filled by hand); notInExchange when the portal says the company is not in the stage. Defined as 'done' | 'alreadyDone' | 'setUnavailable' | 'notInExchange'.
UploadPrintedSamplesInputInput of uploadPrintedSamples.
SamplesOutcomeHow uploadPrintedSamples ended: submitted with the review sent to the SII; alreadySubmitted when a review was already sent (its state in the detail); blocked when the portal says the application is not in the stage; rejected when the SII rejected the review at once (the summary in the detail). Defined as 'submitted' | 'alreadySubmitted' | 'blocked' | 'rejected'.
PrintedSampleFileA sample file as the certification uploads it: its base name and its bytes.

Fields of RunExchangeInput

FieldTypeDescription
setXml?stringThe exchange set, when the caller has it (downloaded by hand from the portal).

Fields of UploadPrintedSamplesInput

FieldTypeDescription
samplesreadonly PrintedSampleFile[]The PDFs to upload, in order; readPrintedSamples reads them from a directory.

Runner#

runCertification runs the HTML side of the certification in stage order (test sets, books, simulation, exchange, printed samples, declaration of compliance), resumed from the saved state, and stops with a RunStop. The declaration of compliance is irreversible and is made only with declareCompliance: true. Guide: Runner.

TypeScript
// The HTML side of the certification, in stage order, resumed from the saved state: the test set
// (downloaded once), the folios, each set not yet sent, their declaration and approval; the books;
// the advance; the simulation sent, declared and confirmed; the exchange set answered, uploaded
// and confirmed; the printed samples uploaded and submitted when the `samples` option gives them
// (else it stops there); and then it declares compliance, only with `declareCompliance: true`,
// because that declaration cannot be undone.
function runCertification(
  dependencies: CertificationDependencies,
  options?: RunCertificationOptions,
): Promise<RunCertificationResult>
TypeDescription
RunCertificationOptionsOptions of runCertification.
RunCertificationResultWhat runCertification returns.
RunStopWhy the runner stopped. Defined as | 'done' | 'exchange' | 'printedSamples' | 'compliance' | 'until' | 'blocked' | 'rejected' | 'timedOut' | 'incomplete'.

Fields of RunCertificationOptions

FieldTypeDescription
until?CertificationStageStop once this stage is complete.
optionalSets?readonly string[]The optional sets to tick when downloading; DEFAULT_OPTIONAL_SETS by default.
declareCompliance?booleanMake the declaration of compliance, the sworn statement of the legal representative, which cannot be undone. Off by default: the runner stops at compliance instead.
exchangeSetXml?stringThe exchange set, when it was downloaded by hand from the portal.
samples?readonly PrintedSampleFile[] | (() => Promise<readonly PrintedSampleFile[]>)The printed samples to upload, or a function that reads them (readPrintedSamples); without them the runner stops at printedSamples.

Fields of RunCertificationResult

FieldTypeDescription
stateCertificationStateThe state as saved.
stoppedRunStopWhy it stopped.
detail?stringA word or sentence on why, when there is one.

Certification of receipts#

The receipts (boletas) certification is an application of its own with no runner: these are pieces you chain. A receipt (39, 41) takes receiptReferences, never references. Guide: Receipts.

Test set#

TypeScript
// The receipts portal (`certBolElectDteInternet`), where the certification of electronic receipts
// runs. Its hashes are not discovered: `moduleName` is what its interface suggests, not a recorded
// fact.
const RECEIPTS_PORTAL: GwtPortal
 
// Parses the receipts test set the receipts portal delivers, a plain text.
function parseReceiptsTestSet(text: string): readonly ReceiptsTestCase[]
TypeDescription
ReceiptsTestCaseOne case of the receipts test set: one receipt to issue.
ReceiptsTestItemOne item of a case of the receipts test set.

Issuing#

TypeScript
// Issues the receipts test set: one receipt of type 39 per case, in order, each with the next
// folio of the source, the final consumer as receiver, the prices of the set taken as including
// VAT, the exemption of an exempt item, the unit of measure an observation names on its first
// item, and one reference with the code `SET` and the reason `CASO-<n>`; then signs the
// `EnvioBOLETA` that carries them, with the certificate holder as sender (the issuer when the
// certificate names none) and the SII as receiver.
function issueReceiptsSet(
  cases: readonly ReceiptsTestCase[],
  options: IssueReceiptsSetOptions,
): Promise<IssuedReceiptsSet>
TypeDescription
IssueReceiptsSetOptionsWhat issuing the receipts set needs.
IssuedReceiptOne issued receipt of the set.
IssuedReceiptsSetThe receipts set issued: its receipts in case order and the signed envelope that carries them.

Fields of IssueReceiptsSetOptions

FieldTypeDescription
issuerCertificationIssuerInputThe issuer, as for a document; what it leaves out takes the defaults of DEFAULT_CERTIFICATION_ISSUER. The RUT, the name and the address have none.
certificateCertificateThe signing certificate; its holder is the sender of the envelope.
foliosFolioSourceWhere the folios of type 39 and their CAFs come from.
resolution?{ readonly number?: number; readonly date?: string }The resolution of the certification environment; number 0 and the UTC date of the instant by default, field by field.
now?() => DateClock, read once for the issue date (its UTC date), once per receipt for its stamps (the UTC instant to the second) and once for the envelope (the time of Chile).

Sending#

TypeScript
// Sends the receipts set: uploads the envelope and reads the reply (`STATUS` 0 with a track id is
// sent; `STATUS` 7 with a track id is also taken as sent, and without one it is a duplicate that
// skips to the report with no track id; `STATUS` 99 and any other reply is a failure and throws),
// waits 20 s and reads the status of a sent envelope once (a rejection ends here; a query that
// never got through is logged, and an answer without a state, or an unknown one, blocks nothing),
// then sends the folio consumption report built from the envelope, with the sequence number
// `sequence` plus the attempt, up to ten attempts: a `STATUS` 7 without a track id is a duplicate
// and three in a row mean today's report was already accepted; a `STATUS` 99 or another refusal
// ends it as `consumptionFailed`; an uploaded report is given 30 s and its status read once: a
// success or an intermediate state (a query error code or `0` too) accepts it, a query that never
// got through accepts it, and anything else (a rejection, no state, an unknown state) tries the
// next sequence number, unless its gloss speaks of authorisation or signing.
function sendReceiptsSet(
  sii: SiiClient,
  issued: { readonly envelope: SignedEnvelope; },
  options?: SendReceiptsSetOptions,
): Promise<ReceiptsSendResult>
 
// Builds the folio consumption report again from a receipts envelope already sent and uploads it
// once, with the sequence number given.
function resendReceiptsConsumption(
  sii: SiiClient,
  input: ResendReceiptsConsumptionInput,
): Promise<{ readonly sequence: number; readonly xml: string; readonly trackId: string; readonly duplicate: boolean; }>
TypeDescription
ReceiptsProgressEventThe progress events of sendReceiptsSet, with their step names. Defined as { readonly step: 'BOLETA_SOAP_CHECK' } | { readonly step: 'BOLETA_RCOF' }.
SendReceiptsSetOptionsOptions of sendReceiptsSet.
ReceiptsConsumptionAttemptOne folio consumption report tried.
ReceiptsSendResultWhat sendReceiptsSet did.
ResendReceiptsConsumptionInputInput of resendReceiptsConsumption.

Fields of SendReceiptsSetOptions

FieldTypeDescription
sequence?numberThe sequence number of the first folio consumption report; 100 by default (also when it is 0), and each attempt adds one.
sleep?(ms: number) => Promise<void>Wait function; the client's by default.
onProgress?(event: ReceiptsProgressEvent) => voidProgress events.

Fields of ReceiptsSendResult

FieldTypeDescription
outcome'sent' | 'envelopeRejected' | 'consumptionFailed'How it ended.
notAuthorizedbooleanThe SII's gloss or the error speaks of authorisation or signing: the company cannot sign receipts yet.
envelopeTrackIdstring | nullThe envelope's track id, to declare on the receipts portal; null when the SII already had the envelope and named none.
envelopeDuplicatebooleanThe SII already had the envelope.
consumptionTrackIdstring | nullThe accepted report's track id, or null.
consumptionSequencenumber | nullThe accepted report's sequence number, or null.
consumptionAlreadySentbooleanThree reports in a row were duplicates: one was already accepted today.
consumptionsreadonly ReceiptsConsumptionAttempt[]Every report tried, in order.
detail?stringThe gloss or error that ended it, when it did not end in sent.

Fields of ResendReceiptsConsumptionInput

FieldTypeDescription
envelopeXmlstringThe receipts envelope as it was sent.
sequencenumberThe sequence number of the report.

Portal#

TypeScript
// Downloads the receipts test set.
function downloadReceiptsTestSet(
  portal: PortalClient,
  input?: DownloadReceiptsTestSetInput,
  overrides?: CallOverrides,
): Promise<ReceiptsTestSetDownload>
 
// Declares the track id of the receipts envelope, so the SII validates the set
// (`ingresarTrackId`), exactly as it is given. Sent once.
function declareReceiptsTrackId(
  portal: PortalClient,
  input: ReceiptsPortalInput & { readonly trackId: string; },
  overrides?: CallOverrides,
): Promise<{ readonly body: string; }>
 
// Reads the state of the receipts application: whether the company is enrolled (it has valid
// representatives), whether the SII approved the set (`P90`, ready to declare) and whether the
// declaration was made (`P91`).
function readReceiptsStatus(
  portal: PortalClient,
  input?: ReceiptsPortalInput,
  overrides?: CallOverrides,
): Promise<ReceiptsStatus>
 
// Makes the declaration of compliance of the receipts application, which authorises the company to
// issue receipts in production (`autorizarEmpresaBolProd`). It cannot be undone.
function declareReceiptsCompliance(
  portal: PortalClient,
  input: DeclareReceiptsComplianceInput,
  overrides?: CallOverrides,
): Promise<ReceiptsComplianceResult>
 
// Reads whether the company may issue receipts. In production, a GET of the stamping entry page
// and a POST of its form with the company, and type 39 among the quoted option values of the
// answer (which must have a selector).
function verifyReceiptsAuthorization(
  input: VerifyReceiptsAuthorizationInput,
): Promise<ReceiptsAuthorization>
TypeDescription
ReceiptsPortalInputWhat every operation of the receipts portal takes.
DownloadReceiptsTestSetInputInput of downloadReceiptsTestSet.
ReceiptsTestSetDownloadWhat downloadReceiptsTestSet read.
ReceiptsStatusThe state of the receipts application.
ReceiptsProviderThe software provider the declaration names.
DeclareReceiptsComplianceInputInput of declareReceiptsCompliance.
ReceiptsComplianceResultHow declareReceiptsCompliance ended.
VerifyReceiptsAuthorizationInputInput of verifyReceiptsAuthorization.
ReceiptsAuthorizationCheckOne side of verifyReceiptsAuthorization. queryFailed means the portal did not answer the question: it is never "not authorised".
ReceiptsAuthorizationWhat verifyReceiptsAuthorization read; a side is null when its client was not given.
ReceiptsProgressThe receipts row of the progress page.

Fields of ReceiptsPortalInput

FieldTypeDescription
companyRut?stringCompany RUT; the client's by default.
gwt?GwtHashesThe portal's hashes, when the pair known to work has gone stale.
sessionChecked?booleanTrue when an earlier operation of the same run already checked the saved session.

Fields of DownloadReceiptsTestSetInput

FieldTypeDescription
companyRut?stringCompany RUT; the client's by default.
gwt?GwtHashesThe portal's hashes, when the pair known to work has gone stale.
sessionChecked?booleanTrue when an earlier operation of the same run already checked the saved session.
providerMail?stringThe software provider's mail the portal asks for with the set.

Fields of DeclareReceiptsComplianceInput

FieldTypeDescription
companyRut?stringCompany RUT; the client's by default.
gwt?GwtHashesThe portal's hashes, when the pair known to work has gone stale.
sessionChecked?booleanTrue when an earlier operation of the same run already checked the saved session.
providerReceiptsProviderThe software provider; a company that is its own provider passes itself.
businessNamestringThe company's business name.
link?stringThe query link; www.sii.cl by default.

Fields of VerifyReceiptsAuthorizationInput

FieldTypeDescription
production?PortalClientA client on production, to read the stamping form.
certification?PortalClientA client on certification, to read the progress page.
companyRut?stringCompany RUT; each client's by default.
sessionChecked?booleanTrue when an earlier operation of the same run already checked the saved sessions.