{
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "$id": "https://artifacts.apis.io/frihet-io/json-schema/frihet-io-quarterly-summary-schema.json",
  "title": "QuarterlySummary",
  "x-generated": "2026-11-09",
  "x-method": "derived",
  "x-generator": "derive-json-schema.py",
  "x-source": "openapi/frihet-io-openapi.json#/components/schemas/QuarterlySummary",
  "type": "object",
  "properties": {
    "data": {
      "type": "object",
      "properties": {
        "period": {
          "type": "string"
        },
        "months": {
          "type": "array",
          "items": {
            "type": "string"
          }
        },
        "modelo303": {
          "type": "object",
          "description": "Pre-filled Modelo 303 (IVA return) figures. Read-only summary, never submitted. Tax family per invoice = explicit taxType, otherwise the issuer workspace's fiscal zone (peninsula = IVA, canarias = IGIC, ceuta_melilla = IPSI); the client's location never decides it. Figures are returned only for a workspace that declares the peninsula fiscal zone with country ES, and whose fiscal-profile zone (if set) is peninsula too. Any other workspace gets a refusal here instead and NO figures: only `error`, `code` (MODELO_303_NOT_APPLICABLE), `reason`, `applicableModel` and, for zone_not_applicable, `fiscalZone`: the body of the 409 of GET /fiscal/modelo/303 without `meta`. The rest of the payload is unchanged.",
          "properties": {
            "code": {
              "type": "string",
              "enum": [
                "MODELO_303_NOT_APPLICABLE"
              ],
              "description": "Refusal only. Present instead of the figures below."
            },
            "reason": {
              "type": "string",
              "enum": [
                "zone_undeclared",
                "zone_not_applicable",
                "zone_country_mismatch"
              ],
              "description": "Refusal only. zone_undeclared = no declared country and fiscal zone (or an unrecognised fiscal-profile zone); zone_not_applicable = the declared zone does not file Modelo 303; zone_country_mismatch = peninsula declared with a country other than ES."
            },
            "fiscalZone": {
              "type": "string",
              "enum": [
                "canarias",
                "ceuta_melilla",
                "eu",
                "world"
              ],
              "description": "Refusal only, when reason is zone_not_applicable."
            },
            "applicableModel": {
              "type": [
                "string",
                "null"
              ],
              "description": "Refusal only. The IGIC return a Canary Islands workspace files instead (\"420\"); null otherwise."
            },
            "error": {
              "type": "string",
              "description": "Refusal only. Human-readable explanation."
            },
            "baseImponible": {
              "type": "number",
              "description": "Total tax base across all tax families (IVA, IGIC, IPSI, exempt)"
            },
            "cuotaRepercutida": {
              "type": "number",
              "description": "Output IVA charged to clients (IGIC and IPSI excluded, see outOfScope)"
            },
            "outOfScope": {
              "type": "object",
              "description": "IGIC (Canarias) and IPSI (Ceuta/Melilla) base and cuota kept out of the Modelo 303 figures. Informational; not part of the IVA return.",
              "properties": {
                "igic": {
                  "type": "object",
                  "properties": {
                    "base": {
                      "type": "number"
                    },
                    "cuota": {
                      "type": "number"
                    }
                  }
                },
                "ipsi": {
                  "type": "object",
                  "properties": {
                    "base": {
                      "type": "number"
                    },
                    "cuota": {
                      "type": "number"
                    }
                  }
                }
              }
            },
            "baseDeducible": {
              "type": "number",
              "description": "Deductible expense base"
            },
            "cuotaDeducible": {
              "type": "number",
              "description": "Input VAT (paid on deductible expenses)"
            },
            "resultado": {
              "type": "number",
              "description": "Net VAT (output - input)"
            }
          }
        },
        "modelo130": {
          "type": "object",
          "description": "Pre-filled Modelo 130 (IRPF pago fraccionado, estimación directa) figures. Read-only, never submitted. Per the AEAT instructions every figure is YEAR-TO-DATE (1 January to the last day of the requested quarter), not the quarter alone. Accrual basis (invoice issueDate, expense date); draft and cancelled invoices are excluded. Casillas 13-19 (minoraciones, vivienda habitual, complementaria) are not computed and are returned as null.",
          "properties": {
            "ingresos": {
              "type": "number",
              "description": "Casilla 01 — computable income, year-to-date"
            },
            "gastos": {
              "type": "number",
              "description": "Casilla 02 — deductible expenses, year-to-date"
            },
            "rendimientoNeto": {
              "type": "number",
              "description": "Casilla 03 — net income (ingresos - gastos), year-to-date, may be negative"
            },
            "pagoFraccionado": {
              "type": "number",
              "description": "Casilla 12 — max(0, casilla 07): 20% of the positive year-to-date net income minus prior positive payments of the year and minus retenciones. Before the non-computed reductions of casillas 13-16."
            },
            "retencionesSoportadas": {
              "type": "number",
              "description": "Casilla 06 — IRPF withheld on issued invoices, year-to-date"
            },
            "basis": {
              "type": "string",
              "enum": [
                "ytd"
              ]
            },
            "year": {
              "type": "integer"
            },
            "quarter": {
              "type": "integer",
              "minimum": 1,
              "maximum": 4
            },
            "porcentaje": {
              "type": "number",
              "description": "Percentage applied in casilla 04 (always 20; see notModelled)"
            },
            "casillas": {
              "type": "object",
              "description": "Official AEAT casillas. Non-computed casillas are null.",
              "properties": {
                "c01": {
                  "type": "number"
                },
                "c02": {
                  "type": "number"
                },
                "c03": {
                  "type": "number"
                },
                "c04": {
                  "type": "number",
                  "description": "20% of the positive casilla 03, otherwise 0"
                },
                "c05": {
                  "type": "number",
                  "description": "Sum of the positive casilla 07 of earlier quarters of the same year, recomputed from stored documents"
                },
                "c06": {
                  "type": "number"
                },
                "c07": {
                  "type": "number",
                  "description": "c04 - c05 - c06, may be negative"
                },
                "c12": {
                  "type": "number",
                  "description": "max(0, c07)"
                },
                "c13": {
                  "type": "null"
                },
                "c14": {
                  "type": "null"
                },
                "c15": {
                  "type": "null"
                },
                "c16": {
                  "type": "null"
                },
                "c17": {
                  "type": "null"
                },
                "c18": {
                  "type": "null"
                },
                "c19": {
                  "type": "null"
                }
              }
            },
            "pagosAnterioresPorTrimestre": {
              "type": "array",
              "description": "Recomputed casilla 07 of each earlier quarter of the year (source of c05)",
              "items": {
                "type": "object",
                "properties": {
                  "quarter": {
                    "type": "integer"
                  },
                  "c07": {
                    "type": "number"
                  }
                }
              }
            },
            "excluded": {
              "type": "object",
              "description": "Counted invoices / expenses skipped because their date is missing or not ISO YYYY-MM-DD",
              "properties": {
                "invoicesWithoutValidDate": {
                  "type": "integer"
                },
                "expensesWithoutValidDate": {
                  "type": "integer"
                }
              }
            },
            "notModelled": {
              "type": "array",
              "description": "AEAT rules this summary does not apply",
              "items": {
                "type": "string"
              }
            },
            "sourceUrl": {
              "type": "string",
              "description": "AEAT Modelo 130 instructions used as ground truth"
            }
          }
        },
        "summary": {
          "type": "object",
          "properties": {
            "totalRevenue": {
              "type": "number"
            },
            "totalExpenses": {
              "type": "number"
            },
            "invoiceCount": {
              "type": "integer"
            },
            "clientCount": {
              "type": "integer"
            }
          }
        }
      }
    },
    "meta": {
      "type": "object",
      "properties": {
        "requestId": {
          "type": "string"
        },
        "timestamp": {
          "type": "string",
          "format": "date-time"
        }
      }
    }
  }
}