Connectors
The first-party sources that feed the expense ledger: Fintoc and bank statement uploads.
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.
| Method | Path | What it does |
|---|---|---|
GET | /connections | List connector connections for this empresa |
POST | /connections | Create a Fintoc bank/card connection |
GET | /connections/{connection_id} | Retrieve a connection |
DELETE | /connections/{connection_id} | Disconnect (revokes the link, stops ingestion) |
POST | /connections/{connection_id}/sync | Force a movement sync (async) |
GET | /tax/statements | List uploaded cartolas |
POST | /tax/statements | Upload a cartola (CSV/XLSX) to create expenses |
GET /connections
List connector connections for this empresa
Connectors (bank feeds, accounting integrations) linked to the empresa, with each one's last sync and status.
curl -sS https://api.facturia.cl/v1/connections \
-H "Authorization: Bearer $FACTURIA_KEY" \
-H "Facturia-Empresa: $EMPRESA"Parameters
| Parameter | In | Required | Type | Notes |
|---|---|---|---|---|
Facturia-Empresa | header | — | string | Target 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. |
limit | query | — | integer | |
cursor | query | — | string | Opaque cursor from a previous response's next_cursor. |
Responses
| Code | Meaning | Body |
|---|---|---|
200 | A list of connections. | lista de Connection |
401 | Missing, malformed or revoked key. | ErrorResponse |
403 | Valid key, not permitted — scope, empresa allowlist, or mode. | ErrorResponse |
429 | Too many requests. | ErrorResponse |
default | An 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 /connections
Create a Fintoc bank/card connection
Returns status: pending_link with a link_url. Send the user through it once; from then
on each sync keeps the foreign-currency movements, converts them into expense objects
(source: "fintoc", fx_source: "card_rate") and lets the tipo-46 detector run.
Credentials stay with Fintoc — Facturia stores a link token, never a bank password.
connection.linked fires when the link completes.
IN TEST MODE there is no link to complete, so the connection is born active, link_url
is null and connection.linked fires with the 201 — §4.1's "complete in-process
simulation", and the only way the connector surface is exercisable before a real bank is
involved.
curl -sS -X POST https://api.facturia.cl/v1/connections \
-H "Authorization: Bearer $FACTURIA_KEY" \
-H "Facturia-Empresa: $EMPRESA" \
-H "Idempotency-Key: $(uuidgen)" \
-H "Content-Type: application/json" \
-d '{"provider":"fintoc"}'Parameters
| Parameter | In | Required | Type | Notes |
|---|---|---|---|---|
Facturia-Empresa | header | — | string | Target 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-Key | header | — | string | Client-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
| Field | Type | Required | Notes |
|---|---|---|---|
provider | fintoc | yes | |
account_types | checking · credit_card[] | — | |
sync_frequency | daily · weekly · manual | — | Default: "daily". |
| Responses |
| Code | Meaning | Body |
|---|---|---|
201 | The connection, awaiting the link flow. | Connection |
400 | Malformed or missing input. | ErrorResponse |
401 | Missing, malformed or revoked key. | ErrorResponse |
403 | Valid key, not permitted — scope, empresa allowlist, or mode. | ErrorResponse |
429 | Too many requests. | ErrorResponse |
default | An 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 /connections/{connection_id}
Retrieve a connection
One connector's configuration and sync history, without its stored credentials.
curl -sS https://api.facturia.cl/v1/connections/con_01K2RJ7B2W4M \
-H "Authorization: Bearer $FACTURIA_KEY" \
-H "Facturia-Empresa: $EMPRESA"Parameters
| Parameter | In | Required | Type | Notes |
|---|---|---|---|---|
connection_id | path | yes | string | |
Facturia-Empresa | header | — | string | Target 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
| Code | Meaning | Body |
|---|---|---|
200 | The connection. | Connection |
401 | Missing, malformed or revoked key. | ErrorResponse |
403 | Valid key, not permitted — scope, empresa allowlist, or mode. | ErrorResponse |
404 | No such object under this key. | ErrorResponse |
429 | Too many requests. | ErrorResponse |
default | An 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 |
DELETE /connections/{connection_id}
Disconnect (revokes the link, stops ingestion)
Expenses already created from this connection are kept.
curl -sS -X DELETE https://api.facturia.cl/v1/connections/con_01K2RJ7B2W4M \
-H "Authorization: Bearer $FACTURIA_KEY" \
-H "Facturia-Empresa: $EMPRESA"Parameters
| Parameter | In | Required | Type | Notes |
|---|---|---|---|---|
connection_id | path | yes | string | |
Facturia-Empresa | header | — | string | Target 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
| Code | Meaning | Body |
|---|---|---|
204 | Disconnected. | — |
401 | Missing, malformed or revoked key. | ErrorResponse |
403 | Valid key, not permitted — scope, empresa allowlist, or mode. | ErrorResponse |
429 | Too many requests. | ErrorResponse |
default | An 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 /connections/{connection_id}/sync
Force a movement sync (async)
422 connection_not_linked on a connection that is not active: tax_bank_sync only
looks at linked rows, so queueing one would be a job that runs, does nothing, and reports
succeeded.
In TEST MODE the job comes back already succeeded — there is no bank to call and no
worker to wait for, so a queued job would never move (§4.1).
curl -sS -X POST https://api.facturia.cl/v1/connections/con_01K2RJ7B2W4M/sync \
-H "Authorization: Bearer $FACTURIA_KEY" \
-H "Facturia-Empresa: $EMPRESA" \
-H "Idempotency-Key: $(uuidgen)"Parameters
| Parameter | In | Required | Type | Notes |
|---|---|---|---|---|
connection_id | path | yes | string | |
Facturia-Empresa | header | — | string | Target 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-Key | header | — | string | Client-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
| Code | Meaning | Body |
|---|---|---|
202 | Sync job accepted — queued in live, already succeeded in test. | Job |
401 | Missing, malformed or revoked key. | ErrorResponse |
403 | Valid key, not permitted — scope, empresa allowlist, or mode. | ErrorResponse |
422 | Well-formed but violates a domain rule — folios exhausted, acuse window closed. | ErrorResponse |
429 | Too many requests. | ErrorResponse |
default | An 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 /tax/statements
List uploaded cartolas
Bank or card statements imported for the empresa, the raw material tax:write imports feed into the expense ledger and its suggestions.
curl -sS https://api.facturia.cl/v1/tax/statements \
-H "Authorization: Bearer $FACTURIA_KEY" \
-H "Facturia-Empresa: $EMPRESA"Parameters
| Parameter | In | Required | Type | Notes |
|---|---|---|---|---|
Facturia-Empresa | header | — | string | Target 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. |
limit | query | — | integer | |
cursor | query | — | string | Opaque cursor from a previous response's next_cursor. |
Responses
| Code | Meaning | Body |
|---|---|---|
200 | A list of statement imports. | lista de Statement |
401 | Missing, malformed or revoked key. | ErrorResponse |
403 | Valid key, not permitted — scope, empresa allowlist, or mode. | ErrorResponse |
429 | Too many requests. | ErrorResponse |
default | An 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 /tax/statements
Upload a cartola (CSV/XLSX) to create expenses
Asynchronous. The returned job's result carries rows_read, expenses_created,
duplicates_skipped and per-row errors[]. Deduplication is by
(empresa, date, amount_original, currency, provider) plus external_id where present,
so re-uploading an overlapping cartola is safe.
202 when this upload created the import; 200 with the ORIGINAL job when the exact same
BYTES were uploaded before for this empresa (a sha256 taken before anything touches
storage) — no second storage object, no second parse. Same body either way.
curl -sS -X POST https://api.facturia.cl/v1/tax/statements \
-H "Authorization: Bearer $FACTURIA_KEY" \
-H "Facturia-Empresa: $EMPRESA" \
-H "Idempotency-Key: $(uuidgen)" \
-F "file=…" \
-F "format=…"Parameters
| Parameter | In | Required | Type | Notes |
|---|---|---|---|---|
Facturia-Empresa | header | — | string | Target 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-Key | header | — | string | Client-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 (multipart/form-data)
| Field | Type | Required | Notes |
|---|---|---|---|
file | string | yes | |
format | auto · generic_csv · santander · bci · banco_chile · itau · scotiabank · xlsx | — | Default: "auto". |
default_currency | string | — | Applied to rows whose currency column is absent. |
| Responses |
| Code | Meaning | Body |
|---|---|---|
200 | These exact bytes were already uploaded. The ORIGINAL import job. | StatementImportJob |
202 | Import job accepted. | StatementImportJob |
400 | Malformed or missing input. | ErrorResponse |
401 | Missing, malformed or revoked key. | ErrorResponse |
403 | Valid key, not permitted — scope, empresa allowlist, or mode. | ErrorResponse |
429 | Too many requests. | ErrorResponse |
default | An 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 |