Imports i dates
Com representa l'API els diners documentals, preus i quantitats precises de catàleg, dates, timestamps i límits Europe/Madrid.
Cada valor monetari, de data i d'hora de l'API pública segueix un petit conjunt de convencions fixes. Són les mateixes a tots els recursos, així que tan aviat com les gestiones en un lloc el teu client funciona a tot arreu.
Diners
Els imports sempre van en euros (EUR) — el camp currency és present a tots
els documents i és "EUR" a v1 (ISO 4217).
L’escriptura de documents públics continua limitada a EUR; els connectors de botigues poden convertir comandes entrants a EUR.
Els imports porten dos decimals (precisió de cèntims). La representació canònica és un string decimal amb exactament dos decimals, a l'estil Stripe:
{ "price": "1234.56" }Els diners dels documents i de les seves línies viatgen sempre com a string
decimal: el total, el subtotal i l'unit_price d'un document tornen com
a "1210.00", "1000.00" i "100.00", mai com a números JSON pelats. Els
números JSON que continues veient no són diners documentals — quantitats i
percentatges (quantity, tax_rate, discount_percent), els totals de
previsualització de POST /v1/companies/{company}/taxes/calculate-totals, els
agregats dels endpoints d'estadístiques i els imports dels informes fiscals en
cèntims enters. Converteix cada import a un tipus decimal fix al teu costat
(p. ex. Decimal a Python, un big-decimal o un enter d'unitats menors a JS).
No guardis mai els diners com un float binari en cru.
Deixa que l'API calculi els totals
No arrodoneixis ni calculis per endavant. Envia les dades en cru de cada
línia (quantity, unit_price, discount, el *_id de l'impost) i deixa que
l'API derivi el subtotal, l'IVA, el recàrrec, la retenció i el total general. El
servidor és l'única font de veritat per a cada total — si arrodoneixes els
imports de línia pel teu compte abans d'enviar-los, les teves xifres poden
divergir del que emmagatzema l'API.
El total d'un document segueix una sola fórmula a tota l'API:
total = subtotal + total_vat + total_surcharge − total_retentionSi necessites previsualitzar el desglossament abans de crear un document — per
a un resum de comanda, un carretó o per conciliar les teves pròpies xifres — crida
POST /v1/companies/{company}/taxes/calculate-totals amb les línies i llegeix el subtotal, el
total_vat, el total_surcharge, el total_retention i el total calculats
(imports en EUR), més un desglossament per línia en el mateix ordre:
{
"subtotal": 250,
"total_vat": 52.5,
"total_surcharge": 0,
"total_retention": 15,
"total": 287.5,
"lines": [
{ "subtotal": 100, "vat_amount": 21, "surcharge_amount": 0, "retention_amount": 0, "total": 121 }
]
}El mateix desglossament d'impostos per línia aplica a tots els documents de venda:
factures, pressupostos, proformes i albarans accepten tots un
retention_rate i un surcharge_rate per línia (retenció d'IRPF i recàrrec
d'equivalència, 0–100), i la seva capçalera porta els total_vat,
total_surcharge i total_retention agregats. La mateixa fórmula es compleix a
tot arreu. Cada línia a més retorna retention_rate i surcharge_rate a la
resposta, perquè puguis reconciliar el desglossament línia a línia.
El recàrrec d'equivalència segueix parells legals fixos. Quan una línia
declara un surcharge_rate, ha de coincidir amb el tipus d'IVA d'aquesta línia
segons el règim espanyol: 21% → 5.2%, 10% → 1.4%, 4% → 0.5%,
0% → 0%. Un parell il·legal (p. ex. tax_rate: 21 amb surcharge_rate: 1.4)
es rebutja amb 422 i els parells permesos es retornen a
error.allowed_values. Envia només el recàrrec que admet el tipus d'IVA de la
línia.
Despeses — impost per línia
Una despesa registra el que et va cobrar un proveïdor, així que
cadascuna de les seves línies accepta uns qualificadors fiscals extra que el
costat de venda cobreix a la seva manera. A
CreatePurchaseInvoiceRequest.lines[] pots fixar:
| Camp | Tipus | Significat |
|---|---|---|
retention_rate | number (0–100) | Retenció d'IRPF aplicada a la línia. |
surcharge_rate | number | Recàrrec d'equivalència, mateixos parells legals que en venda. |
vat_deductible | boolean | Informatiu — marca l'IVA com a deduïble. No canvia l'import pagat. |
exemption_reason | enum o null | Per què la línia està exempta o no subjecta (vegeu sota). |
Les línies de catàleg accepten a més discount_percent (0–100, aplicat abans
d'impostos i ja descomptat a subtotal) i el bloc purchase_measurement, que
separa embalums, quantitat facturada i cost unitari. En una línia mesurada l'API
retorna quantity i unit_price com a strings de 4 decimals; una línia legacy
conserva el número que sempre ha publicat, així que parseja tots dos. Consulta
Línies de compra mesurades.
El total per línia segueix la mateixa forma que al costat de venda, restant la retenció i sumant el recàrrec:
total de línia = subtotal + impostos − retention_amount + surcharge_amountEl surcharge_rate d'una línia de compra segueix els mateixos parells
legals IVA↔recàrrec que una línia de venda, validats al servidor:
21 → 5.2, 10 → 1.4, 4 → 0.5, 0 → 0. El parell 0 → 0 també és
vàlid al costat de compra — una línia exempta o a tipus zero porta un recàrrec
zero. Un parell il·legal es rebutja amb 422.
exemption_reason qualifica per què una línia queda fora de l'IVA ordinari. És
un enum o null (o absent), cosa que significa que la línia hereta la
qualificació de la capçalera de la factura, o no en declara cap:
| Valor | Classe |
|---|---|
E1, E2, E3, E4, E5, E6 | Exempta (causa d'exempció de la LIVA) |
N1, N2 | No subjecta (causa de no subjecció) |
null | Heretar de la capçalera / cap declarada |
Una línia de despesa que porta alhora un recàrrec i un motiu d'exempció:
{
"description": "Wholesale goods",
"quantity": 10,
"unit_price": "50.00",
"tax_rate": 21,
"surcharge_rate": 5.2,
"retention_rate": 0,
"vat_deductible": true,
"exemption_reason": null
}curl -s -X POST https://api.factuarea.com/v1/companies/$COMPANY_ID/purchase-invoices \
-H "Authorization: Bearer $FACTUAREA_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"supplier_id": "01931b3e-...s01",
"received_on": "2026-03-15",
"lines": [
{ "description": "Exempt service", "quantity": 1, "unit_price": "200.00", "tax_rate": 0, "surcharge_rate": 0, "exemption_reason": "E1" }
]
}' | jq '.data | {subtotal, total_vat, total_surcharge, total_retention, total}'Cèntims als informes fiscals. Els endpoints fiscals agregats (Modelo 303 /
347 via /v1/companies/{company}/tax-reports/*) retornen els seus imports com a cèntims enters,
no com a decimals d'EUR — p. ex. una base imposable acumulada de 25000
significa 250.00 €. Això està documentat camp a camp a la spec; tracta les
xifres dels informes fiscals com a unitats menors i divideix per 100 només per
mostrar-les.
Venciments de pagament
El payment_terms d'una factura és el seu calendari contractual de venciments. A diferència
dels totals anteriors, els seus imports mai no són nombres JSON i mai no s'infereixen.
| Camp | Contracte |
|---|---|
amount | Cadena amb exactament dos decimals i un signe menys opcional al principi: "40.00", "-20.00". Es rebutgen "0.00", 40, 40.5 i "40.5". Sempre en EUR (payment_terms_currency és "EUR" i de només lectura). |
| Signe | Totes les files tenen el signe de total_to_pay. Una factura rectificativa amb total negatiu té venciments negatius; els signes barrejats es rebutgen. |
| Suma | La suma exacta dels imports és igual a total_to_pay, suplerts inclosos. Res no es prorrateja, arrodoneix ni compensa per tu. |
due_date | Una data real YYYY-MM-DD (anys 0001 a 9999). Les files conserven l'ordre que envies i les seves dates no poden decréixer; s'admeten dates iguals. |
Una factura de 121.00 repartida en tres venciments:
{
"payment_terms": [
{ "due_date": "2026-02-15", "amount": "40.00", "payment_means": "01" },
{ "due_date": "2026-03-15", "amount": "30.00", "payment_means": "04",
"account": { "iban": "ES9121000418450200051332", "bic": "CAIXESBBXXX" } },
{ "due_date": "2026-04-15", "amount": "51.00", "payment_means": "04",
"account": { "iban": "ES9121000418450200051332", "bic": "CAIXESBBXXX" } }
]
}40.00 + 30.00 + 51.00 suma 121.00. Una factura rectificativa de -50.00 porta
"-20.00" i "-30.00". Un calendari que no suma, o amb un import que no és una cadena de dos
decimals, respon 422 invalid_invoice_payment_terms i no escriu res: param anomena
la fila (payment_terms.1.amount) o payment_terms per a l'ordre, el signe i el total.
Ometre, null i [] signifiquen coses diferents (desconegut, treure, sense calendari de forma
explícita); consulta Dades de negoci de la factura.
Amb terminis, la factura venç el dia del seu últim termini: a l'exemple anterior,
due_on ha de ser 2026-04-15 per emetre-la. Un esborrany conserva una altra data, però
emetre'l respon 422 invoice_due_date_not_last_instalment; consulta
el calendari de pagaments.
Dates
Les dates de calendari (sense component horari) usen YYYY-MM-DD — la forma
de data completa ISO-8601 / RFC 3339.
Això cobreix camps com ara issued_on, due_on, paid_on, valid_until,
delivery_date, received_on, start_on i end_on:
{
"issued_on": "2026-03-15",
"due_on": "2026-04-14",
"paid_on": "2026-03-20"
}Envia les dates en el mateix format. Una data no té hora ni zona horària — és el dia de calendari tal com queda registrat per al document.
Període de facturació i data de generació
invoicing_period és { "start_date", "end_date" }, dues dates reals amb
start_date <= end_date (les dates iguals són vàlides). Un període que envies substitueix
el període sencer i null l'esborra. Cap de les dues dates porta hora ni zona.
La data de generació d'una factura recurrent no és un camp que enviïs: el servidor la
fixa com el dia de negoci de la petició que genera la factura, i repetir la mateixa petició
retorna la factura ja creada. El calendari relatiu d'una recurrència
(payment_terms_template) dona a cada factura nova les seves pròpies dates de venciment,
comptades des d'aquell dia.
Timestamps
Els camps d'instant temporal (metadades d'auditoria i cicle de vida com ara
created_at, updated_at, signed_at, last_delivery_at) usen strings de
data-hora ISO-8601 / RFC 3339 complets. La majoria s'emeten en UTC amb un
sufix Z:
{ "created_at": "2026-05-15T10:34:21Z" }Alguns timestamps porten en el seu lloc un offset Europe/Madrid explícit
(+01:00 a l'hivern, +02:00 a l'estiu):
{ "created_at": "2026-04-15T10:31:05+02:00" }Totes dues formes són ISO-8601 vàlides i denoten el mateix tipus de valor: un
instant exacte. Analitza l'offset — no donis per fet que el string sempre
està en UTC. Un parser ISO-8601 en condicions (Instant.parse,
datetime.fromisoformat, new Date(...), Carbon::parse) gestiona Z i
±hh:mm de manera idèntica i normalitza a l'instant absolut.
Zona horària per a les quotes
La quota mensual del rate limit es reinicia el dia 1 de cada mes natural a
les 00:00 Europe/Madrid (CET/CEST), no en UTC. La quota per minut és una
finestra lliscant i la capçalera X-RateLimit-Reset és un UNIX timestamp
(segons des de l'epoch, independent de la zona horària). Consulta
Rate limits per a la semàntica completa de les finestres.
Sempre que l'API necessita una única referència de calendari civil per a un límit de negoci — períodes fiscals, el reinici de la quota mensual — aquesta referència és Europe/Madrid.
Referència ràpida
| Valor | Format | Exemple |
|---|---|---|
| Diners i totals documentals | EUR, dos decimals — string decimal | "1234.56" |
| Preu / cost unitari de catàleg | EUR, fins a quatre decimals | "8.7500" |
| Quantitat / estoc de catàleg | Fins a quatre decimals | "12.3750" |
| Factor de conversió | Fins a sis decimals | "12.000000" |
| Divisa | ISO 4217, sempre EUR a v1 | "EUR" |
| Imports d'informes fiscals | Cèntims enters (unitats menors) | 25000 → 250.00 € |
| Data | YYYY-MM-DD (ISO-8601 data completa) | "2026-03-15" |
| Import d'un venciment | Cadena decimal en EUR amb signe i exactament dos decimals; la suma és igual a total_to_pay | "-20.00" |
| Timestamp | ISO-8601 data-hora, normalment UTC Z, de vegades ±hh:mm | "2026-05-15T10:34:21Z" |
| Calendari de quotes / fiscal | Hora civil Europe/Madrid | dia 1, 00:00 CET/CEST |
Descripcions addicionals de línia
Les línies admeten additional_description nullable de fins a 5000 caràcters al costat de description. Està disponible en factures i rectificatives, pressupostos, proformes, albarans, despeses i plantilles recurrents. Mantén aquest detall separat de quantitats, preus, camps fiscals i identificadors del catàleg; afegir descripció no canvia el càlcul de l’import.