Factuarea APIDevelopers

Tax reports

Generate Modelo 303, 347 and 130, choose the right output format, and tell the file you submit apart from the workbook you review.

A tax report is a filing computed from your own invoicing data for a fiscal period and materialised as a file. Factuarea covers the three Spanish models that a company issuing invoices files on its own behalf, produces each one in three formats, and keeps every generation in a history you can list, audit and download again.

All endpoints live under https://api.factuarea.com/v1. Generating uses tax_reports:write; previewing, listing and downloading use tax_reports:read.

The three models

ModelWhat it declaresPeriodEndpoint
Modelo 303Quarterly IVA: output VAT, equivalence surcharge, intra-EU acquisitions, reverse charge, deductible input VAT and the resulting balance.Year + quarterPOST /v1/tax_reports/303
Modelo 347Annual operations with third parties above 3,005.06 € per counterparty and year, split into the four quarters.Year onlyPOST /v1/tax_reports/347
Modelo 130Quarterly IRPF instalment for the self-employed under direct estimation. The calculation is cumulative from 1 January to the end of the quarter.Year + quarterPOST /v1/tax_reports/130

year and format are required on all three. quarter is required by 303 and 130, and ignored by 347 — the 347 is annual, and there is no such thing as a quarterly one. Supported fiscal years start at 2024.

curl -X POST https://api.factuarea.com/v1/tax_reports/303 \
  -H "Authorization: Bearer $FACTUAREA_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "year": 2026, "quarter": 1, "format": "txt_aeat" }'

Modelo 131 (objective estimation, the "módulos" regime) is out of scope. A company on that regime asking for a 130 gets 422 with a message pointing at the 131 instead of a file it could not file.

Three formats, one calculation

Every model produces the same three outputs, and all three are built from the same domain calculation. They differ in what they are for, not in what they say.

formatWhat it isCan you file it?
txt_aeatThe official positional file that follows the AEAT record layout of the model's ministerial order.Yes — this is the one you submit.
pdfA readable rendering of the filing, for archiving and for sending to a client or an advisor.No.
excelA working workbook (.xlsx) for reviewing and reconciling the figures before filing.No.

Only txt_aeat is filed with the AEAT. The PDF and the spreadsheet are review material: they are never uploaded to the Sede Electrónica and never replace the official file in any procedure.

That said — and this is the other half of the rule — the figures in the PDF and in the workbook are trustworthy. They are not recomputed for the presentation layer: they come from the very same calculation that produces the official file, so reconciling against them is reconciling against what you will file. A number that differed between two formats of the same filing is impossible by construction.

The Excel workbook

The workbook has exactly two sheetsResumen (summary) and Detalle (detail) — and both open with the same context label: model, fiscal period and the declaring company with its NIF. A sheet gets copied into another workbook or printed on its own, and none of the surrounding application context travels with it.

The first rows of Resumen, before any data, carry the notice in Spanish:

AVISO: este libro es material de trabajo y NO es presentable ante la AEAT.
La presentación se realiza con el fichero oficial en formato TXT que genera
la propia aplicación.

The warning lives inside the file on purpose. The workbook is downloaded, attached to an email and opened on a different computer — which is exactly where someone might try to file it. A warning that only existed on the screen that triggered the download would not be there at that moment.

What each model puts in each sheet:

ModelResumenDetalle
347Declared clients and suppliers, total declared amount, and how many counterparties cleared the 3,005.06 € threshold.One row per counterparty: type, NIF, name, province, country, annual base and the four quarters. Clients first, then suppliers — the same order as the official file's records.
303Accrued base and tax, surcharge, intra-EU, reverse charge, corrective entries, deductible input VAT, carried-forward credit and the resulting balance.Accrued VAT and surcharge broken down by tax rate, plus eleven fixed blocks that are always emitted, zeros included.
130The derived boxes: the chain that ends in the amount payable.The starting boxes that feed them, so the result is traceable without redoing the arithmetic.

Two properties worth relying on:

  • Amounts are numbers, not formatted text. A column of amounts can be summed in the sheet with no conversion, and a zero is written as 0 rather than left blank — in a financial report an empty cell reads as "no data", not as "zero".
  • In every 347 row, the four quarters add up to the annual base. The Tipo column is what tells a purchase from a sale once you sort the sheet.

A year with no counterparty above the threshold still produces a workbook: the detail sheet comes back empty and the summary says so, quoting the threshold. That is the ordinary case for a small company, not an error — you should not have to guess whether the calculation ran.

Generate, download, keep the history

A generation is a persisted resource. The three model endpoints return 201 with the report and its id; the file itself is fetched separately, as many times as you need.

# 1. Generate — returns 201 with the report id
curl -X POST https://api.factuarea.com/v1/tax_reports/347 \
  -H "Authorization: Bearer $FACTUAREA_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "year": 2025, "format": "excel" }'

# 2. Download the file it produced
curl -G https://api.factuarea.com/v1/tax_reports/01931b3e-7c4a-7f2e-9a8b-3c5d6e7f8a0b/download \
  -H "Authorization: Bearer $FACTUAREA_API_KEY" \
  --output modelo-347-2025.xlsx

GET /v1/tax_reports/{tax_report}/download streams the file with the content type of the format it was generated in — positional text, PDF or spreadsheet — and adds an X-Tax-Report-Hash header so you can verify that the bytes you archived are the bytes that were generated.

The rest of the domain reads that same history:

EndpointWhat it gives you
GET /v1/tax_reports/historyEvery generation of the company, newest first, filterable by type and year, with cursor pagination.
POST /v1/tax_reports/find-by-periodThe most recent generation for a type + year (+ quarter), or 404 if the period has never been generated.
GET /v1/tax_reports/statsAggregate KPIs: totals by model and by format, accumulated file size and the current fiscal period.
GET /v1/tax_reports/{tax_report}/activitiesThe activity timeline of one generation — when it was generated and by whom.

To see the numbers before committing to a file, use POST /v1/tax_reports/preview with type, year and quarter: it computes the same breakdown, persists nothing and writes no file. It is the call to make behind a "review before filing" screen.

Errors you should expect

StatuscodeWhen
422invalid_periodYear outside the supported range, or a missing/invalid quarter for a model that needs one.
422insufficient_data_for_reportThe period has nothing to file, or an invoice in it lacks a field the model requires.
422unsupported_formatThe model does not produce that format for that fiscal year.
422report_format_invalidformat outside txt_aeat, pdf, excel.
422tax_report_type_invalidtype outside modelo_303, modelo_347, modelo_130.
404tax_report_not_foundThe id does not resolve to a report of your company.

Full reference in All error codes.

From an agent

The same nine operations are exposed as MCP tools — generate_tax_report_303, generate_tax_report_347 and generate_tax_report_130 under tax_reports:write, and preview, find-by-period, history, stats, activities and download under tax_reports:read. See the tool catalog.

Next steps

On this page

Need a hand?Contact support