{
  "openapi": "3.1.0",
  "info": {
    "title": "API de LeeFactura",
    "version": "1.0.0",
    "description": "API de solo lectura para consultar clientes, facturas y borradores de impuestos de una cuenta de LeeFactura. Incluida en los planes Gestoría y Gestoría Pro. Los permisos de una clave: `clients:read` (Clientes), `invoices:read` (Facturas), `taxes:read` (Impuestos)."
  },
  "servers": [
    {
      "url": "https://leefactura.es/api/v1"
    }
  ],
  "paths": {
    "/account": {
      "get": {
        "summary": "Quién es esta clave",
        "description": "Devuelve la cuenta, el plan, el alcance de la clave y sus topes. Sirve para comprobar que la clave funciona.",
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "parameters": [],
        "responses": {
          "200": {
            "description": "Correcto",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                },
                "example": {
                  "account": {
                    "id": "9d1e…",
                    "name": "Gestoría Ejemplo",
                    "plan": "gestoria"
                  },
                  "key": {
                    "id": "c4a2…",
                    "name": "Programa de la gestoría",
                    "scopes": [
                      "clients:read",
                      "invoices:read"
                    ],
                    "client_ids": null,
                    "expires_at": null
                  },
                  "limits": {
                    "per_minute": 60,
                    "per_day": 5000
                  }
                }
              }
            }
          },
          "400": {
            "description": "Parámetro no válido",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "Clave ausente o no válida",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "Sin permiso o sin plan",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "No existe",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "Demasiadas peticiones",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/clients": {
      "get": {
        "summary": "Lista de clientes",
        "description": "Los clientes de la cuenta que la clave puede ver, del más antiguo al más reciente. Permiso necesario: `clients:read`.",
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "parameters": [
          {
            "name": "page",
            "in": "query",
            "required": false,
            "description": "Página, desde 1.",
            "schema": {
              "type": "string"
            },
            "example": "1"
          },
          {
            "name": "per_page",
            "in": "query",
            "required": false,
            "description": "Resultados por página: de 1 a 200 (50 por defecto).",
            "schema": {
              "type": "string"
            },
            "example": "50"
          }
        ],
        "responses": {
          "200": {
            "description": "Correcto",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                },
                "example": {
                  "data": [
                    {
                      "id": "0b5b…",
                      "name": "Taller Mecánico Juan",
                      "tax_id": "12345678Z",
                      "address": "Calle Mayor 1, 08001 Barcelona",
                      "is_own_business": false,
                      "is_freelancer": true,
                      "created_at": "2026-02-03T09:12:00Z"
                    }
                  ],
                  "pagination": {
                    "page": 1,
                    "per_page": 2,
                    "total": 1,
                    "total_pages": 1
                  }
                }
              }
            }
          },
          "400": {
            "description": "Parámetro no válido",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "Clave ausente o no válida",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "Sin permiso o sin plan",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "No existe",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "Demasiadas peticiones",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/clients/{id}": {
      "get": {
        "summary": "Un cliente",
        "description": "La ficha de un cliente. 404 si no existe o la clave no llega a él. Permiso necesario: `clients:read`.",
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "description": "Identificador del cliente.",
            "schema": {
              "type": "string"
            },
            "example": "7f3c2a1e-9d4b-4c6a-8e21-5b0d7a9c4f10"
          }
        ],
        "responses": {
          "200": {
            "description": "Correcto",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                },
                "example": {
                  "data": {
                    "id": "0b5b…",
                    "name": "Taller Mecánico Juan",
                    "tax_id": "12345678Z",
                    "address": null,
                    "is_own_business": false,
                    "is_freelancer": true,
                    "created_at": "2026-02-03T09:12:00Z"
                  }
                }
              }
            }
          },
          "400": {
            "description": "Parámetro no válido",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "Clave ausente o no válida",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "Sin permiso o sin plan",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "No existe",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "Demasiadas peticiones",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/sales-invoices": {
      "get": {
        "summary": "Facturas de venta emitidas",
        "description": "Las facturas emitidas desde LeeFactura, de la más reciente a la más antigua, con su estado de cobro. Permiso necesario: `invoices:read`.",
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "parameters": [
          {
            "name": "client_id",
            "in": "query",
            "required": false,
            "description": "Solo los de este cliente.",
            "schema": {
              "type": "string"
            },
            "example": "0b5b4d54-6f5e-4b2d-9b0a-5d1a9b8c3e11"
          },
          {
            "name": "from",
            "in": "query",
            "required": false,
            "description": "Fecha de emisión desde (AAAA-MM-DD, incluida).",
            "schema": {
              "type": "string"
            },
            "example": "2026-01-01"
          },
          {
            "name": "to",
            "in": "query",
            "required": false,
            "description": "Fecha de emisión hasta (AAAA-MM-DD, incluida).",
            "schema": {
              "type": "string"
            },
            "example": "2026-03-31"
          },
          {
            "name": "page",
            "in": "query",
            "required": false,
            "description": "Página, desde 1.",
            "schema": {
              "type": "string"
            },
            "example": "1"
          },
          {
            "name": "per_page",
            "in": "query",
            "required": false,
            "description": "Resultados por página: de 1 a 200 (50 por defecto).",
            "schema": {
              "type": "string"
            },
            "example": "50"
          }
        ],
        "responses": {
          "200": {
            "description": "Correcto",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                },
                "example": {
                  "data": [
                    {
                      "id": "7f3c…",
                      "client_id": "0b5b…",
                      "number": "2026-0007",
                      "year": 2026,
                      "issue_date": "2026-03-01",
                      "due_date": "2026-03-31",
                      "invoice_type": "F1",
                      "recipient": {
                        "name": "Cliente SL",
                        "tax_id": "B22222222",
                        "address": "Calle 2",
                        "postal_code": "08001",
                        "city": "Barcelona",
                        "province": "Barcelona",
                        "country": "ES"
                      },
                      "lines": [
                        {
                          "description": "Reparación",
                          "quantity": 2,
                          "unit_price": 50,
                          "vat_rate": 21,
                          "exemption": null,
                          "base": 100,
                          "vat_amount": 21
                        }
                      ],
                      "totals": {
                        "base": 100,
                        "vat": 21,
                        "withholding_rate": null,
                        "withholding_amount": null,
                        "total": 121
                      },
                      "payment_method": "transferencia",
                      "notes": null,
                      "status": {
                        "annulled": false,
                        "annulled_at": null,
                        "collection": {
                          "state": "pendiente",
                          "paid": 0,
                          "pending": 121,
                          "days_overdue": 0
                        }
                      },
                      "rectification": null,
                      "created_at": "2026-03-01T10:00:00Z"
                    }
                  ],
                  "pagination": {
                    "page": 1,
                    "per_page": 50,
                    "total": 1,
                    "total_pages": 1
                  }
                }
              }
            }
          },
          "400": {
            "description": "Parámetro no válido",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "Clave ausente o no válida",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "Sin permiso o sin plan",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "No existe",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "Demasiadas peticiones",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/sales-invoices/{id}": {
      "get": {
        "summary": "Una factura de venta",
        "description": "Una factura emitida con el mismo formato que en la lista. 404 si no existe o es de un cliente al que la clave no llega. Permiso necesario: `invoices:read`.",
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "description": "Identificador de la factura.",
            "schema": {
              "type": "string"
            },
            "example": "7f3c2a1e-9d4b-4c6a-8e21-5b0d7a9c4f10"
          }
        ],
        "responses": {
          "200": {
            "description": "Correcto",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                },
                "example": {
                  "data": {
                    "id": "7f3c…",
                    "number": "2026-0007",
                    "…": "…"
                  }
                }
              }
            }
          },
          "400": {
            "description": "Parámetro no válido",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "Clave ausente o no válida",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "Sin permiso o sin plan",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "No existe",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "Demasiadas peticiones",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/scanned-invoices": {
      "get": {
        "summary": "Facturas, tickets y albaranes escaneados",
        "description": "Los documentos leídos por la IA (solo los ya leídos), del más reciente al más antiguo. Sin enlaces al archivo original. Permiso necesario: `invoices:read`.",
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "parameters": [
          {
            "name": "client_id",
            "in": "query",
            "required": false,
            "description": "Solo los de este cliente.",
            "schema": {
              "type": "string"
            },
            "example": "0b5b4d54-6f5e-4b2d-9b0a-5d1a9b8c3e11"
          },
          {
            "name": "type",
            "in": "query",
            "required": false,
            "description": "gasto, ingreso o albaran.",
            "schema": {
              "type": "string"
            },
            "example": "gasto"
          },
          {
            "name": "from",
            "in": "query",
            "required": false,
            "description": "Fecha de la factura desde (AAAA-MM-DD, incluida).",
            "schema": {
              "type": "string"
            },
            "example": "2026-01-01"
          },
          {
            "name": "to",
            "in": "query",
            "required": false,
            "description": "Fecha de la factura hasta (AAAA-MM-DD, incluida).",
            "schema": {
              "type": "string"
            },
            "example": "2026-03-31"
          },
          {
            "name": "page",
            "in": "query",
            "required": false,
            "description": "Página, desde 1.",
            "schema": {
              "type": "string"
            },
            "example": "1"
          },
          {
            "name": "per_page",
            "in": "query",
            "required": false,
            "description": "Resultados por página: de 1 a 200 (50 por defecto).",
            "schema": {
              "type": "string"
            },
            "example": "50"
          }
        ],
        "responses": {
          "200": {
            "description": "Correcto",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                },
                "example": {
                  "data": [
                    {
                      "id": "a91e…",
                      "client_id": "0b5b…",
                      "type": "gasto",
                      "status": "completed",
                      "source": "web",
                      "created_at": "2026-03-02T08:30:00Z",
                      "document": {
                        "provider_name": "Ferretería Industrial SL",
                        "tax_id": "B12345674",
                        "tax_id_valid": true,
                        "number": "A-2026-114",
                        "date": "2026-02-28",
                        "base": 100,
                        "vat": 21,
                        "total": 121,
                        "withholding_amount": null,
                        "withholding_category": null,
                        "vat_breakdown": [
                          {
                            "rate": 21,
                            "base": 100,
                            "quota": 21,
                            "type": "iva"
                          }
                        ],
                        "deductible_expense_percentage": 100,
                        "deductible_vat_percentage": 100,
                        "confidence": "high",
                        "reviewed": true
                      }
                    }
                  ],
                  "pagination": {
                    "page": 1,
                    "per_page": 50,
                    "total": 1,
                    "total_pages": 1
                  }
                }
              }
            }
          },
          "400": {
            "description": "Parámetro no válido",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "Clave ausente o no válida",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "Sin permiso o sin plan",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "No existe",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "Demasiadas peticiones",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/scanned-invoices/{id}": {
      "get": {
        "summary": "Un documento escaneado",
        "description": "Un documento leído por la IA con el mismo formato que en la lista. Permiso necesario: `invoices:read`.",
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "description": "Identificador del documento.",
            "schema": {
              "type": "string"
            },
            "example": "7f3c2a1e-9d4b-4c6a-8e21-5b0d7a9c4f10"
          }
        ],
        "responses": {
          "200": {
            "description": "Correcto",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                },
                "example": {
                  "data": {
                    "id": "a91e…",
                    "type": "gasto",
                    "…": "…"
                  }
                }
              }
            }
          },
          "400": {
            "description": "Parámetro no válido",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "Clave ausente o no válida",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "Sin permiso o sin plan",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "No existe",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "Demasiadas peticiones",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/tax-drafts/{model}": {
      "get": {
        "summary": "Borrador del modelo 303 o 130",
        "description": "El borrador de un cliente en un trimestre, con el mismo cálculo que el panel: orientativo, no una declaración. El modelo 130 es acumulado desde el 1 de enero. Permiso necesario: `taxes:read`.",
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "parameters": [
          {
            "name": "model",
            "in": "path",
            "required": true,
            "description": "303 o 130.",
            "schema": {
              "type": "string"
            },
            "example": "303"
          },
          {
            "name": "client_id",
            "in": "query",
            "required": true,
            "description": "El cliente.",
            "schema": {
              "type": "string"
            },
            "example": "0b5b4d54-6f5e-4b2d-9b0a-5d1a9b8c3e11"
          },
          {
            "name": "quarter",
            "in": "query",
            "required": true,
            "description": "Trimestre con la forma AAAA-Q1 a AAAA-Q4.",
            "schema": {
              "type": "string"
            },
            "example": "2026-Q3"
          }
        ],
        "responses": {
          "200": {
            "description": "Correcto",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                },
                "example": {
                  "data": {
                    "model": "303",
                    "client_id": "0b5b…",
                    "quarter": "2026-Q3",
                    "issued": {
                      "base": 1000,
                      "vat": 210,
                      "invoices": 3,
                      "ticket_days": 0
                    },
                    "received": {
                      "base": 400,
                      "deductible_vat": 84,
                      "invoices": 5
                    },
                    "result": {
                      "amount": 126,
                      "to_pay": true
                    },
                    "equivalence_surcharge": {
                      "received": 0,
                      "issued": 0
                    },
                    "reverse_charge_base": 0,
                    "warnings": [],
                    "notice": "Borrador orientativo calculado con las facturas de LeeFactura: no sustituye la presentación ante la Agencia Tributaria. Revísalo con el asesor antes de presentarlo."
                  }
                }
              }
            }
          },
          "400": {
            "description": "Parámetro no válido",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "Clave ausente o no válida",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "Sin permiso o sin plan",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "No existe",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "Demasiadas peticiones",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    }
  },
  "components": {
    "securitySchemes": {
      "bearerAuth": {
        "type": "http",
        "scheme": "bearer",
        "description": "Clave de API (lf_…), creada por el titular en el panel."
      }
    },
    "schemas": {
      "Error": {
        "type": "object",
        "properties": {
          "error": {
            "type": "object",
            "properties": {
              "code": {
                "type": "string"
              },
              "message": {
                "type": "string"
              },
              "request_id": {
                "type": "string"
              }
            },
            "required": [
              "code",
              "message",
              "request_id"
            ]
          }
        },
        "required": [
          "error"
        ]
      }
    }
  }
}