Facturiadocs
API reference

Documents

Issuing DTEs, reading them, PDF and XML artifacts, public links, and actions on a document.

Base: https://api.facturia.cl/v1. Every endpoint in this chapter authenticates with Authorization: Bearer unless stated otherwise, and the error envelope is the one in Errors.

MethodPathWhat it does
GET/documentsList emitted documents
POST/documentsEmit a DTE
POST/documents/previewsPrice and validate a document without emitting it
GET/documents/previews/{preview_id}Retrieve a stored preview
GET/documents/{document_id}Retrieve a document
GET/documents/{document_id}/pdfDownload the PDF
GET/documents/{document_id}/xmlDownload the signed XML exactly as sent to the SII
GET/documents/{document_id}/eventsLifecycle events for one document
POST/documents/{document_id}/retryRetry a document in failed
POST/documents/{document_id}/sendEmail the document to the receptor
POST/documents/{document_id}/cesionAsk the SII whether this factura is cedible
POST/documents/{document_id}/cedeCede this factura to a factoring company, registering it in the SII's RTC
POST/documents/{document_id}/credit_noteEmit a nota de crédito against this document
POST/documents/{document_id}/public_linksCreate or rotate public links for this document's artifacts
DELETE/documents/{document_id}/public_linksRevoke every public link for this document

GET /documents

List emitted documents

List documents for the empresa, newest first, filterable by tipo_dte, status and date range.

curl -sS https://api.facturia.cl/v1/documents \
  -H "Authorization: Bearer $FACTURIA_KEY" \
  -H "Facturia-Empresa: $EMPRESA"

Parameters

ParameterInRequiredTypeNotes
Facturia-Empresaheader—stringTarget empresa: canonical RUT (77928532-4) or empresa id (emp_…). Required on every empresa-scoped call unless the key is an empresa token. This header is the ONLY mechanism: there is no ?empresa= query parameter and no empresa body field. Omitted where required → 400 empresa_required; outside the allowlist → 403 empresa_not_allowed.
limitquery—integer
cursorquery—stringOpaque cursor from a previous response's next_cursor.
expandquery—stringComma-separated, applied per returned page. On a LIST the vocabulary is narrower than on GET /documents/\{document_id\}: events, references and received_document only. xml and pdf_base64 inline a whole artifact per row and are 400 invalid_field here — fetch them from the single document, or from /pdf and /xml (§5.4).
statusquery—queued · sent · accepted · reparo · rejected · failed · annulled
tipo_dtequery—33 · 34 · 39 · 41 · 46 · 52 · 56 · 61
folioquery—integer
receptor_rutquery—Rut
external_idquery—string
issue_date[gte]query—string
issue_date[lte]query—string
created_at[gte]query—string

Responses

CodeMeaningBody
200A list of documents.lista de Document
400Malformed or missing input.ErrorResponse
401Missing, malformed or revoked key.ErrorResponse
403Valid key, not permitted — scope, empresa allowlist, or mode.ErrorResponse
429Too many requests.ErrorResponse
defaultAn error not otherwise enumerated for this operation, in the same §5.5 envelope as every other refusal. Branch on error.code, never on the HTTP status alone or on error.message — a code this operation has not been seen to throw yet is still safer to route on than a string meant for a human.ErrorResponse

POST /documents

Emit a DTE

Returns 201 with status: queued and folio: null. The folio arrives when the document reaches sent: it is allocated by the engine after the row exists, so no 201 can carry one. null there is a WAIT, not a failure and not a placeholder — observe it with document.sent, or by re-reading the document on the cadence Facturia-Poll-After gives you.

The SII round-trip after that is a state machine you watch the same way. Everything not supplied is defaulted from the empresa profile (emisor block, giro, dirección), the receptor registry, and the tipo's tax rules.

curl -sS -X POST https://api.facturia.cl/v1/documents \
  -H "Authorization: Bearer $FACTURIA_KEY" \
  -H "Facturia-Empresa: $EMPRESA" \
  -H "Idempotency-Key: $(uuidgen)" \
  -H "Content-Type: application/json" \
  -d '{"tipo_dte":33,"items":[{"description":"Consultoría","quantity":1,"unit_price":1200000}]}'

Parameters

ParameterInRequiredTypeNotes
Facturia-Empresaheader—stringTarget empresa: canonical RUT (77928532-4) or empresa id (emp_…). Required on every empresa-scoped call unless the key is an empresa token. This header is the ONLY mechanism: there is no ?empresa= query parameter and no empresa body field. Omitted where required → 400 empresa_required; outside the allowlist → 403 empresa_not_allowed.
Idempotency-Keyheader—stringClient-generated key, unique per logical operation, retained 24h and scoped to (account, empresa, endpoint). Replays return the original response with Facturia-Idempotent-Replay: true. Same key + different body → 409.

Body

FieldTypeRequiredNotes
preview_idstring—Emit a previously computed preview (POST /documents/previews). The stored request is replayed through the ordinary create path, so nothing about the emission differs from a direct one. Only external_id and metadata may be supplied alongside it — nothing that could change an amount, a receptor or a date. Emitting the same preview twice returns the original document with 200 rather than a second 201. E.g.: "prev_01K2R9M3D8V5QW7N".
tipo_dte33 · 34 · 39 · 41 · 46 · 52 · 56 · 61yes33 factura afecta · 34 factura exenta · 39 boleta afecta · 41 boleta exenta · 46 factura de compra · 52 guía de despacho · 56 nota de débito · 61 nota de crédito. Boletas (39/41) travel a different SII transport; that is invisible through this API.
external_idstring—Your own identifier. Unique per empresa; a duplicate returns 409 external_id_exists.
issue_datestring—Defaults to today in America/Santiago.
prices_include_taxboolean—Defaults to true for 39/41 and false for every other tipo.
receptorParty—Who the document is issued to. giro here is the SII's GiroRecep, capped at 40 characters — tighter than the emisor's own GiroEmis (80), so the same name of trade can be legal on one side of a document and illegal on the other. legal_name is 100 and address is 70/20/20. Over-long values are refused with 400 field_too_long before a folio is allocated, and never truncated: shortening a razón social or a name of trade would change what the document says about the parties. address must be an object; a bare string is 400 invalid_field, because there is no way to split one into the three components the SII asks for and dropping it silently would emit a document with no address at all. AND THE ADDRESS IS NOT OPTIONAL on 33, 34, 46, 52, 56 and 61: the SII accepts the ENVELOPE and then REJECTS the document whose <Receptor> carries no GiroRecep/DirRecep/CmnaRecep, with the folio already spent. So giro, address.street and address.comuna are resolved from this empresa's own earlier documents to the same RUT and, failing that, refused with 400 receptor_incomplete before a folio is allocated. Three exceptions: a tipo 52 needs no giro (its receptor is often the emisor itself, whose own giro frequently exceeds 40); emission_channel=sfg also needs address.city, which the SII portal's own form demands; and 39/41 and a foreign 46 (foreign: true, or 55555555-5) need none of them.
itemsDocumentItem[]yes
global_discountsobject[]—The engine emits a single global discount line — the SII's <DscRcgGlobal> is one hard-coded NroLinDR>1 — so a second entry is refused with 400 invalid_field before a folio is allocated, rather than dropped. MERCADO CHANNEL ONLY: on emission_channel=sfg it is refused with 422 global_discount_not_available_for_channel, because the SII portal's emission form has no discount field at all — its EFXP_PCT_DESC/EFXP_MNT_DESC inputs are commented out in the captured form, and items[].discount_percent is refused there for the same reason. Fold the discount into items[].unit_price on that channel.
referencesDocumentReference[]—
dispatchobject—Required for tipo 52, and its transfer_type / dispatch_type are refused on any other tipo. Both emission channels emit a guía; they differ in which fields they can express. destination and dispatch_type are accepted on emission_channel=mercado (the engine writes them into the DTE's IdDoc/TipoDespacho and Transporte block) and refused on emission_channel=sfg with 422 dispatch_not_available_for_channel, because the SII portal's guía form has nowhere to put them: it carries a single address — the receptor's, so put a differing one in receptor.address — and its only traslado select is the kind of movement, with no TipoDespacho input at all. The two channels also differ on amounts: sfg refuses a guía with any line priced at or below 0, or a zero total, with 422 sfg_guia_zero_amount — the portal validates the guía with its factura validations, whatever the traslado kind — while mercado accepts one.
withholdingobject—Tipo 46 — you are the withholding agent.
paymentobject—
totalsTotals + any—
pdfobject—
xmlobject—The XML artifact shares the PDF's public-link mechanism on identical terms — it is the artifact the receptor's accounting system actually ingests, so gating it behind a key would force integrators to proxy a file we have already generated.
notesstring—
metadataobject—Up to 20 keys, ≤500 chars each. Stored and returned untouched; never sent to the SII.
testobject—Test mode only. Sending this with a live key fails with 400 test_field_in_live_mode.
Responses
CodeMeaningBody
200The preview named by preview_id was ALREADY emitted, by this call's own earlier attempt or by a concurrent one. The original document, unchanged — nothing was created by this call and no second folio was spent (§10.2). Only reachable on a \{"preview_id": "prev_…"\} body.EmittedDocument
201Document created and queued for transmission. Carries Facturia-Poll-After when the document is not terminal — which the 201 always is on the live lane, since it answers status: "queued". It was attached only by GET /v1/documents/\{document_id\} until 2026-09-04, so an agent following «poll per Facturia-Poll-After» had to issue a first read purely to discover the number it was told to poll with (#522). Same value, same function, both doors.EmittedDocument
400Malformed or missing input.ErrorResponse
401Missing, malformed or revoked key.ErrorResponse
402subscription_required - this live act needs an active subscription for the EMPRESA the request names, and that empresa has none (enforced). The subscription is per empresa: another empresa on the same account is unaffected, and error.details carries empresa, empresa_rut, empresa_name, account_plan, subscription_status, grace_until, blocked_by, a next handoff and a checkout_url pointing at that empresa. Or plan_limit_reached - a plan quota is exhausted (declared, not yet enforced). Test mode is never gated on either. ELIGIBILITY IS EVALUATED FIRST (2026-09-04, #475). This refusal now arrives ONLY when the empresa is otherwise able to emit: while its checklist is unfinished, its puesta en vivo pending or the empresa suspended, the act is refused by 422 empresa_not_emitting with the checklist handoff instead. So this 402 and Empresa.capabilities.blocked_by can no longer name two different next actions for one state — which they did, the object saying «sign the mandato» while the door said «pay».ErrorResponse
403Valid key, not permitted — scope, empresa allowlist, or mode.ErrorResponse
409State conflict — idempotency reuse, duplicate external_id, artifact not ready.ErrorResponse
422Well-formed, and refused by a domain rule. The codes this operation answers, in the order the door checks them: - empresa_not_emitting — live only: this endpoint requires onboarding.status = emitting, and the empresa has not got there yet. In SANDBOX it is not checked at all: a test-mode empresa emits from the first minute, which is what makes the whole surface exercisable before the SII has issued anything. error.details is an EmissionRefusalDetails and carries the pending_action — who must act, where, and in what words — so the refusal itself is the handoff. - empresa_not_active — the empresa is suspended or archived. - tipo_not_available_for_channel — this tipo_dte is not emitted on this empresa's emission_channel (§6.2). - plus the payload rules: totals_mismatch, receptor_incomplete, reference_required and their siblings — see GET /error_codes. This list named folios_exhausted until 2026-09-04. There is no such code and there never was: running out of folios is not refused at this door at all — the range is drawn from AFTER the request is accepted, so it arrives as a rejected document or, on POST /documents/previews, as the non-blocking warning no_folios_available (#496 found it by cross-checking every code these sentences name against the published dictionary).ErrorResponse
429Too many requests.ErrorResponse
defaultAn error not otherwise enumerated for this operation, in the same §5.5 envelope as every other refusal. Branch on error.code, never on the HTTP status alone or on error.message — a code this operation has not been seen to throw yet is still safer to route on than a string meant for a human.ErrorResponse

POST /documents/previews

Price and validate a document without emitting it

Runs the ENTIRE emission validator — the same refusals, in the same words — and then performs none of the emission. folio is null because none was taken; folio_preview is the folio that WOULD be used, read from the counter and not reserved.

Stored for an hour and readable with GET /documents/previews/\{preview_id\}, which returns what was computed rather than re-pricing: totals that moved between being shown and being approved is the failure this flow exists to prevent.

Emit it by sending \{"preview_id": "prev_…"\} to POST /documents. Emitting the same preview twice returns the ORIGINAL document with 200 and spends no second folio — a property enforced in the database, because an agent retrying a tool call is the ordinary case here and agents rarely send an Idempotency-Key.

curl -sS -X POST https://api.facturia.cl/v1/documents/previews \
  -H "Authorization: Bearer $FACTURIA_KEY" \
  -H "Facturia-Empresa: $EMPRESA" \
  -H "Content-Type: application/json" \
  -d '{"tipo_dte":33,"items":[{"description":"Consultoría","quantity":1,"unit_price":1200000}]}'

Parameters

ParameterInRequiredTypeNotes
Facturia-Empresaheader—stringTarget empresa: canonical RUT (77928532-4) or empresa id (emp_…). Required on every empresa-scoped call unless the key is an empresa token. This header is the ONLY mechanism: there is no ?empresa= query parameter and no empresa body field. Omitted where required → 400 empresa_required; outside the allowlist → 403 empresa_not_allowed.

Body

FieldTypeRequiredNotes
preview_idstring—Emit a previously computed preview (POST /documents/previews). The stored request is replayed through the ordinary create path, so nothing about the emission differs from a direct one. Only external_id and metadata may be supplied alongside it — nothing that could change an amount, a receptor or a date. Emitting the same preview twice returns the original document with 200 rather than a second 201. E.g.: "prev_01K2R9M3D8V5QW7N".
tipo_dte33 · 34 · 39 · 41 · 46 · 52 · 56 · 61yes33 factura afecta · 34 factura exenta · 39 boleta afecta · 41 boleta exenta · 46 factura de compra · 52 guía de despacho · 56 nota de débito · 61 nota de crédito. Boletas (39/41) travel a different SII transport; that is invisible through this API.
external_idstring—Your own identifier. Unique per empresa; a duplicate returns 409 external_id_exists.
issue_datestring—Defaults to today in America/Santiago.
prices_include_taxboolean—Defaults to true for 39/41 and false for every other tipo.
receptorParty—Who the document is issued to. giro here is the SII's GiroRecep, capped at 40 characters — tighter than the emisor's own GiroEmis (80), so the same name of trade can be legal on one side of a document and illegal on the other. legal_name is 100 and address is 70/20/20. Over-long values are refused with 400 field_too_long before a folio is allocated, and never truncated: shortening a razón social or a name of trade would change what the document says about the parties. address must be an object; a bare string is 400 invalid_field, because there is no way to split one into the three components the SII asks for and dropping it silently would emit a document with no address at all. AND THE ADDRESS IS NOT OPTIONAL on 33, 34, 46, 52, 56 and 61: the SII accepts the ENVELOPE and then REJECTS the document whose <Receptor> carries no GiroRecep/DirRecep/CmnaRecep, with the folio already spent. So giro, address.street and address.comuna are resolved from this empresa's own earlier documents to the same RUT and, failing that, refused with 400 receptor_incomplete before a folio is allocated. Three exceptions: a tipo 52 needs no giro (its receptor is often the emisor itself, whose own giro frequently exceeds 40); emission_channel=sfg also needs address.city, which the SII portal's own form demands; and 39/41 and a foreign 46 (foreign: true, or 55555555-5) need none of them.
itemsDocumentItem[]yes
global_discountsobject[]—The engine emits a single global discount line — the SII's <DscRcgGlobal> is one hard-coded NroLinDR>1 — so a second entry is refused with 400 invalid_field before a folio is allocated, rather than dropped. MERCADO CHANNEL ONLY: on emission_channel=sfg it is refused with 422 global_discount_not_available_for_channel, because the SII portal's emission form has no discount field at all — its EFXP_PCT_DESC/EFXP_MNT_DESC inputs are commented out in the captured form, and items[].discount_percent is refused there for the same reason. Fold the discount into items[].unit_price on that channel.
referencesDocumentReference[]—
dispatchobject—Required for tipo 52, and its transfer_type / dispatch_type are refused on any other tipo. Both emission channels emit a guía; they differ in which fields they can express. destination and dispatch_type are accepted on emission_channel=mercado (the engine writes them into the DTE's IdDoc/TipoDespacho and Transporte block) and refused on emission_channel=sfg with 422 dispatch_not_available_for_channel, because the SII portal's guía form has nowhere to put them: it carries a single address — the receptor's, so put a differing one in receptor.address — and its only traslado select is the kind of movement, with no TipoDespacho input at all. The two channels also differ on amounts: sfg refuses a guía with any line priced at or below 0, or a zero total, with 422 sfg_guia_zero_amount — the portal validates the guía with its factura validations, whatever the traslado kind — while mercado accepts one.
withholdingobject—Tipo 46 — you are the withholding agent.
paymentobject—
totalsTotals + any—
pdfobject—
xmlobject—The XML artifact shares the PDF's public-link mechanism on identical terms — it is the artifact the receptor's accounting system actually ingests, so gating it behind a key would force integrators to proxy a file we have already generated.
notesstring—
metadataobject—Up to 20 keys, ≤500 chars each. Stored and returned untouched; never sent to the SII.
testobject—Test mode only. Sending this with a live key fails with 400 test_field_in_live_mode.
Responses
CodeMeaningBody
201The computed preview. Nothing was emitted and no folio was reserved.DocumentPreview
400Malformed or missing input.ErrorResponse
401Missing, malformed or revoked key.ErrorResponse
403Valid key, not permitted — scope, empresa allowlist, or mode.ErrorResponse
422Well-formed but violates a domain rule — folios exhausted, acuse window closed.ErrorResponse
429Too many requests.ErrorResponse
defaultAn error not otherwise enumerated for this operation, in the same §5.5 envelope as every other refusal. Branch on error.code, never on the HTTP status alone or on error.message — a code this operation has not been seen to throw yet is still safer to route on than a string meant for a human.ErrorResponse

GET /documents/previews/{preview_id}

Retrieve a stored preview

Returns what was computed, never a re-computation. A preview that has been emitted stays readable with emitted: true and a consumed_at; an unconsumed one is gone an hour after it was created and answers 404.

curl -sS https://api.facturia.cl/v1/documents/previews/prev_01K2R9M3D8V5QW7N \
  -H "Authorization: Bearer $FACTURIA_KEY" \
  -H "Facturia-Empresa: $EMPRESA"

Parameters

ParameterInRequiredTypeNotes
preview_idpathyesstring
Facturia-Empresaheader—stringTarget empresa: canonical RUT (77928532-4) or empresa id (emp_…). Required on every empresa-scoped call unless the key is an empresa token. This header is the ONLY mechanism: there is no ?empresa= query parameter and no empresa body field. Omitted where required → 400 empresa_required; outside the allowlist → 403 empresa_not_allowed.

Responses

CodeMeaningBody
200The preview.DocumentPreview
401Missing, malformed or revoked key.ErrorResponse
403Valid key, not permitted — scope, empresa allowlist, or mode.ErrorResponse
404No such object under this key.ErrorResponse
429Too many requests.ErrorResponse
defaultAn error not otherwise enumerated for this operation, in the same §5.5 envelope as every other refusal. Branch on error.code, never on the HTTP status alone or on error.message — a code this operation has not been seen to throw yet is still safer to route on than a string meant for a human.ErrorResponse

GET /documents/{document_id}

Retrieve a document

One document: its lifecycle status, totals, public_links if any are live, and rejection_reasons if the SII refused it.

curl -sS https://api.facturia.cl/v1/documents/doc_01K2R7Q4XW9M3B8ZC5YHTVJD6N \
  -H "Authorization: Bearer $FACTURIA_KEY" \
  -H "Facturia-Empresa: $EMPRESA"

Parameters

ParameterInRequiredTypeNotes
document_idpathyesstring
Facturia-Empresaheader—stringTarget empresa: canonical RUT (77928532-4) or empresa id (emp_…). Required on every empresa-scoped call unless the key is an empresa token. This header is the ONLY mechanism: there is no ?empresa= query parameter and no empresa body field. Omitted where required → 400 empresa_required; outside the allowlist → 403 empresa_not_allowed.
expandquery—stringComma-separated. One or more of xml, pdf_base64, events, references, received_document. An unrecognised value is 400 invalid_field. received_document is populated when this document was emitted in response to a supplier's — matched at emission by reference (tipo_dte, folio) plus emisor RUT = receptor RUT, within the same empresa, and only when that match is unique (§5.4).

Responses

CodeMeaningBody
200The document.Document
400Malformed or missing input.ErrorResponse
401Missing, malformed or revoked key.ErrorResponse
403Valid key, not permitted — scope, empresa allowlist, or mode.ErrorResponse
404No such object under this key.ErrorResponse
429Too many requests.ErrorResponse
defaultAn error not otherwise enumerated for this operation, in the same §5.5 envelope as every other refusal. Branch on error.code, never on the HTTP status alone or on error.message — a code this operation has not been seen to throw yet is still safer to route on than a string meant for a human.ErrorResponse

GET /documents/{document_id}/pdf

Download the PDF

The document's rendered PDF (?copy=original or cedible where Ley 19.983 gives one). 409 artifact_not_ready if the SII has not accepted the document yet — the representación impresa is rendered on acceptance, not before.

curl -sS https://api.facturia.cl/v1/documents/doc_01K2R7Q4XW9M3B8ZC5YHTVJD6N/pdf \
  -H "Authorization: Bearer $FACTURIA_KEY" \
  -H "Facturia-Empresa: $EMPRESA"

Parameters

ParameterInRequiredTypeNotes
document_idpathyesstring
Facturia-Empresaheader—stringTarget empresa: canonical RUT (77928532-4) or empresa id (emp_…). Required on every empresa-scoped call unless the key is an empresa token. This header is the ONLY mechanism: there is no ?empresa= query parameter and no empresa body field. Omitted where required → 400 empresa_required; outside the allowlist → 403 empresa_not_allowed.
copyquery—original · cedibleWhich printed copy to serve. cedible is available for facturas — tipo_dte 33 and 34 (Ley 19.983 art. 1; Res. Ex. SII N°14/2005 §1°; Manual de Muestras Impresas §1.4). Any other type returns 422 cedible_not_available. cedible does not exist AT ALL on an emission_channel=sfg empresa, on any tipo: the SII signs and proxies its own PDF for that channel, and its bytes carry no acuse-de-recibo box or CEDIBLE legend to serve as one. copy=cedible there returns 422 cedible_not_available_for_channel; copy=original is unaffected. The two copies are two separate files: the original carries no acuse-de-recibo box and no CEDIBLE legend, the cedible copy carries both. both was withdrawn in wave 9 — the muestras manual allows exactly one page per file (p.12) — and now returns 400 invalid_field, as does any other unrecognised value. format (carta | 80mm) was also withdrawn: no thermal layout exists and none was ever served. Supplying it returns 400 invalid_field. Omitting it does not always mean original. The default is resolved in order: this document's own pdf.cedible (set at emission, §9.3) if it named one; else the empresa's branding.cedible_by_default (§7.6); else original — and never cedible on the SFG channel, regardless of either default. Send ?copy= explicitly to override either default for one read.

Responses

CodeMeaningBody
200The rendered PDF.application/pdf
401Missing, malformed or revoked key.ErrorResponse
403Valid key, not permitted — scope, empresa allowlist, or mode.ErrorResponse
404No such object under this key.ErrorResponse
409State conflict — idempotency reuse, duplicate external_id, artifact not ready.ErrorResponse
422Well-formed but violates a domain rule — folios exhausted, acuse window closed.ErrorResponse
429Too many requests.ErrorResponse
defaultAn error not otherwise enumerated for this operation, in the same §5.5 envelope as every other refusal. Branch on error.code, never on the HTTP status alone or on error.message — a code this operation has not been seen to throw yet is still safer to route on than a string meant for a human.ErrorResponse

GET /documents/{document_id}/xml

Download the signed XML exactly as sent to the SII

The exact XML Facturia sent to the SII (or will send), for a caller that wants the wire bytes rather than the parsed object.

curl -sS https://api.facturia.cl/v1/documents/doc_01K2R7Q4XW9M3B8ZC5YHTVJD6N/xml \
  -H "Authorization: Bearer $FACTURIA_KEY" \
  -H "Facturia-Empresa: $EMPRESA"

Parameters

ParameterInRequiredTypeNotes
document_idpathyesstring
Facturia-Empresaheader—stringTarget empresa: canonical RUT (77928532-4) or empresa id (emp_…). Required on every empresa-scoped call unless the key is an empresa token. This header is the ONLY mechanism: there is no ?empresa= query parameter and no empresa body field. Omitted where required → 400 empresa_required; outside the allowlist → 403 empresa_not_allowed.

Responses

CodeMeaningBody
200The signed EnvioDTE / EnvioBOLETA XML (ISO-8859-1).application/xml
401Missing, malformed or revoked key.ErrorResponse
403Valid key, not permitted — scope, empresa allowlist, or mode.ErrorResponse
404No such object under this key.ErrorResponse
409State conflict — idempotency reuse, duplicate external_id, artifact not ready.ErrorResponse
429Too many requests.ErrorResponse
defaultAn error not otherwise enumerated for this operation, in the same §5.5 envelope as every other refusal. Branch on error.code, never on the HTTP status alone or on error.message — a code this operation has not been seen to throw yet is still safer to route on than a string meant for a human.ErrorResponse

GET /documents/{document_id}/events

Lifecycle events for one document

The document's own event history — every document.* webhook Facturia published for it, in order, independent of whether delivery succeeded.

curl -sS https://api.facturia.cl/v1/documents/doc_01K2R7Q4XW9M3B8ZC5YHTVJD6N/events \
  -H "Authorization: Bearer $FACTURIA_KEY" \
  -H "Facturia-Empresa: $EMPRESA"

Parameters

ParameterInRequiredTypeNotes
document_idpathyesstring
Facturia-Empresaheader—stringTarget empresa: canonical RUT (77928532-4) or empresa id (emp_…). Required on every empresa-scoped call unless the key is an empresa token. This header is the ONLY mechanism: there is no ?empresa= query parameter and no empresa body field. Omitted where required → 400 empresa_required; outside the allowlist → 403 empresa_not_allowed.

Responses

CodeMeaningBody
200Events, oldest first.lista de DocumentEvent
401Missing, malformed or revoked key.ErrorResponse
403Valid key, not permitted — scope, empresa allowlist, or mode.ErrorResponse
429Too many requests.ErrorResponse
defaultAn error not otherwise enumerated for this operation, in the same §5.5 envelope as every other refusal. Branch on error.code, never on the HTTP status alone or on error.message — a code this operation has not been seen to throw yet is still safer to route on than a string meant for a human.ErrorResponse

POST /documents/{document_id}/retry

Retry a document in failed

Reuses the already-assigned folio. Never creates a second document.

curl -sS -X POST https://api.facturia.cl/v1/documents/doc_01K2R7Q4XW9M3B8ZC5YHTVJD6N/retry \
  -H "Authorization: Bearer $FACTURIA_KEY" \
  -H "Facturia-Empresa: $EMPRESA"

Parameters

ParameterInRequiredTypeNotes
document_idpathyesstring
Facturia-Empresaheader—stringTarget empresa: canonical RUT (77928532-4) or empresa id (emp_…). Required on every empresa-scoped call unless the key is an empresa token. This header is the ONLY mechanism: there is no ?empresa= query parameter and no empresa body field. Omitted where required → 400 empresa_required; outside the allowlist → 403 empresa_not_allowed.

Responses

CodeMeaningBody
200The document, back in queued.Document
401Missing, malformed or revoked key.ErrorResponse
403Valid key, not permitted — scope, empresa allowlist, or mode.ErrorResponse
409State conflict — idempotency reuse, duplicate external_id, artifact not ready.ErrorResponse
429Too many requests.ErrorResponse
defaultAn error not otherwise enumerated for this operation, in the same §5.5 envelope as every other refusal. Branch on error.code, never on the HTTP status alone or on error.message — a code this operation has not been seen to throw yet is still safer to route on than a string meant for a human.ErrorResponse

POST /documents/{document_id}/send

Email the document to the receptor

202 when THIS call created the send; 200 with the SAME job when an identical one (same document, same addresses, same attachments) already exists — one email, one job id, mirroring §10.2's "emitting the same preview twice returns the original document". Both statuses carry the same body, so a client that only handles one of them is handling half the endpoint.

curl -sS -X POST https://api.facturia.cl/v1/documents/doc_01K2R7Q4XW9M3B8ZC5YHTVJD6N/send \
  -H "Authorization: Bearer $FACTURIA_KEY" \
  -H "Facturia-Empresa: $EMPRESA" \
  -H "Idempotency-Key: $(uuidgen)" \
  -H "Content-Type: application/json" \
  -d '{"to":["[email protected]"],"attach":["pdf","xml"]}'

Parameters

ParameterInRequiredTypeNotes
document_idpathyesstring
Facturia-Empresaheader—stringTarget empresa: canonical RUT (77928532-4) or empresa id (emp_…). Required on every empresa-scoped call unless the key is an empresa token. This header is the ONLY mechanism: there is no ?empresa= query parameter and no empresa body field. Omitted where required → 400 empresa_required; outside the allowlist → 403 empresa_not_allowed.
Idempotency-Keyheader—stringClient-generated key, unique per logical operation, retained 24h and scoped to (account, empresa, endpoint). Replays return the original response with Facturia-Idempotent-Replay: true. Same key + different body → 409.

Body

FieldTypeRequiredNotes
tostring[]—
attachpdf · xml[]—Always the ORIGINAL copy of the PDF — never cedible, whatever this document's or the empresa's default says. §9.6: the cedible copy is an instrument for assigning the debt, not the invoice you send a customer to be paid. Default: ["pdf","xml"].
Responses
CodeMeaningBody
200An identical send already exists. The ORIGINAL job — no second email.SendJob
202Queued for delivery.SendJob
401Missing, malformed or revoked key.ErrorResponse
402subscription_required - this live act needs an active subscription for the EMPRESA the request names, and that empresa has none (enforced). The subscription is per empresa: another empresa on the same account is unaffected, and error.details carries empresa, empresa_rut, empresa_name, account_plan, subscription_status, grace_until, blocked_by, a next handoff and a checkout_url pointing at that empresa. Or plan_limit_reached - a plan quota is exhausted (declared, not yet enforced). Test mode is never gated on either. ELIGIBILITY IS EVALUATED FIRST (2026-09-04, #475). This refusal now arrives ONLY when the empresa is otherwise able to emit: while its checklist is unfinished, its puesta en vivo pending or the empresa suspended, the act is refused by 422 empresa_not_emitting with the checklist handoff instead. So this 402 and Empresa.capabilities.blocked_by can no longer name two different next actions for one state — which they did, the object saying «sign the mandato» while the door said «pay».ErrorResponse
403Valid key, not permitted — scope, empresa allowlist, or mode.ErrorResponse
409State conflict — idempotency reuse, duplicate external_id, artifact not ready.ErrorResponse
429Too many requests.ErrorResponse
defaultAn error not otherwise enumerated for this operation, in the same §5.5 envelope as every other refusal. Branch on error.code, never on the HTTP status alone or on error.message — a code this operation has not been seen to throw yet is still safer to route on than a string meant for a human.ErrorResponse

POST /documents/{document_id}/cesion

Ask the SII whether this factura is cedible

READ-ONLY (ticket #47). Queues a query against the SII's own registro (WSREGISTRORECLAMODTE.consultarDocDteCedible) and caches the answer on the document's cesion object. Nothing here cedes the invoice, builds an AEC, or writes to the Registro de Cesión de Créditos — that operation takes no action code and cannot change SII state.

Under Ley 19.983 a factura becomes assignable when the receptor gives acuse de recibo, or when eight días corridos pass without a reclamo; one declared as paid al contado never does (Circular N°35 de 23.06.2017). Only the SII knows which of those applies, so this is a report, never a computation.

202 when this call queued the question, 200 when an identical one is already in flight. Poll GET /documents/\{document_id\} for the answer; there is no webhook.

Accepts a documents:read key: the caller this exists for is a factoring integration, which should not need one that can issue invoices.

In test mode the answer is simulated in-process against the empresa's simulated clock and no SII socket is opened — 24 until eight days after acceptance, 25 after.

curl -sS -X POST https://api.facturia.cl/v1/documents/doc_01K2R7Q4XW9M3B8ZC5YHTVJD6N/cesion \
  -H "Authorization: Bearer $FACTURIA_KEY" \
  -H "Facturia-Empresa: $EMPRESA" \
  -H "Idempotency-Key: $(uuidgen)"

Parameters

ParameterInRequiredTypeNotes
document_idpathyesstring
Facturia-Empresaheader—stringTarget empresa: canonical RUT (77928532-4) or empresa id (emp_…). Required on every empresa-scoped call unless the key is an empresa token. This header is the ONLY mechanism: there is no ?empresa= query parameter and no empresa body field. Omitted where required → 400 empresa_required; outside the allowlist → 403 empresa_not_allowed.
Idempotency-Keyheader—stringClient-generated key, unique per logical operation, retained 24h and scoped to (account, empresa, endpoint). Replays return the original response with Facturia-Idempotent-Replay: true. Same key + different body → 409.

Responses

CodeMeaningBody
200A check against this same answer is already queued (or, in test mode, the simulated answer, already applied). The document, with its current cesion.Document
202Queued. The document, with cesion still showing the previously known answer — null throughout if this was the first check.Document
401Missing, malformed or revoked key.ErrorResponse
403Valid key, not permitted — scope, empresa allowlist, or mode.ErrorResponse
409State conflict — idempotency reuse, duplicate external_id, artifact not ready.ErrorResponse
422Well-formed but violates a domain rule — folios exhausted, acuse window closed.ErrorResponse
429Too many requests.ErrorResponse
defaultAn error not otherwise enumerated for this operation, in the same §5.5 envelope as every other refusal. Branch on error.code, never on the HTTP status alone or on error.message — a code this operation has not been seen to throw yet is still safer to route on than a string meant for a human.ErrorResponse

POST /documents/{document_id}/cede

Cede this factura to a factoring company, registering it in the SII's RTC

THE WRITE (ticket #60), unlike POST …/cesion above (a read). Assembles an Archivo Electrónico de Cesión — the emisor's original signed DTE plus the terms of the transfer, signed by the cedente — and uploads it to the SII's Registro Electrónico de Transferencia de Crédito. A real, irreversible act.

Works the same regardless of channel (ticket #60, ruled 2026-09-06): the AEC carries the emisor's original signed envelope verbatim, so it does not care whether the DTE was emitted through emission_channel=sfg or emission_channel=mercado. cesion_channel_unsupported, the code the old channel guard raised, is RETIRED from the catalogue.

202 with a job when this call queued a NEW attempt; 200 with the SAME job when one is already queued/submitted/aec_generated for this document (one attempt in flight at a time). GET /documents/\{document_id\} carries the newest attempt's outcome under cesion.status.

A RECEIPT IS NOT A REGISTRATION (ticket #69). The furthest the upload itself can take an attempt is submitted — the SII answered «Envío recibido OK» and issued a TrackID. Its validation happens afterwards, and a rejection is notified by e-mail to the cedente hours later, so this API claims confirmed only when the registry's own wsRPETCConsulta.getEstEnvio answers EOK («Envío Aceptado») for that TrackID. Webhooks follow that exactly: document.cesion_submitted means «AEC recibido, anotación pendiente», document.cesion_confirmed is the one to settle money on, and document.cesion_failed covers a refusal, a fence, an answer nobody recognises, and a registration that could never be confirmed.

409 cesion_attempt_may_have_registered when the newest attempt for this document had already put the signed AEC on the wire when it stopped (ticket #76). Whether it registered cannot be decided from here, so a second cesión is refused rather than risking the same credit being assigned twice. error.details carries this system's own last known registry answer for that attempt (rtc_estado, rtc_track_id) when one was ever recorded — reading it costs a column, not a new SII call; when neither was ever recorded the details say so.

In test mode this settles in the same request (§4.1) — no socket opened, the attempt lands simulated, and BOTH document.cesion_submitted and document.cesion_confirmed fire, in that order, so the event a factoring integration acts on is exercisable in test.

Live submission is owner-gated, and since the 2026-09-06 ruling (R6) also gated per empresa: the AEC assembly and the registry upload are built and checked against the SII's own schema — the first live upload (2026-09-03) was accepted by the registry with a real TrackID and then rejected at validation for a signature defect, since fixed. Opening it needs BOTH ALLOW_LIVE_CESION_SUBMITS (an operator's own shell, never a deploy) AND the ceding empresa's own connection reaching onboarding_status=emitting, active, ambiente=palena and not a sandbox connection. A live attempt missing either one is accepted and queued like any other and settles failed non-retryably, naming whichever condition is missing.

curl -sS -X POST https://api.facturia.cl/v1/documents/doc_01K2R7Q4XW9M3B8ZC5YHTVJD6N/cede \
  -H "Authorization: Bearer $FACTURIA_KEY" \
  -H "Facturia-Empresa: $EMPRESA" \
  -H "Idempotency-Key: $(uuidgen)" \
  -H "Content-Type: application/json" \
  -d '{"cesionario":{},"ultimo_vencimiento":"…"}'

Parameters

ParameterInRequiredTypeNotes
document_idpathyesstring
Facturia-Empresaheader—stringTarget empresa: canonical RUT (77928532-4) or empresa id (emp_…). Required on every empresa-scoped call unless the key is an empresa token. This header is the ONLY mechanism: there is no ?empresa= query parameter and no empresa body field. Omitted where required → 400 empresa_required; outside the allowlist → 403 empresa_not_allowed.
Idempotency-Keyheader—stringClient-generated key, unique per logical operation, retained 24h and scoped to (account, empresa, endpoint). Replays return the original response with Facturia-Idempotent-Replay: true. Same key + different body → 409.

Body

FieldTypeRequiredNotes
cesionarioobjectyes
montointeger—CLP, in [1, total]. Defaults to the document's total.
ultimo_vencimientostringyes
otras_condicionesstring—
email_deudorstring—
contactoobject—
Responses
CodeMeaningBody
200A cesión attempt was already in flight for this document. The same job.CesionJob
202Queued.CesionJob
401Missing, malformed or revoked key.ErrorResponse
403Valid key, not permitted — scope, empresa allowlist, or mode.ErrorResponse
409State conflict — idempotency reuse, duplicate external_id, artifact not ready.ErrorResponse
422Well-formed but violates a domain rule — folios exhausted, acuse window closed.ErrorResponse
429Too many requests.ErrorResponse
defaultAn error not otherwise enumerated for this operation, in the same §5.5 envelope as every other refusal. Branch on error.code, never on the HTTP status alone or on error.message — a code this operation has not been seen to throw yet is still safer to route on than a string meant for a human.ErrorResponse

POST /documents/{document_id}/credit_note

Emit a nota de crédito against this document

There is no "delete an invoice" in Chile. code: 1 annuls the referenced document, 2 corrects text, 3 corrects amounts (supply items for the corrected values).

curl -sS -X POST https://api.facturia.cl/v1/documents/doc_01K2R7Q4XW9M3B8ZC5YHTVJD6N/credit_note \
  -H "Authorization: Bearer $FACTURIA_KEY" \
  -H "Facturia-Empresa: $EMPRESA" \
  -H "Idempotency-Key: $(uuidgen)" \
  -H "Content-Type: application/json" \
  -d '{"code":1,"reason":"content"}'

Parameters

ParameterInRequiredTypeNotes
document_idpathyesstring
Facturia-Empresaheader—stringTarget empresa: canonical RUT (77928532-4) or empresa id (emp_…). Required on every empresa-scoped call unless the key is an empresa token. This header is the ONLY mechanism: there is no ?empresa= query parameter and no empresa body field. Omitted where required → 400 empresa_required; outside the allowlist → 403 empresa_not_allowed.
Idempotency-Keyheader—stringClient-generated key, unique per logical operation, retained 24h and scoped to (account, empresa, endpoint). Replays return the original response with Facturia-Idempotent-Replay: true. Same key + different body → 409.

Body

FieldTypeRequiredNotes
code1 · 2 · 3yes
reasonstringyes
itemsDocumentItem[]—
Responses
CodeMeaningBody
201The nota de crédito (tipo 61).Document
401Missing, malformed or revoked key.ErrorResponse
402subscription_required - this live act needs an active subscription for the EMPRESA the request names, and that empresa has none (enforced). The subscription is per empresa: another empresa on the same account is unaffected, and error.details carries empresa, empresa_rut, empresa_name, account_plan, subscription_status, grace_until, blocked_by, a next handoff and a checkout_url pointing at that empresa. Or plan_limit_reached - a plan quota is exhausted (declared, not yet enforced). Test mode is never gated on either. ELIGIBILITY IS EVALUATED FIRST (2026-09-04, #475). This refusal now arrives ONLY when the empresa is otherwise able to emit: while its checklist is unfinished, its puesta en vivo pending or the empresa suspended, the act is refused by 422 empresa_not_emitting with the checklist handoff instead. So this 402 and Empresa.capabilities.blocked_by can no longer name two different next actions for one state — which they did, the object saying «sign the mandato» while the door said «pay».ErrorResponse
403Valid key, not permitted — scope, empresa allowlist, or mode.ErrorResponse
422Well-formed but violates a domain rule — folios exhausted, acuse window closed.ErrorResponse
429Too many requests.ErrorResponse
defaultAn error not otherwise enumerated for this operation, in the same §5.5 envelope as every other refusal. Branch on error.code, never on the HTTP status alone or on error.message — a code this operation has not been seen to throw yet is still safer to route on than a string meant for a human.ErrorResponse

POST /documents/{document_id}/public_links

Create or rotate public links for this document's artifacts

Turns a public link on after the fact, or rotates an existing one (which invalidates the previous URL). A link exposes exactly one artifact of one document — never the empresa's other documents, never account data — and cannot be escalated into an API credential.

cedible (ticket #18 wave 10) is NOT in the default set: unlike pdf/xml it does not exist for every document, so a caller who did not ask for it does not get one minted silently — mirroring ?copy= on GET …/pdf, which defaults to original rather than guessing. Requesting it for a tipo outside 33/34 is 422 cedible_not_available; requesting it on an emission_channel=sfg empresa, on any tipo, is 422 cedible_not_available_for_channel (#48) — the SII proxies its own PDF for that channel and no cedible copy of it ever exists, so this refuses the mint rather than handing back a .cedible link that could only ever resolve to the non-cedible file.

curl -sS -X POST https://api.facturia.cl/v1/documents/doc_01K2R7Q4XW9M3B8ZC5YHTVJD6N/public_links \
  -H "Authorization: Bearer $FACTURIA_KEY" \
  -H "Facturia-Empresa: $EMPRESA" \
  -H "Idempotency-Key: $(uuidgen)" \
  -H "Content-Type: application/json" \
  -d '{"artifacts":["pdf","xml"]}'

Parameters

ParameterInRequiredTypeNotes
document_idpathyesstring
Facturia-Empresaheader—stringTarget empresa: canonical RUT (77928532-4) or empresa id (emp_…). Required on every empresa-scoped call unless the key is an empresa token. This header is the ONLY mechanism: there is no ?empresa= query parameter and no empresa body field. Omitted where required → 400 empresa_required; outside the allowlist → 403 empresa_not_allowed.
Idempotency-Keyheader—stringClient-generated key, unique per logical operation, retained 24h and scoped to (account, empresa, endpoint). Replays return the original response with Facturia-Idempotent-Replay: true. Same key + different body → 409.

Body

FieldTypeRequiredNotes
artifactspdf · xml · cedible[]yesDefault: ["pdf","xml"].
expires_in_daysinteger,null—Null means the link does not expire. Default: 90.
expires_in_secondsinteger,null—The same lifetime in seconds, clamped to 30s–365d. WINS when both units are sent: days cannot express the ten-minute link an agent needs, and the shorter, more specific unit is the safer reading of an ambiguous request.
Responses
CodeMeaningBody
200The minted links. NOT the document: the secret half of each URL is stored hashed, so this response is the only place a working URL ever exists. Capture it.PublicLinks
401Missing, malformed or revoked key.ErrorResponse
403Valid key, not permitted — scope, empresa allowlist, or mode.ErrorResponse
409State conflict — idempotency reuse, duplicate external_id, artifact not ready.ErrorResponse
429Too many requests.ErrorResponse
defaultAn error not otherwise enumerated for this operation, in the same §5.5 envelope as every other refusal. Branch on error.code, never on the HTTP status alone or on error.message — a code this operation has not been seen to throw yet is still safer to route on than a string meant for a human.ErrorResponse

Revoke every public link for this document

Revoke every live public link minted for the document. Already-cached copies of the URL keep working until they expire; this only stops new fetches.

curl -sS -X DELETE https://api.facturia.cl/v1/documents/doc_01K2R7Q4XW9M3B8ZC5YHTVJD6N/public_links \
  -H "Authorization: Bearer $FACTURIA_KEY" \
  -H "Facturia-Empresa: $EMPRESA"

Parameters

ParameterInRequiredTypeNotes
document_idpathyesstring
Facturia-Empresaheader—stringTarget empresa: canonical RUT (77928532-4) or empresa id (emp_…). Required on every empresa-scoped call unless the key is an empresa token. This header is the ONLY mechanism: there is no ?empresa= query parameter and no empresa body field. Omitted where required → 400 empresa_required; outside the allowlist → 403 empresa_not_allowed.

Responses

CodeMeaningBody
204Revoked. Existing URLs stop resolving immediately.—
401Missing, malformed or revoked key.ErrorResponse
403Valid key, not permitted — scope, empresa allowlist, or mode.ErrorResponse
429Too many requests.ErrorResponse
defaultAn error not otherwise enumerated for this operation, in the same §5.5 envelope as every other refusal. Branch on error.code, never on the HTTP status alone or on error.message — a code this operation has not been seen to throw yet is still safer to route on than a string meant for a human.ErrorResponse

On this page