Factuarea API
Core concepts

Amounts & dates

How the API represents money (EUR, two decimals), dates (YYYY-MM-DD), timestamps (ISO-8601) and the Europe/Madrid timezone used for quota resets.

Every monetary, date and time value in the public API follows a small set of fixed conventions. They are the same across every resource, so once you handle them in one place your client works everywhere.

Money

Amounts are always in euros (EUR) — the currency field is present on every document and is "EUR" in v1 (ISO 4217). There is no multi-currency support yet.

Amounts carry two decimal places (cents precision). The canonical representation is a decimal string with exactly two decimals, Stripe-style:

{ "price": "1234.56" }

Some resources currently emit amounts as JSON numbers (floats) rather than decimal strings — for example a document's total, subtotal or unit_price come back as 1802.9, 968, 100. Write your parser to accept both a string and a number for any money field, and normalise to a fixed decimal type on your side (e.g. Decimal in Python, a big-decimal / minor-units integer in JS). Never store money as a raw binary float.

Let the API compute totals

Do not pre-round and do not pre-compute. Send the raw inputs of each line (quantity, unit_price, discount, the tax *_id) and let the API derive the subtotal, VAT, surcharge, retention and the grand total. The server is the single source of truth for every total — if you round line amounts yourself before sending them, your figures can drift from what the API stores.

The total of a document follows one formula across the whole API:

total = subtotal + total_vat + total_surcharge − total_retention

If you need to preview the breakdown before creating a document — for an order summary, a cart, or to reconcile your own figures — call POST /v1/taxes/calculate-totals with the lines and read back the computed subtotal, total_vat, total_surcharge, total_retention and total (amounts in EUR), plus a per-line breakdown in the same order:

{
  "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 }
  ]
}

The same per-line tax breakdown applies to every sales document, not just invoices: quotes, proformas and delivery notes also accept a per-line retention_rate and surcharge_rate (IRPF withholding and equivalence surcharge, 0–100), and their header carries the aggregated total_vat, total_surcharge and total_retention. The same formula holds everywhere.

Cents in tax reports. Aggregated fiscal endpoints (Modelo 303 / 347 via /v1/tax_reports/*) return their amounts as integer cents, not EUR decimals — e.g. an accumulated taxable base of 25000 means 250.00 €. This is documented per field in the spec; treat tax-report figures as minor units and divide by 100 only for display.

Dates

Calendar dates (no time component) use YYYY-MM-DD — the ISO-8601 / RFC 3339 full-date form. This covers fields such as issued_on, due_on, paid_on, valid_until, delivery_date, received_on, start_on and end_on:

{
  "issued_on": "2026-03-15",
  "due_on": "2026-04-14",
  "paid_on": "2026-03-20"
}

Send dates in the same format. There is no time and no timezone on a date — it is the calendar day as recorded for the document.

Timestamps

Instant-in-time fields (audit and lifecycle metadata such as created_at, updated_at, signed_at, last_delivery_at) use full ISO-8601 / RFC 3339 date-time strings. Most are emitted in UTC with a Z suffix:

{ "created_at": "2026-05-15T10:34:21Z" }

Some timestamps carry an explicit Europe/Madrid offset instead (+01:00 in winter, +02:00 in summer):

{ "created_at": "2026-04-15T10:31:05+02:00" }

Both forms are valid ISO-8601 and denote the same kind of value: an exact instant. Parse the offset — do not assume the string is always UTC. A proper ISO-8601 parser (Instant.parse, datetime.fromisoformat, new Date(...), Carbon::parse) handles Z and ±hh:mm identically and normalises to the absolute instant.

Timezone for quotas

The monthly rate-limit quota resets on day 1 of each calendar month at 00:00 Europe/Madrid (CET/CEST), not UTC. The per-minute quota is a sliding window and the X-RateLimit-Reset header is a UNIX timestamp (seconds since the epoch, timezone-independent). See Rate limits for the full window semantics.

Whenever the API needs a single civil-calendar reference for a business boundary — fiscal periods, the monthly quota reset — that reference is Europe/Madrid.

Quick reference

ValueFormatExample
MoneyEUR, two decimals — decimal string (some fields emit a number)"1234.56" / 1802.9
CurrencyISO 4217, always EUR in v1"EUR"
Tax-report amountsInteger cents (minor units)25000 → 250.00 €
DateYYYY-MM-DD (ISO-8601 full-date)"2026-03-15"
TimestampISO-8601 date-time, usually UTC Z, sometimes ±hh:mm"2026-05-15T10:34:21Z"
Quota / fiscal calendarEurope/Madrid civil timeday 1, 00:00 CET/CEST

On this page