Factuarea APIDevelopers

Escàner de documents

Puja factures de proveïdors i rebuts, revisa les dades extretes i crea esborranys de despesa vinculats.

L’escàner conserva junts l’original, les evidències d’extracció, l’historial de revisió i el vincle amb la despesa. Crea esborranys de despesa justificats per factures del proveïdor o factures simplificades aptes; no emet factures ni registra pagaments. Revisa les dades fiscals abans de convertir. Un tipus impositiu desconegut no equival a un zero verificat.

Accés i pujada

L’empresa ha de tenir accés a l’escàner/OCR. Fes servir purchase_invoices:read per consultar, purchase_invoices:write per pujar, revisar i convertir, i purchase_invoices:delete per arxivar. L’empresa vinculada continua sent el límit d’autorització per a API keys, OAuth i MCP.

Puja fins a 20 arxius PDF, JPEG o PNG: 20 MiB per arxiu, 100 MiB per petició, 25 pàgines per document (POST /v1/purchase_scans). Un cos de petició que supera el límit de la vora es rebutja abans d’arribar a l’aplicació amb 413 payload_too_large. Dins d’un cos admès, un arxiu massa gran o que supera el límit del lot retorna un 413 de l’aplicació: scan_file_too_large, scan_batch_too_large o scan_page_limit_exceeded. Els arxius passen controls de seguretat i s’emmagatzemen xifrats. Una resposta 202 conté data.accepted i data.rejected; indica admissió, no que l’OCR hagi acabat. Si es rebutgen tots els arxius, la resposta 422 conserva el resultat del lot. Comprova cada element. Reintenta el mateix lot amb el mateix ordre d’arxius, payload i Idempotency-Key.

curl https://api.factuarea.com/v1/purchase_scans \
  -H "Authorization: Bearer $FACTUAREA_API_KEY" \
  -H "Idempotency-Key: scanner-upload-batch-001" \
  -F "files[]=@invoice.pdf" \
  -F "files[]=@receipt.jpg"

Comença sempre amb una clau fact_test_: el sandbox executa el mateix contracte amb una extracció simulada determinista, sense proveïdor d’OCR i sense consumir quota. Passa a fact_live_ només quan el flux estigui validat.

Processament i revisió

Consulta GET /v1/purchase_scans/{id}. received espera processament; queued i processing estan en curs. Si l’escaneig automàtic està desactivat, inicia explícitament el document rebut mitjançant POST /v1/purchase_scans/{id}/retry. needs_review exposa camps extrets, confiança, evidències de pàgina/zona, incidències i review_fields (el catàleg de noms de camp que encara està pendent de revisió). failed admet reintent només si és recuperable. duplicate requereix una decisió. Respecta available_actions i els indicadors de capacitat en lloc de deduir-los únicament de l’estat. Arxiva un escaneig que no s’estigui processant amb DELETE /v1/purchase_scans/{id}; és reversible amb POST /v1/purchase_scans/{id}/restore — comprova available_actions de nou després, ja que restaurar no recupera un original ja purgat.

Fes servir PUT /v1/purchase_scans/{id}/review amb l’expected_version observada. Envia només les correccions revisades: els camps i les línies omesos es conserven; { "value": null } esborra un camp. Els identificadors públics són UUID v7 a id, supplier_id i line_id. Els decimals són cadenes. Un pedaç de línia fa servir update, add sense line_id (l’assigna el servidor) o remove amb un line_id existent.

Evidència de compra i selecció de catàleg

Cada línia pot conservar fins a cinc dades de compra tal com apareixen impreses a l’original: supplier_sku, unit_code, price_unit_code, package_quantity i measured_base_quantity. Són opcionals i mai s’infereixen: un valor absent queda null sense incidència i mai bloqueja la conversió, i package_quantity/measured_base_quantity mai es converteixen per si soles en quantitat facturada ni en una conversió d’unitats.

lines[].catalog_selection és una decisió a part, només humana: l’OCR mai l’escriu. Al pedaç de revisió, ometre catalog_selection conserva la selecció desada, null desvincula la línia (la seva evidència de compra no es toca) i un objecte la substitueix. En desar, només es verifiquen contra el catàleg de l’empresa que fa la petició les seleccions noves o canviades; un producte, variant, presentació o oferta de proveïdor d’una altra empresa —o que no existeix— respon 422 sense desar res ni canviar la versió:

// PUT /v1/purchase_scans/{id}/review amb un producte d'una altra empresa
{"expected_version": 7, "lines": [{"line_id": "019c...", "fields": {}, "catalog_selection": {"product_id": "<producte d'una altra empresa>"}}]}
// → 422, error.code = "validation_failed", error.param = "lines.0.catalog_selection.product_id"

Una referència desactivada es pot continuar vinculant en desar. La conversió torna a resoldre la selecció contra l’empresa de l’esborrany; si ja no és vàlida, respon 422 i no crea la factura — l’escaneig continua revisable per corregir o desvincular la línia.

Conversió i conflictes

Després de desar, fes servir la nova versió per a POST /v1/purchase_scans/{id}/convert. La conversió crea atòmicament un esborrany de despesa i vincula el seu original — és irreversible, i repetir-la sobre un escaneig ja convertit retorna 409 purchase_scan_already_converted. Consulta purchase_invoice_id per continuar a Despeses. Es requereixen EUR i dades fiscals resoltes; les despeses simplificades i les factures completes de proveïdors segueixen les respectives regles de validació. L’API pública i MCP requereixen un proveïdor existent quan sigui obligatori. Crear proveïdors o autoritzar excepcions de duplicat requereix un usuari interactiu autoritzat a l’app. external_id el defineixes tu en altres recursos, excepte el prefix purchase-scan:, reservat per al pont intern i rebutjat amb 422 parameter_invalid_value si l’envies.

Una versió obsoleta retorna 409 stale_scan_version: recarrega i concilia els canvis abans de reintentar. Un error 422 de conversió exposa els camps que has de corregir a error.details.field_errors. Reutilitza la clau d’idempotència només per a la mateixa mutació; després de canviar la revisió, fes servir una clau nova. L’escàner distingeix un duplicat exacte (mateix arxiu) d’un duplicat fiscal (mateix proveïdor i número de document); la resolució pública de duplicats (POST /v1/purchase_scans/{id}/duplicate_resolution, irreversible) admet link_existing amb purchase_invoice_id o archive — l’API v1 no autoritza forçar un duplicat exacte; aquesta excepció requereix un usuari interactiu autoritzat a l’app. Arxivar és reversible; restaurar no recupera un original ja purgat per retenció.

Originals, correu i clients

Descarrega els originals conservats mitjançant GET /v1/purchase_scans/{id}/source com a dades binàries; requereix la capacitat export sobre l’escaneig, o 403 forbidden_action. Una API key el creador de la qual ja no és membre de l’empresa es rebutja igual, tant en aquesta descàrrega com en qualsevol escriptura.

GET /v1/purchase_scan_emails llista remitent, assumpte i adjunts acceptats/rebutjats; les entrades acceptades enllacen amb els identificadors d’escaneig. L’app configura la bústia de l’escàner: una allowlist d’adreces o dominis remitents, i verificació SPF/DKIM/DMARC — només DMARC pass admet la ingesta, la resta queda parked o rejected amb un reason, i el veredicte brut es publica com a sender_authentication. La recepció desactivada o sense configurar es mostra explícitament. Tot correu admès queda en needs_review: la bústia mai crea automàticament un proveïdor ni un esborrany, ni tan sols amb un remitent a l’allowlist.

El SDK TypeScript exposa purchaseScans i purchaseScanEmails; les respostes binàries ofereixen toBuffer(). La CLI admet repetir --file-files per pujar un lot. Tots dos conserven els errors per arxiu i admeten claus d’idempotència explícites. Consulta el SDK, la CLI i el catàleg MCP.

MCP utilitza el mateix contracte de revisió, versió i conversió. La pujada i la descàrrega binària continuen sent operacions REST. A l’assistent web, les tools de l’escàner consulten dades i naveguen a la revisió humana. Les fotos/PDF del WhatsApp vinculat entren en aquest mateix escàner persistent; el canal pot proposar una conversió versionada a esborrany per a confirmació explícita o retornar un enllaç de revisió si queden processament o correccions pendents.

Consulta GET /v1/purchase_invoices/expense_categories (o MCP list_purchase_invoice_expense_categories) i fes servir un id retornat per a expense_category. Les categories pertanyen a l’empresa autenticada; es rebutgen noms i identificadors d’altres empreses.

Quota mensual i diària

Empresari inclou 100 escanejos al mes i 10 al dia per empresa; Enterprise no té límit d'escanejos del pla. Tots els usuaris de l'empresa comparteixen les dues quotes. Un escaneig desat amb deferred_reason=ocr_daily_quota_reached i deferred_until espera el reinici de la quota diària. El processament es reprèn automàticament: conserva'n l'ID i no el tornis a pujar ni cridis repetidament retry.

El detall limita attempts i audit a les últimes 50 entrades; utilitza attempts_total i audit_total per consultar els recomptes complets.

El consum d’OCR es mesura cada mes, per empresa, compartit per tots els canals de l’escàner (app, v1, MCP, bústia) i per l’assistent de WhatsApp. Un cop exhaurit, iniciar una nova extracció (pujada o reintent) respon 429 ocr_company_quota_exceeded amb Retry-After comptant els segons fins que la quota es reinicia l’1 del mes següent. Un arxiu ja admès i a la cua no es rebutja retroactivament.

Filtres i estadístiques

Els filtres de GET /v1/purchase_scans es combinen amb AND entre filtres i amb OR entre els valors separats per comes d’un mateix filtre: filter[document_kind] (invoice, simplified_qualified, ticket, delivery_note, other, undetermined), filter[file_kind] (pdf/image), filter[supplier_link_state], filter[has_issues] (sobre issue_count > 0), filter[sender], filter[source] i filter[supplier_id] (fins a 20 valors cadascun). Tota referència es comprova contra la teva empresa abans d’executar la consulta; una que no li pertanyi respon 422 sense revelar si existeix en una altra empresa:

GET /v1/purchase_scans?filter[document_kind]=ticket,invoice&filter[has_issues]=true&filter[sender]=@proveïdor.example

issue_count a cada fila és el recompte de camps encara pendents de revisar —el mateix número que mostraria la pantalla de revisió en obrir-la, sense edicions—, no el recompte brut de codis d’incidència de l’escaneig. uploaded_by és exclusiu de la SPA i queda exclòs de v1 i MCP, que només publiquen uploaded_by.name.

GET /v1/purchase_scans/stats admet scope=inbox (per defecte) o scope=history i retorna recomptes per estat, origen, tipus de document, tipus d’arxiu, estat del vincle amb el proveïdor i incidències sota facets.

En aquesta pàgina

Et donem un cop de mà?Contactar amb suport