{
    "openapi": "3.0.3",
    "info": {
        "title": "API de CopilotGestoria",
        "version": "2026-09-05",
        "description": "API para integrar CopilotGestoria en tu web, tu app o tu ERP.\n\nAutenticación: `Authorization: Bearer cg_live_<prefijo>.<secreto>`.\nCliente sobre el que operas: cabecera `X-CG-Client`.\nToda escritura exige `Idempotency-Key`.\n\nLas respuestas llevan siempre la cabecera `Request-Id`: guárdala, es lo que permite localizar la llamada exacta si algo falla.",
        "contact": {
            "name": "Soporte",
            "email": "info@copilotgestoria.com"
        }
    },
    "servers": [
        {
            "url": "https://copilotgestoria.com/api/public/v1",
            "description": "Producción"
        }
    ],
    "components": {
        "securitySchemes": {
            "ClaveApi": {
                "type": "http",
                "scheme": "bearer",
                "description": "Clave de API creada por el gestor desde su panel."
            }
        },
        "parameters": {
            "Cliente": {
                "name": "X-CG-Client",
                "in": "header",
                "required": true,
                "schema": {
                    "type": "integer"
                },
                "description": "Identificador del cliente final. Los que puedes usar salen en GET /clients."
            },
            "Idempotencia": {
                "name": "Idempotency-Key",
                "in": "header",
                "required": true,
                "schema": {
                    "type": "string",
                    "maxLength": 255
                },
                "description": "UUID distinto por operación. Repite el MISMO valor si reintentas."
            },
            "Cursor": {
                "name": "cursor",
                "in": "query",
                "schema": {
                    "type": "string"
                },
                "description": "Valor de next_cursor de la página anterior."
            },
            "Limite": {
                "name": "limit",
                "in": "query",
                "schema": {
                    "type": "integer",
                    "minimum": 1,
                    "maximum": 100,
                    "default": 25
                }
            }
        },
        "schemas": {
            "Error": {
                "type": "object",
                "properties": {
                    "error": {
                        "type": "object",
                        "properties": {
                            "type": {
                                "type": "string",
                                "description": "Familia del error"
                            },
                            "code": {
                                "type": "string",
                                "description": "Código estable; no cambia aunque cambie el texto"
                            },
                            "message": {
                                "type": "string"
                            },
                            "param": {
                                "type": "string",
                                "description": "Campo concreto que falla"
                            },
                            "doc_url": {
                                "type": "string"
                            },
                            "request_id": {
                                "type": "string"
                            },
                            "request_log_url": {
                                "type": "string"
                            }
                        }
                    }
                }
            },
            "Lista": {
                "type": "object",
                "properties": {
                    "object": {
                        "type": "string",
                        "example": "list"
                    },
                    "data": {
                        "type": "array",
                        "items": {
                            "type": "object"
                        }
                    },
                    "has_more": {
                        "type": "boolean"
                    },
                    "next_cursor": {
                        "type": "string",
                        "nullable": true
                    }
                }
            }
        }
    },
    "security": [
        {
            "ClaveApi": []
        }
    ],
    "x-scopes": {
        "clientes:leer": "Ver la lista de clientes autorizados y sus datos fiscales básicos",
        "clientes:derechos": "Atender los derechos del cliente: exportar todo su histórico y borrar su rastro",
        "facturas:leer": "Consultar las facturas emitidas y recibidas",
        "facturas:escribir": "Emitir facturas nuevas en nombre del cliente",
        "documentos:leer": "Consultar los documentos digitalizados y sus datos extraídos",
        "documentos:escribir": "Enviar documentos para su digitalización",
        "gastos:leer": "Consultar los gastos y recibos sin factura",
        "gastos:escribir": "Registrar gastos y recibos (quedan en borrador hasta que el gestor confirme)",
        "contabilidad:leer": "Consultar asientos contables, plan contable y periodos",
        "bancos:leer": "Consultar cuentas y movimientos bancarios",
        "nominas:leer": "Consultar las nóminas generadas",
        "modelos:leer": "Consultar los modelos fiscales y descargar sus ficheros",
        "modelos:escribir": "Generar modelos fiscales nuevos",
        "modelos:presentar": "Presentar modelos ante la AEAT (irreversible)",
        "webhooks:gestionar": "Configurar avisos automáticos hacia un servidor propio"
    },
    "x-webhooks": {
        "cabecera_firma": "CG-Signature",
        "tolerancia_segundos": 300,
        "eventos": {
            "invoice.emitted": "Se ha emitido una factura",
            "invoice.verifactu_sent": "La factura se ha enviado a la AEAT",
            "invoice.verifactu_accepted": "La AEAT ha aceptado la factura",
            "invoice.verifactu_accepted_with_errors": "La AEAT la ha registrado CON INCIDENCIAS (no es un éxito)",
            "invoice.verifactu_rejected": "La AEAT ha rechazado la factura",
            "invoice.verifactu_needs_review": "Estado desconocido tras el envío: lo revisa el gestor",
            "invoice.annulled": "Se ha anulado una factura",
            "invoice.payment_recorded": "Se ha registrado un cobro",
            "document.processed": "Se ha digitalizado un documento",
            "document.rejected": "Un documento se ha descartado (duplicado o no es factura)",
            "document.alert_detected": "Un documento tiene incidencias que revisar",
            "tax_model.generated": "Se ha generado un modelo fiscal",
            "consent.revoked": "Un cliente ha retirado su autorización"
        }
    },
    "paths": {
        "/status": {
            "get": {
                "summary": "Señal de vida y permisos de la clave",
                "description": "No consume cupo ni exige ningún permiso. Es lo primero que conviene llamar.",
                "responses": {
                    "200": {
                        "description": "Estado de la credencial"
                    }
                }
            }
        },
        "/clients": {
            "get": {
                "summary": "Clientes que esta clave puede tocar",
                "description": "Devuelve SOLO los que el gestor ha autorizado. Si no ha marcado ninguno, la lista viene vacía: no es un error.",
                "parameters": [
                    {
                        "$ref": "#/components/parameters/Cursor"
                    },
                    {
                        "$ref": "#/components/parameters/Limite"
                    }
                ],
                "responses": {
                    "200": {
                        "description": "Listado paginado por cursor",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Lista"
                                }
                            }
                        }
                    },
                    "401": {
                        "description": "Clave ausente o inválida",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Error"
                                }
                            }
                        }
                    },
                    "403": {
                        "description": "Falta el permiso, el cliente no está autorizado o no ha consentido"
                    },
                    "429": {
                        "description": "Límite de peticiones alcanzado. Mira Retry-After"
                    }
                }
            }
        },
        "/clients/{id}": {
            "get": {
                "summary": "Ficha de un cliente con sus actividades económicas",
                "parameters": [
                    {
                        "name": "id",
                        "in": "path",
                        "required": true,
                        "schema": {
                            "type": "string"
                        }
                    }
                ],
                "responses": {
                    "200": {
                        "description": "Cliente"
                    },
                    "401": {
                        "description": "Clave ausente o inválida",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Error"
                                }
                            }
                        }
                    },
                    "403": {
                        "description": "Falta el permiso, el cliente no está autorizado o no ha consentido"
                    },
                    "429": {
                        "description": "Límite de peticiones alcanzado. Mira Retry-After"
                    }
                }
            }
        },
        "/invoices": {
            "get": {
                "summary": "Facturas del cliente",
                "parameters": [
                    {
                        "$ref": "#/components/parameters/Cliente"
                    },
                    {
                        "$ref": "#/components/parameters/Cursor"
                    },
                    {
                        "$ref": "#/components/parameters/Limite"
                    }
                ],
                "responses": {
                    "200": {
                        "description": "Listado paginado por cursor",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Lista"
                                }
                            }
                        }
                    },
                    "401": {
                        "description": "Clave ausente o inválida",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Error"
                                }
                            }
                        }
                    },
                    "403": {
                        "description": "Falta el permiso, el cliente no está autorizado o no ha consentido"
                    },
                    "429": {
                        "description": "Límite de peticiones alcanzado. Mira Retry-After"
                    }
                }
            },
            "post": {
                "summary": "Emitir una factura",
                "description": "Exige `Idempotency-Key`. La respuesta dice si la factura se remitirá a la AEAT y por qué.\n\nAnular y rectificar NO están en la API: son irreversibles y se hacen desde el panel del gestor.",
                "parameters": [
                    {
                        "$ref": "#/components/parameters/Cliente"
                    },
                    {
                        "$ref": "#/components/parameters/Idempotencia"
                    }
                ],
                "responses": {
                    "201": {
                        "description": "Factura emitida"
                    },
                    "409": {
                        "description": "Clave de idempotencia reutilizada con otros datos, o emisión no posible"
                    },
                    "401": {
                        "description": "Clave ausente o inválida",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Error"
                                }
                            }
                        }
                    },
                    "403": {
                        "description": "Falta el permiso, el cliente no está autorizado o no ha consentido"
                    },
                    "429": {
                        "description": "Límite de peticiones alcanzado. Mira Retry-After"
                    }
                }
            }
        },
        "/documents": {
            "get": {
                "summary": "Documentos digitalizados",
                "parameters": [
                    {
                        "$ref": "#/components/parameters/Cliente"
                    },
                    {
                        "$ref": "#/components/parameters/Cursor"
                    },
                    {
                        "$ref": "#/components/parameters/Limite"
                    }
                ],
                "responses": {
                    "200": {
                        "description": "Listado paginado por cursor",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Lista"
                                }
                            }
                        }
                    },
                    "401": {
                        "description": "Clave ausente o inválida",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Error"
                                }
                            }
                        }
                    },
                    "403": {
                        "description": "Falta el permiso, el cliente no está autorizado o no ha consentido"
                    },
                    "429": {
                        "description": "Límite de peticiones alcanzado. Mira Retry-After"
                    }
                }
            },
            "post": {
                "summary": "Enviar un documento a digitalizar",
                "description": "Responde **202**: el OCR no cabe en una petición HTTP. El cuerpo trae un trabajo con `consultar_en`; cuando su estado sea `succeeded`, `resultado` traerá los documentos.\n\nUn mismo fichero puede contener varias facturas: el resultado las devuelve todas.",
                "parameters": [
                    {
                        "$ref": "#/components/parameters/Cliente"
                    },
                    {
                        "$ref": "#/components/parameters/Idempotencia"
                    }
                ],
                "responses": {
                    "202": {
                        "description": "Aceptado; consulta el trabajo en `consultar_en`"
                    },
                    "401": {
                        "description": "Clave ausente o inválida",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Error"
                                }
                            }
                        }
                    },
                    "403": {
                        "description": "Falta el permiso, el cliente no está autorizado o no ha consentido"
                    },
                    "429": {
                        "description": "Límite de peticiones alcanzado. Mira Retry-After"
                    }
                }
            }
        },
        "/expenses": {
            "get": {
                "summary": "Gastos y recibos sin factura",
                "parameters": [
                    {
                        "$ref": "#/components/parameters/Cliente"
                    },
                    {
                        "$ref": "#/components/parameters/Cursor"
                    },
                    {
                        "$ref": "#/components/parameters/Limite"
                    }
                ],
                "responses": {
                    "200": {
                        "description": "Listado paginado por cursor",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Lista"
                                }
                            }
                        }
                    },
                    "401": {
                        "description": "Clave ausente o inválida",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Error"
                                }
                            }
                        }
                    },
                    "403": {
                        "description": "Falta el permiso, el cliente no está autorizado o no ha consentido"
                    },
                    "429": {
                        "description": "Límite de peticiones alcanzado. Mira Retry-After"
                    }
                }
            },
            "post": {
                "summary": "Registrar un gasto",
                "description": "Nace en borrador: no entra en el Modelo 130 hasta que el gestor lo confirme.",
                "parameters": [
                    {
                        "$ref": "#/components/parameters/Cliente"
                    },
                    {
                        "$ref": "#/components/parameters/Idempotencia"
                    }
                ],
                "responses": {
                    "201": {
                        "description": "Gasto creado en borrador"
                    },
                    "401": {
                        "description": "Clave ausente o inválida",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Error"
                                }
                            }
                        }
                    },
                    "403": {
                        "description": "Falta el permiso, el cliente no está autorizado o no ha consentido"
                    },
                    "429": {
                        "description": "Límite de peticiones alcanzado. Mira Retry-After"
                    }
                }
            }
        },
        "/journal-entries": {
            "get": {
                "summary": "Asientos del libro diario",
                "parameters": [
                    {
                        "$ref": "#/components/parameters/Cliente"
                    },
                    {
                        "$ref": "#/components/parameters/Cursor"
                    },
                    {
                        "$ref": "#/components/parameters/Limite"
                    }
                ],
                "responses": {
                    "200": {
                        "description": "Listado paginado por cursor",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Lista"
                                }
                            }
                        }
                    },
                    "401": {
                        "description": "Clave ausente o inválida",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Error"
                                }
                            }
                        }
                    },
                    "403": {
                        "description": "Falta el permiso, el cliente no está autorizado o no ha consentido"
                    },
                    "429": {
                        "description": "Límite de peticiones alcanzado. Mira Retry-After"
                    }
                }
            }
        },
        "/chart-of-accounts": {
            "get": {
                "summary": "Plan contable del cliente",
                "parameters": [
                    {
                        "$ref": "#/components/parameters/Cliente"
                    },
                    {
                        "$ref": "#/components/parameters/Cursor"
                    },
                    {
                        "$ref": "#/components/parameters/Limite"
                    }
                ],
                "responses": {
                    "200": {
                        "description": "Listado paginado por cursor",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Lista"
                                }
                            }
                        }
                    },
                    "401": {
                        "description": "Clave ausente o inválida",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Error"
                                }
                            }
                        }
                    },
                    "403": {
                        "description": "Falta el permiso, el cliente no está autorizado o no ha consentido"
                    },
                    "429": {
                        "description": "Límite de peticiones alcanzado. Mira Retry-After"
                    }
                }
            }
        },
        "/bank-accounts": {
            "get": {
                "summary": "Cuentas bancarias (IBAN enmascarado)",
                "parameters": [
                    {
                        "$ref": "#/components/parameters/Cliente"
                    },
                    {
                        "$ref": "#/components/parameters/Cursor"
                    },
                    {
                        "$ref": "#/components/parameters/Limite"
                    }
                ],
                "responses": {
                    "200": {
                        "description": "Listado paginado por cursor",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Lista"
                                }
                            }
                        }
                    },
                    "401": {
                        "description": "Clave ausente o inválida",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Error"
                                }
                            }
                        }
                    },
                    "403": {
                        "description": "Falta el permiso, el cliente no está autorizado o no ha consentido"
                    },
                    "429": {
                        "description": "Límite de peticiones alcanzado. Mira Retry-After"
                    }
                }
            }
        },
        "/bank-transactions": {
            "get": {
                "summary": "Movimientos bancarios",
                "parameters": [
                    {
                        "$ref": "#/components/parameters/Cliente"
                    },
                    {
                        "$ref": "#/components/parameters/Cursor"
                    },
                    {
                        "$ref": "#/components/parameters/Limite"
                    }
                ],
                "responses": {
                    "200": {
                        "description": "Listado paginado por cursor",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Lista"
                                }
                            }
                        }
                    },
                    "401": {
                        "description": "Clave ausente o inválida",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Error"
                                }
                            }
                        }
                    },
                    "403": {
                        "description": "Falta el permiso, el cliente no está autorizado o no ha consentido"
                    },
                    "429": {
                        "description": "Límite de peticiones alcanzado. Mira Retry-After"
                    }
                }
            }
        },
        "/payrolls": {
            "get": {
                "summary": "Nóminas generadas",
                "parameters": [
                    {
                        "$ref": "#/components/parameters/Cliente"
                    },
                    {
                        "$ref": "#/components/parameters/Cursor"
                    },
                    {
                        "$ref": "#/components/parameters/Limite"
                    }
                ],
                "responses": {
                    "200": {
                        "description": "Listado paginado por cursor",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Lista"
                                }
                            }
                        }
                    },
                    "401": {
                        "description": "Clave ausente o inválida",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Error"
                                }
                            }
                        }
                    },
                    "403": {
                        "description": "Falta el permiso, el cliente no está autorizado o no ha consentido"
                    },
                    "429": {
                        "description": "Límite de peticiones alcanzado. Mira Retry-After"
                    }
                }
            }
        },
        "/tax-models": {
            "get": {
                "summary": "Modelos fiscales del cliente",
                "parameters": [
                    {
                        "$ref": "#/components/parameters/Cliente"
                    },
                    {
                        "$ref": "#/components/parameters/Cursor"
                    },
                    {
                        "$ref": "#/components/parameters/Limite"
                    }
                ],
                "responses": {
                    "200": {
                        "description": "Listado paginado por cursor",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Lista"
                                }
                            }
                        }
                    },
                    "401": {
                        "description": "Clave ausente o inválida",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Error"
                                }
                            }
                        }
                    },
                    "403": {
                        "description": "Falta el permiso, el cliente no está autorizado o no ha consentido"
                    },
                    "429": {
                        "description": "Límite de peticiones alcanzado. Mira Retry-After"
                    }
                }
            },
            "post": {
                "summary": "Generar un modelo fiscal",
                "description": "**Trimestrales (respuesta directa, 201):** 303, 111, 130, 131, 115, 123. Exigen `trimestre`.\n\n**Anuales (respuesta 202 + trabajo):** 100, 180, 190, 193, 200, 202, 347, 349, 390. Tardan más de lo que aguanta una petición HTTP.\nEl 202 y el 349 exigen `periodo` (y el 349, además, `periodo_tipo` M o T). El 100 exige `comunidad_autonoma`.\n\n`activity_id` solo se admite en el 130 y el 131: los demás se declaran por NIF y no se pueden fraccionar por actividad.\n\nPresentar ante la AEAT NO está en la API: exige la contraseña del certificado del cliente, que no guardamos.",
                "parameters": [
                    {
                        "$ref": "#/components/parameters/Cliente"
                    },
                    {
                        "$ref": "#/components/parameters/Idempotencia"
                    }
                ],
                "responses": {
                    "201": {
                        "description": "Modelo generado (trimestrales)"
                    },
                    "202": {
                        "description": "Aceptado; consulta el trabajo en `consultar_en` (anuales)"
                    },
                    "409": {
                        "description": "Ya existe ese modelo para ese periodo"
                    },
                    "401": {
                        "description": "Clave ausente o inválida",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Error"
                                }
                            }
                        }
                    },
                    "403": {
                        "description": "Falta el permiso, el cliente no está autorizado o no ha consentido"
                    },
                    "429": {
                        "description": "Límite de peticiones alcanzado. Mira Retry-After"
                    }
                }
            }
        },
        "/tax-models/{id}/file": {
            "get": {
                "summary": "Enlace temporal al fichero oficial para la Sede",
                "parameters": [
                    {
                        "$ref": "#/components/parameters/Cliente"
                    },
                    {
                        "name": "id",
                        "in": "path",
                        "required": true,
                        "schema": {
                            "type": "string"
                        }
                    }
                ],
                "responses": {
                    "200": {
                        "description": "Enlace firmado, válido 15 minutos"
                    },
                    "401": {
                        "description": "Clave ausente o inválida",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Error"
                                }
                            }
                        }
                    },
                    "403": {
                        "description": "Falta el permiso, el cliente no está autorizado o no ha consentido"
                    },
                    "429": {
                        "description": "Límite de peticiones alcanzado. Mira Retry-After"
                    }
                }
            }
        },
        "/tax-models/{id}/receipt": {
            "get": {
                "summary": "Justificante de una presentación ya hecha ante la AEAT",
                "description": "Devuelve el CSV, el número de justificante y un enlace temporal al PDF.\n\nVa bajo el permiso propio `modelos:presentar`, NO bajo `modelos:leer`: un justificante acredita ante terceros que un cliente presentó.\n\nPresentar en sí no está en la API — exige la contraseña del certificado del cliente, que no guardamos.",
                "parameters": [
                    {
                        "$ref": "#/components/parameters/Cliente"
                    },
                    {
                        "name": "id",
                        "in": "path",
                        "required": true,
                        "schema": {
                            "type": "string"
                        }
                    }
                ],
                "responses": {
                    "200": {
                        "description": "Justificante"
                    },
                    "409": {
                        "description": "El modelo no consta presentado"
                    },
                    "401": {
                        "description": "Clave ausente o inválida",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Error"
                                }
                            }
                        }
                    },
                    "403": {
                        "description": "Falta el permiso, el cliente no está autorizado o no ha consentido"
                    },
                    "429": {
                        "description": "Límite de peticiones alcanzado. Mira Retry-After"
                    }
                }
            }
        },
        "/tax-models/export": {
            "get": {
                "summary": "Todos los modelos de un ejercicio, de una vez",
                "description": "Pensado para migrar un cliente o cerrar el año sin recorrer el cursor N veces. Tope de 500 modelos.",
                "parameters": [
                    {
                        "$ref": "#/components/parameters/Cliente"
                    },
                    {
                        "name": "ejercicio",
                        "in": "query",
                        "required": true,
                        "schema": {
                            "type": "integer",
                            "example": 2026
                        }
                    }
                ],
                "responses": {
                    "200": {
                        "description": "Modelos del ejercicio"
                    },
                    "401": {
                        "description": "Clave ausente o inválida",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Error"
                                }
                            }
                        }
                    },
                    "403": {
                        "description": "Falta el permiso, el cliente no está autorizado o no ha consentido"
                    },
                    "429": {
                        "description": "Límite de peticiones alcanzado. Mira Retry-After"
                    }
                }
            }
        },
        "/clients/{id}/activity": {
            "get": {
                "summary": "Qué ha hecho esta integración con los datos de un cliente",
                "description": "El derecho de acceso del art. 15 del RGPD: las 500 últimas llamadas sobre ese cliente, con su permiso usado y su resultado, más la fecha en que se otorgó el consentimiento.\n\nExige consentimiento vigente, igual que la ficha.",
                "parameters": [
                    {
                        "name": "id",
                        "in": "path",
                        "required": true,
                        "schema": {
                            "type": "string"
                        }
                    }
                ],
                "responses": {
                    "200": {
                        "description": "Actividad y consentimiento"
                    },
                    "401": {
                        "description": "Clave ausente o inválida",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Error"
                                }
                            }
                        }
                    },
                    "403": {
                        "description": "Falta el permiso, el cliente no está autorizado o no ha consentido"
                    },
                    "429": {
                        "description": "Límite de peticiones alcanzado. Mira Retry-After"
                    }
                }
            }
        },
        "/clients/{id}/export": {
            "get": {
                "summary": "Portabilidad: todos los datos del cliente en un fichero (RGPD art. 20)",
                "description": "Ficha, documentos, asientos y modelos fiscales, con la misma forma siempre. Tope de 5.000 documentos y asientos.",
                "parameters": [
                    {
                        "name": "id",
                        "in": "path",
                        "required": true,
                        "schema": {
                            "type": "string"
                        }
                    }
                ],
                "responses": {
                    "200": {
                        "description": "Exportación completa"
                    },
                    "401": {
                        "description": "Clave ausente o inválida",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Error"
                                }
                            }
                        }
                    },
                    "403": {
                        "description": "Falta el permiso, el cliente no está autorizado o no ha consentido"
                    },
                    "429": {
                        "description": "Límite de peticiones alcanzado. Mira Retry-After"
                    }
                }
            }
        },
        "/clients/{id}/data": {
            "delete": {
                "summary": "Supresión: retirar a este cliente de tu integración (RGPD art. 17)",
                "description": "Revoca el consentimiento, te desautoriza sobre ese cliente y borra tu rastro de llamadas.\n\n**No borra sus facturas, asientos ni modelos**: son documentación contable con plazos de conservación propios, y esa decisión es del gestor.",
                "parameters": [
                    {
                        "name": "id",
                        "in": "path",
                        "required": true,
                        "schema": {
                            "type": "string"
                        }
                    }
                ],
                "responses": {
                    "200": {
                        "description": "Cliente retirado de esta integración"
                    },
                    "401": {
                        "description": "Clave ausente o inválida",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Error"
                                }
                            }
                        }
                    },
                    "403": {
                        "description": "Falta el permiso, el cliente no está autorizado o no ha consentido"
                    },
                    "429": {
                        "description": "Límite de peticiones alcanzado. Mira Retry-After"
                    }
                }
            }
        },
        "/jobs": {
            "get": {
                "summary": "Trabajos en diferido de esta clave",
                "description": "Filtra por `estado` (`pending`, `running`, `succeeded`, `failed`). Si mandas `X-CG-Client`, se acota a ese cliente.",
                "parameters": [
                    {
                        "$ref": "#/components/parameters/Cursor"
                    },
                    {
                        "$ref": "#/components/parameters/Limite"
                    }
                ],
                "responses": {
                    "200": {
                        "description": "Listado paginado por cursor",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Lista"
                                }
                            }
                        }
                    },
                    "401": {
                        "description": "Clave ausente o inválida",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Error"
                                }
                            }
                        }
                    },
                    "403": {
                        "description": "Falta el permiso, el cliente no está autorizado o no ha consentido"
                    },
                    "429": {
                        "description": "Límite de peticiones alcanzado. Mira Retry-After"
                    }
                }
            }
        },
        "/jobs/{id}": {
            "get": {
                "summary": "Estado de un trabajo",
                "description": "Responde 200 en los cuatro estados: que el trabajo fallara no es un fallo de tu consulta — el motivo va dentro, en `error`.\n\nCuando `estado` es `succeeded`, `resultado` trae el MISMO recurso que devolvería la vía directa.",
                "parameters": [
                    {
                        "name": "id",
                        "in": "path",
                        "required": true,
                        "schema": {
                            "type": "string"
                        }
                    }
                ],
                "responses": {
                    "200": {
                        "description": "El trabajo, en cualquiera de sus cuatro estados"
                    },
                    "401": {
                        "description": "Clave ausente o inválida",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Error"
                                }
                            }
                        }
                    },
                    "403": {
                        "description": "Falta el permiso, el cliente no está autorizado o no ha consentido"
                    },
                    "429": {
                        "description": "Límite de peticiones alcanzado. Mira Retry-After"
                    }
                }
            }
        },
        "/webhooks": {
            "get": {
                "summary": "Destinos de webhook configurados",
                "responses": {
                    "200": {
                        "description": "Listado paginado por cursor",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Lista"
                                }
                            }
                        }
                    },
                    "401": {
                        "description": "Clave ausente o inválida",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Error"
                                }
                            }
                        }
                    },
                    "403": {
                        "description": "Falta el permiso, el cliente no está autorizado o no ha consentido"
                    },
                    "429": {
                        "description": "Límite de peticiones alcanzado. Mira Retry-After"
                    }
                }
            },
            "post": {
                "summary": "Dar de alta un destino",
                "description": "Nace apagado. Hay que verificarlo antes de que reciba nada.",
                "responses": {
                    "201": {
                        "description": "Destino creado; el secreto se muestra una sola vez"
                    },
                    "401": {
                        "description": "Clave ausente o inválida",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Error"
                                }
                            }
                        }
                    },
                    "403": {
                        "description": "Falta el permiso, el cliente no está autorizado o no ha consentido"
                    },
                    "429": {
                        "description": "Límite de peticiones alcanzado. Mira Retry-After"
                    }
                }
            }
        },
        "/webhooks/{id}/verificar": {
            "post": {
                "summary": "Comprobar que tu servidor valida la firma",
                "description": "Enviamos una carga con firma válida (debe responder 2xx) y otra con firma inválida (debe responder 401). Si aceptas la mala, el destino no se activa.",
                "parameters": [
                    {
                        "name": "id",
                        "in": "path",
                        "required": true,
                        "schema": {
                            "type": "string"
                        }
                    }
                ],
                "responses": {
                    "200": {
                        "description": "Verificado y activado"
                    },
                    "409": {
                        "description": "Tu servidor no valida la firma correctamente"
                    }
                }
            }
        },
        "/webhooks/eventos": {
            "get": {
                "summary": "Catálogo de eventos y cómo verificar la firma",
                "responses": {
                    "200": {
                        "description": "Catálogo"
                    }
                }
            }
        }
    }
}