{
    "openapi": "3.1.0",
    "info": {
        "title": "API de socios v1 · Sistema Facturación Perú",
        "version": "1.0.0",
        "summary": "Da de alta empresas, crea sus claves de la API v1, consulta tu saldo y recibe avisos.",
        "description": "Para programadores y empresas de software con muchos clientes propios. Tú das de alta a tus clientes como empresas\nde Sistema Facturación Perú, las pagas con bolsas prepago de comprobantes y emites con cada una usando su **API v1**\n(https://sistemafacturacionperu.com/desarrolladores/referencia/).\n\n- Base: `https://api.sistemafacturacionperu.com/socios/v1` (nunca en el subdominio de una empresa).\n- Autenticación: OAuth 2 «client_credentials». Pide un token con `POST /token` (tu `client_id` y `client_secret`) y\n  úsalo en `Authorization: Bearer sfp_pat_…`. Dura 1 hora. Nunca en la URL.\n- Éxito: `{ \"success\": true, \"data\": …, \"meta\"?: … }`. Error: `{ \"success\": false, \"code\": \"…\", \"message\": \"…\", \"errors\"?: {…} }`\n  (el mismo formato de la API v1).\n- Todo `POST` y `PATCH` acepta `Idempotency-Key`: el reintento con el mismo cuerpo devuelve la misma respuesta con\n  `Idempotent-Replayed: true`; la misma clave con otro cuerpo responde 409 `idempotencia_distinta`.\n- Límites: 120 llamadas por minuto por token (`X-RateLimit-Limit`, `X-RateLimit-Remaining`; al pasarte, 429 con\n  `Retry-After`) y 10 intentos de token por minuto por IP y por `client_id`.\n- Una empresa que no es tuya responde 404 (nunca se revela que existe).\n\nBolsas (con IGV, 6 meses de validez, se consume primero la que vence antes): 3.300 = S/ 180; 5.500 = S/ 285;\n10.000 = S/ 480. Descuenta 1 cada comprobante, resumen diario, baja y guía que sale por **nuestro PSE**; lo que la\nempresa envía con su propio usuario SOL no descuenta. Cuota: S/ 9 al mes con IGV por cada empresa que emitió.\n\nGuía completa: https://sistemafacturacionperu.com/desarrolladores/socios/\n",
        "contact": {
            "name": "Sistema Facturación Perú",
            "url": "https://sistemafacturacionperu.com/desarrolladores"
        }
    },
    "servers": [
        {
            "url": "https://api.sistemafacturacionperu.com/socios/v1",
            "description": "Producción"
        }
    ],
    "security": [
        {
            "bearer": []
        }
    ],
    "tags": [
        {
            "name": "Autenticación"
        },
        {
            "name": "Empresas",
            "description": "Tus clientes como empresas de Sistema Facturación Perú."
        },
        {
            "name": "Claves",
            "description": "Claves de la API v1 (sfp_live_) de cada empresa, para emitir."
        },
        {
            "name": "Saldo",
            "description": "Bolsas, consumos, recargas y cuotas."
        },
        {
            "name": "Webhooks"
        }
    ],
    "paths": {
        "/token": {
            "post": {
                "tags": [
                    "Autenticación"
                ],
                "summary": "Pedir un token de acceso (client_credentials)",
                "description": "Manda tu `client_id` y `client_secret` en `Authorization: Basic base64(client_id:client_secret)` o en el cuerpo\n(JSON o formulario). El token dura 1 hora: pide otro cuando venza (401 `token_vencido`).\n",
                "operationId": "token",
                "security": [],
                "requestBody": {
                    "content": {
                        "application/json": {
                            "schema": {
                                "$ref": "#/components/schemas/PedidoToken"
                            },
                            "example": {
                                "grant_type": "client_credentials",
                                "client_id": "sfp_partner_k2j4h6g8f0d2s4a6q8w0e2r4",
                                "client_secret": "sfp_secret_…"
                            }
                        },
                        "application/x-www-form-urlencoded": {
                            "schema": {
                                "$ref": "#/components/schemas/PedidoToken"
                            }
                        }
                    }
                },
                "responses": {
                    "200": {
                        "description": "El token",
                        "headers": {
                            "Cache-Control": {
                                "schema": {
                                    "type": "string",
                                    "example": "no-store"
                                }
                            }
                        },
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/RespuestaToken"
                                },
                                "example": {
                                    "success": true,
                                    "access_token": "sfp_pat_Q1w2E3r4T5y6U7i8O9p0A1s2D3f4G5h6J7k8L9z0X1c2V3b4",
                                    "token_type": "Bearer",
                                    "expires_in": 3600,
                                    "expires_at": "2026-11-03T15:04:05-05:00",
                                    "data": {
                                        "access_token": "sfp_pat_…",
                                        "token_type": "Bearer",
                                        "expires_in": 3600,
                                        "expires_at": "2026-11-03T15:04:05-05:00"
                                    }
                                }
                            }
                        }
                    },
                    "400": {
                        "description": "`grant_no_soportado` (solo client_credentials) o `secreto_en_url`",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Error"
                                }
                            }
                        }
                    },
                    "401": {
                        "description": "`credenciales_invalidas` (el mismo mensaje si el client_id no existe, el secreto es malo o la credencial se revocó)",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Error"
                                },
                                "example": {
                                    "success": false,
                                    "code": "credenciales_invalidas",
                                    "message": "El client_id o el client_secret no son válidos (o la credencial fue revocada)."
                                }
                            }
                        }
                    },
                    "403": {
                        "description": "`ip_no_permitida` (la credencial tiene IP permitidas) o `socio_suspendido`",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Error"
                                }
                            }
                        }
                    },
                    "429": {
                        "description": "`demasiados_intentos` (10 por minuto por IP y por client_id), con Retry-After",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Error"
                                }
                            }
                        }
                    }
                }
            }
        },
        "/empresas": {
            "get": {
                "tags": [
                    "Empresas"
                ],
                "summary": "Listar tus empresas",
                "description": "El estado es el último conocido; `GET /empresas/{id}` lo vuelve a leer.",
                "operationId": "listarEmpresas",
                "parameters": [
                    {
                        "name": "estado",
                        "in": "query",
                        "schema": {
                            "$ref": "#/components/schemas/EstadoEmpresa"
                        }
                    },
                    {
                        "name": "ruc",
                        "in": "query",
                        "schema": {
                            "type": "string",
                            "pattern": "^\\d{11}$"
                        }
                    },
                    {
                        "$ref": "#/components/parameters/Page"
                    },
                    {
                        "$ref": "#/components/parameters/PerPage"
                    }
                ],
                "responses": {
                    "200": {
                        "description": "Página de empresas",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "type": "object",
                                    "properties": {
                                        "success": {
                                            "const": true
                                        },
                                        "data": {
                                            "type": "array",
                                            "items": {
                                                "$ref": "#/components/schemas/Empresa"
                                            }
                                        },
                                        "meta": {
                                            "$ref": "#/components/schemas/Meta"
                                        }
                                    }
                                }
                            }
                        }
                    },
                    "401": {
                        "$ref": "#/components/responses/NoAutenticado"
                    },
                    "422": {
                        "$ref": "#/components/responses/Validacion"
                    },
                    "429": {
                        "$ref": "#/components/responses/DemasiadasSolicitudes"
                    }
                }
            },
            "post": {
                "tags": [
                    "Empresas"
                ],
                "summary": "Dar de alta una empresa",
                "description": "Responde 201 al instante con `estado: creando`; la empresa queda creada en 1 a 3 minutos (consulta\n`GET /empresas/{id}` o espera el webhook `empresa.lista`). Entra con el plan «Socio»: emitir y consultar + API.\n\n- Sin `administrador.contrasena`, el administrador recibe el correo de bienvenida con el enlace para crearla.\n- Con `certificado` y `sol` la empresa pasa a producción y envía directo a SUNAT con su SOL (no descuenta de tu\n  bolsa). Con `envio: pse` (o sin SOL) envía por nuestro PSE, que activamos nosotros, y descuenta de tu bolsa.\n- Como toda empresa nueva, emite cuando su Ficha RUC queda verificada (`pendientes: ficha_ruc`): el\n  administrador la sube en Configuración › Empresa › Régimen tributario.\n",
                "operationId": "crearEmpresa",
                "parameters": [
                    {
                        "$ref": "#/components/parameters/IdempotencyKey"
                    }
                ],
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "$ref": "#/components/schemas/AltaEmpresa"
                            },
                            "example": {
                                "ruc": "20601030013",
                                "razon_social": "FERRETERIA EL TORNILLO S.A.C.",
                                "nombre_comercial": "El Tornillo",
                                "subdominio": "eltornillo",
                                "regimen_tributario": "rmt",
                                "direccion": {
                                    "direccion": "Av. Grau 123, Lima",
                                    "ubigeo": "150101"
                                },
                                "administrador": {
                                    "nombre": "Ana Quispe",
                                    "correo": "ana@tornillo.pe",
                                    "celular": "987654321"
                                },
                                "certificado": {
                                    "pfx_base64": "MIIK…",
                                    "clave": "clave-del-pfx"
                                },
                                "sol": {
                                    "usuario": "FACTURAS1",
                                    "clave": "clave-sol"
                                }
                            }
                        }
                    }
                },
                "responses": {
                    "201": {
                        "description": "El alta en marcha (o ya lista)",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "type": "object",
                                    "properties": {
                                        "success": {
                                            "const": true
                                        },
                                        "data": {
                                            "$ref": "#/components/schemas/Empresa"
                                        }
                                    }
                                },
                                "example": {
                                    "success": true,
                                    "data": {
                                        "id": 15,
                                        "ruc": "20601030013",
                                        "razon_social": "FERRETERIA EL TORNILLO S.A.C.",
                                        "subdominio": "eltornillo",
                                        "estado": "creando",
                                        "pendientes": [],
                                        "envio": null,
                                        "suspension": null,
                                        "web": "https://eltornillo.sistemafacturacionperu.com",
                                        "api_v1": "https://eltornillo.sistemafacturacionperu.com/api/v1",
                                        "lista_desde": null,
                                        "creada": "2026-11-03T10:15:00-05:00"
                                    }
                                }
                            }
                        }
                    },
                    "400": {
                        "$ref": "#/components/responses/PeticionInvalida"
                    },
                    "401": {
                        "$ref": "#/components/responses/NoAutenticado"
                    },
                    "409": {
                        "description": "`ruc_ya_registrado` (el RUC ya tiene cuenta en el sistema: no se dice de quién), `idempotencia_distinta` o `idempotencia_en_proceso`",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Error"
                                },
                                "example": {
                                    "success": false,
                                    "code": "ruc_ya_registrado",
                                    "message": "Ese RUC ya tiene una cuenta en el sistema. Si es tu cliente, pídele que nos escriba para pasarla a tu cuenta de socio."
                                }
                            }
                        }
                    },
                    "422": {
                        "description": "`validacion` (RUC con dígito verificador malo, subdominio tomado, ubigeo…) o `certificado_invalido` (el .pfx no abre con su clave)",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Error"
                                },
                                "example": {
                                    "success": false,
                                    "code": "validacion",
                                    "message": "Revisa los datos enviados.",
                                    "errors": {
                                        "ruc": [
                                            "El RUC no es válido: revisa los 11 dígitos (el último es el dígito verificador)."
                                        ]
                                    }
                                }
                            }
                        }
                    },
                    "429": {
                        "$ref": "#/components/responses/DemasiadasSolicitudes"
                    }
                }
            }
        },
        "/empresas/{id}": {
            "parameters": [
                {
                    "$ref": "#/components/parameters/IdEmpresa"
                }
            ],
            "get": {
                "tags": [
                    "Empresas"
                ],
                "summary": "Ver una empresa (vuelve a leer su estado)",
                "operationId": "verEmpresa",
                "responses": {
                    "200": {
                        "$ref": "#/components/responses/UnaEmpresa"
                    },
                    "401": {
                        "$ref": "#/components/responses/NoAutenticado"
                    },
                    "404": {
                        "$ref": "#/components/responses/NoEncontrado"
                    }
                }
            },
            "patch": {
                "tags": [
                    "Empresas"
                ],
                "summary": "Cambiar contacto, nombre comercial, dirección, certificado, usuario SOL o forma de envío",
                "description": "El RUC, la razón social y el correo del administrador no se cambian por aquí (422).",
                "operationId": "cambiarEmpresa",
                "parameters": [
                    {
                        "$ref": "#/components/parameters/IdempotencyKey"
                    }
                ],
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "$ref": "#/components/schemas/CambioEmpresa"
                            },
                            "example": {
                                "contacto": {
                                    "nombre": "Rosa",
                                    "correo": "rosa@cliente.pe"
                                },
                                "certificado": {
                                    "pfx_base64": "MIIK…",
                                    "clave": "clave"
                                },
                                "sol": {
                                    "usuario": "FACTURAS1",
                                    "clave": "clave-sol"
                                }
                            }
                        }
                    }
                },
                "responses": {
                    "200": {
                        "$ref": "#/components/responses/UnaEmpresa"
                    },
                    "401": {
                        "$ref": "#/components/responses/NoAutenticado"
                    },
                    "404": {
                        "$ref": "#/components/responses/NoEncontrado"
                    },
                    "409": {
                        "$ref": "#/components/responses/EmpresaNoLista"
                    },
                    "422": {
                        "$ref": "#/components/responses/Validacion"
                    }
                }
            }
        },
        "/empresas/{id}/uso": {
            "get": {
                "tags": [
                    "Empresas"
                ],
                "summary": "Comprobantes del mes por tipo y lo que descontó de tu bolsa",
                "operationId": "usoEmpresa",
                "parameters": [
                    {
                        "$ref": "#/components/parameters/IdEmpresa"
                    },
                    {
                        "name": "mes",
                        "in": "query",
                        "description": "AAAA-MM (por defecto, el actual)",
                        "schema": {
                            "type": "string",
                            "pattern": "^\\d{4}-(0[1-9]|1[0-2])$"
                        }
                    }
                ],
                "responses": {
                    "200": {
                        "description": "El uso del mes",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "type": "object",
                                    "properties": {
                                        "success": {
                                            "const": true
                                        },
                                        "data": {
                                            "$ref": "#/components/schemas/Uso"
                                        }
                                    }
                                },
                                "example": {
                                    "success": true,
                                    "data": {
                                        "mes": "2026-11",
                                        "emitidos": {
                                            "facturas": 120,
                                            "boletas": 840,
                                            "notas_credito": 6,
                                            "notas_debito": 0,
                                            "guias": 30,
                                            "retenciones": 0,
                                            "percepciones": 0,
                                            "liquidaciones_compra": 0,
                                            "resumenes": 22,
                                            "bajas": 2
                                        },
                                        "descontado_de_la_bolsa": {
                                            "total": 1014,
                                            "por_concepto": {
                                                "comprobante": 960,
                                                "resumen": 22,
                                                "baja": 2,
                                                "guia": 30
                                            }
                                        },
                                        "activa": true
                                    }
                                }
                            }
                        }
                    },
                    "401": {
                        "$ref": "#/components/responses/NoAutenticado"
                    },
                    "404": {
                        "$ref": "#/components/responses/NoEncontrado"
                    },
                    "409": {
                        "$ref": "#/components/responses/EmpresaNoLista"
                    },
                    "422": {
                        "$ref": "#/components/responses/Validacion"
                    }
                }
            }
        },
        "/empresas/{id}/suspender": {
            "post": {
                "tags": [
                    "Empresas"
                ],
                "summary": "Pausar la emisión por API de una empresa",
                "description": "Decisión tuya (por ejemplo, tu cliente no te pagó). Su API v1 responde 423 `suspendida_por_socio` al emitir;\nconsultar sigue funcionando y su web no cambia. Avisa con `empresa.suspendida`.\n",
                "operationId": "suspenderEmpresa",
                "parameters": [
                    {
                        "$ref": "#/components/parameters/IdEmpresa"
                    },
                    {
                        "$ref": "#/components/parameters/IdempotencyKey"
                    }
                ],
                "requestBody": {
                    "content": {
                        "application/json": {
                            "schema": {
                                "type": "object",
                                "properties": {
                                    "motivo": {
                                        "type": "string",
                                        "maxLength": 255
                                    }
                                }
                            },
                            "example": {
                                "motivo": "Cliente con pagos pendientes"
                            }
                        }
                    }
                },
                "responses": {
                    "200": {
                        "$ref": "#/components/responses/UnaEmpresa"
                    },
                    "401": {
                        "$ref": "#/components/responses/NoAutenticado"
                    },
                    "404": {
                        "$ref": "#/components/responses/NoEncontrado"
                    },
                    "409": {
                        "$ref": "#/components/responses/EmpresaNoLista"
                    }
                }
            }
        },
        "/empresas/{id}/reactivar": {
            "post": {
                "tags": [
                    "Empresas"
                ],
                "summary": "Volver a permitir la emisión por API",
                "operationId": "reactivarEmpresa",
                "parameters": [
                    {
                        "$ref": "#/components/parameters/IdEmpresa"
                    },
                    {
                        "$ref": "#/components/parameters/IdempotencyKey"
                    }
                ],
                "responses": {
                    "200": {
                        "$ref": "#/components/responses/UnaEmpresa"
                    },
                    "401": {
                        "$ref": "#/components/responses/NoAutenticado"
                    },
                    "404": {
                        "$ref": "#/components/responses/NoEncontrado"
                    },
                    "409": {
                        "$ref": "#/components/responses/EmpresaNoLista"
                    }
                }
            }
        },
        "/empresas/{id}/claves": {
            "parameters": [
                {
                    "$ref": "#/components/parameters/IdEmpresa"
                }
            ],
            "get": {
                "tags": [
                    "Claves"
                ],
                "summary": "Listar las claves v1 de la empresa (sin la clave)",
                "operationId": "listarClaves",
                "responses": {
                    "200": {
                        "description": "Las claves",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "type": "object",
                                    "properties": {
                                        "success": {
                                            "const": true
                                        },
                                        "data": {
                                            "type": "array",
                                            "items": {
                                                "$ref": "#/components/schemas/Clave"
                                            }
                                        }
                                    }
                                }
                            }
                        }
                    },
                    "401": {
                        "$ref": "#/components/responses/NoAutenticado"
                    },
                    "404": {
                        "$ref": "#/components/responses/NoEncontrado"
                    },
                    "409": {
                        "$ref": "#/components/responses/EmpresaNoLista"
                    }
                }
            },
            "post": {
                "tags": [
                    "Claves"
                ],
                "summary": "Crear una clave v1 (sfp_live_) para emitir con esa empresa",
                "description": "La clave se muestra UNA sola vez. Sin `permisos`, trae los de emitir y consultar.",
                "operationId": "crearClave",
                "parameters": [
                    {
                        "$ref": "#/components/parameters/IdempotencyKey"
                    }
                ],
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "type": "object",
                                "required": [
                                    "nombre"
                                ],
                                "properties": {
                                    "nombre": {
                                        "type": "string",
                                        "maxLength": 100
                                    },
                                    "permisos": {
                                        "type": "array",
                                        "items": {
                                            "type": "string",
                                            "enum": [
                                                "comprobantes.emitir",
                                                "comprobantes.leer",
                                                "comprobantes.anular",
                                                "guias.emitir",
                                                "guias.leer",
                                                "cobros.registrar",
                                                "catalogo.leer",
                                                "catalogo.escribir",
                                                "stock.leer",
                                                "consultas",
                                                "webhooks.gestionar"
                                            ]
                                        }
                                    },
                                    "establecimiento": {
                                        "type": "string",
                                        "description": "Código del local (0000). Sin él, el del administrador."
                                    },
                                    "vence": {
                                        "type": "string",
                                        "format": "date"
                                    }
                                }
                            },
                            "example": {
                                "nombre": "Mi sistema · producción",
                                "establecimiento": "0000"
                            }
                        }
                    }
                },
                "responses": {
                    "201": {
                        "description": "La clave (se muestra una vez)",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "type": "object",
                                    "properties": {
                                        "success": {
                                            "const": true
                                        },
                                        "data": {
                                            "allOf": [
                                                {
                                                    "$ref": "#/components/schemas/Clave"
                                                },
                                                {
                                                    "type": "object",
                                                    "properties": {
                                                        "clave": {
                                                            "type": "string",
                                                            "example": "sfp_live_Ab12Cd34Ef56Gh78Ij90Kl12Mn34Op56Qr78St90"
                                                        },
                                                        "api_v1": {
                                                            "type": "string",
                                                            "format": "uri"
                                                        },
                                                        "aviso": {
                                                            "type": "string"
                                                        }
                                                    }
                                                }
                                            ]
                                        }
                                    }
                                }
                            }
                        }
                    },
                    "401": {
                        "$ref": "#/components/responses/NoAutenticado"
                    },
                    "404": {
                        "$ref": "#/components/responses/NoEncontrado"
                    },
                    "409": {
                        "$ref": "#/components/responses/EmpresaNoLista"
                    },
                    "422": {
                        "$ref": "#/components/responses/Validacion"
                    }
                }
            }
        },
        "/empresas/{id}/claves/{keyId}": {
            "delete": {
                "tags": [
                    "Claves"
                ],
                "summary": "Revocar una clave",
                "operationId": "revocarClave",
                "parameters": [
                    {
                        "$ref": "#/components/parameters/IdEmpresa"
                    },
                    {
                        "name": "keyId",
                        "in": "path",
                        "required": true,
                        "schema": {
                            "type": "integer"
                        }
                    }
                ],
                "responses": {
                    "200": {
                        "description": "Revocada",
                        "content": {
                            "application/json": {
                                "example": {
                                    "success": true,
                                    "data": {
                                        "id": 3,
                                        "estado": "revocada"
                                    }
                                }
                            }
                        }
                    },
                    "401": {
                        "$ref": "#/components/responses/NoAutenticado"
                    },
                    "404": {
                        "$ref": "#/components/responses/NoEncontrado"
                    }
                }
            }
        },
        "/saldo": {
            "get": {
                "tags": [
                    "Saldo"
                ],
                "summary": "Tu saldo, tus bolsas, vencimientos y cuotas pendientes",
                "operationId": "saldo",
                "responses": {
                    "200": {
                        "description": "El saldo",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "type": "object",
                                    "properties": {
                                        "success": {
                                            "const": true
                                        },
                                        "data": {
                                            "$ref": "#/components/schemas/Saldo"
                                        }
                                    }
                                },
                                "example": {
                                    "success": true,
                                    "data": {
                                        "saldo": 4120,
                                        "en_bolsas_vigentes": 4120,
                                        "por_cobrar_en_la_siguiente_recarga": 0,
                                        "porcentaje_usado": 52,
                                        "proximo_vencimiento": {
                                            "fecha": "2027-03-01",
                                            "unidades": 820
                                        },
                                        "bolsas": [
                                            {
                                                "id": 4,
                                                "comprobantes": 5500,
                                                "usados": 2200,
                                                "quedan": 3300,
                                                "precio": 285,
                                                "comprada": "2026-11-01",
                                                "vence": "2027-05-01",
                                                "estado": "vigente"
                                            }
                                        ],
                                        "cuotas_pendientes": [
                                            {
                                                "id": 2,
                                                "mes": "2026-10",
                                                "empresas_activas": 14,
                                                "monto_por_empresa": 9,
                                                "monto": 126,
                                                "moneda": "PEN",
                                                "incluye_igv": true,
                                                "estado": "pendiente",
                                                "vence": "2026-11-11",
                                                "vencida": false,
                                                "pagado": null
                                            }
                                        ],
                                        "precios": [
                                            {
                                                "comprobantes": 3300,
                                                "precio": 180,
                                                "moneda": "PEN",
                                                "incluye_igv": true
                                            },
                                            {
                                                "comprobantes": 5500,
                                                "precio": 285,
                                                "moneda": "PEN",
                                                "incluye_igv": true
                                            },
                                            {
                                                "comprobantes": 10000,
                                                "precio": 480,
                                                "moneda": "PEN",
                                                "incluye_igv": true
                                            }
                                        ],
                                        "validez_meses": 6
                                    }
                                }
                            }
                        }
                    },
                    "401": {
                        "$ref": "#/components/responses/NoAutenticado"
                    }
                }
            }
        },
        "/movimientos": {
            "get": {
                "tags": [
                    "Saldo"
                ],
                "summary": "Consumos y recargas, del más nuevo al más viejo",
                "operationId": "movimientos",
                "parameters": [
                    {
                        "name": "tipo",
                        "in": "query",
                        "schema": {
                            "type": "string",
                            "enum": [
                                "consumo",
                                "recarga",
                                "ajuste"
                            ]
                        }
                    },
                    {
                        "name": "empresa_id",
                        "in": "query",
                        "schema": {
                            "type": "integer"
                        }
                    },
                    {
                        "name": "desde",
                        "in": "query",
                        "schema": {
                            "type": "string",
                            "format": "date"
                        }
                    },
                    {
                        "name": "hasta",
                        "in": "query",
                        "schema": {
                            "type": "string",
                            "format": "date"
                        }
                    },
                    {
                        "$ref": "#/components/parameters/Page"
                    },
                    {
                        "$ref": "#/components/parameters/PerPage"
                    }
                ],
                "responses": {
                    "200": {
                        "description": "Página de movimientos",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "type": "object",
                                    "properties": {
                                        "success": {
                                            "const": true
                                        },
                                        "data": {
                                            "type": "array",
                                            "items": {
                                                "$ref": "#/components/schemas/Movimiento"
                                            }
                                        },
                                        "meta": {
                                            "$ref": "#/components/schemas/Meta"
                                        }
                                    }
                                },
                                "example": {
                                    "success": true,
                                    "data": [
                                        {
                                            "id": 901,
                                            "tipo": "consumo",
                                            "unidades": -1,
                                            "concepto": "comprobante",
                                            "tipo_documento": "03",
                                            "referencia": "B001-842",
                                            "empresa_id": 15,
                                            "bolsa_id": 4,
                                            "fecha": "2026-11-03T10:20:11-05:00"
                                        }
                                    ],
                                    "meta": {
                                        "page": 1,
                                        "per_page": 20,
                                        "total": 1,
                                        "last_page": 1
                                    }
                                }
                            }
                        }
                    },
                    "401": {
                        "$ref": "#/components/responses/NoAutenticado"
                    },
                    "422": {
                        "$ref": "#/components/responses/Validacion"
                    }
                }
            }
        },
        "/webhooks": {
            "get": {
                "tags": [
                    "Webhooks"
                ],
                "summary": "Listar tus webhooks (y los eventos disponibles en meta)",
                "operationId": "listarWebhooks",
                "responses": {
                    "200": {
                        "description": "Los webhooks",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "type": "object",
                                    "properties": {
                                        "success": {
                                            "const": true
                                        },
                                        "data": {
                                            "type": "array",
                                            "items": {
                                                "$ref": "#/components/schemas/Webhook"
                                            }
                                        },
                                        "meta": {
                                            "type": "object",
                                            "properties": {
                                                "eventos_disponibles": {
                                                    "type": "object"
                                                }
                                            }
                                        }
                                    }
                                }
                            }
                        }
                    },
                    "401": {
                        "$ref": "#/components/responses/NoAutenticado"
                    }
                }
            },
            "post": {
                "tags": [
                    "Webhooks"
                ],
                "summary": "Registrar un webhook",
                "description": "Solo https a un dominio público. El secreto `whsec_…` se muestra una vez; con él verificas `X-SFP-Signature`.",
                "operationId": "crearWebhook",
                "parameters": [
                    {
                        "$ref": "#/components/parameters/IdempotencyKey"
                    }
                ],
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "type": "object",
                                "required": [
                                    "url",
                                    "eventos"
                                ],
                                "properties": {
                                    "url": {
                                        "type": "string",
                                        "format": "uri"
                                    },
                                    "eventos": {
                                        "type": "array",
                                        "items": {
                                            "$ref": "#/components/schemas/EventoSocio"
                                        }
                                    },
                                    "descripcion": {
                                        "type": "string",
                                        "maxLength": 150
                                    }
                                }
                            },
                            "example": {
                                "url": "https://tusistema.pe/webhooks/sfp",
                                "eventos": [
                                    "empresa.lista",
                                    "saldo.bajo",
                                    "saldo.agotado",
                                    "cuota.vencida"
                                ]
                            }
                        }
                    }
                },
                "responses": {
                    "201": {
                        "description": "El webhook con su secreto (una vez)",
                        "content": {
                            "application/json": {
                                "example": {
                                    "success": true,
                                    "data": {
                                        "id": 2,
                                        "url": "https://tusistema.pe/webhooks/sfp",
                                        "eventos": [
                                            "empresa.lista",
                                            "saldo.bajo"
                                        ],
                                        "descripcion": null,
                                        "activo": true,
                                        "ultima_entrega": null,
                                        "creado": "2026-11-03 10:00:00",
                                        "secreto": "whsec_…",
                                        "aviso": "Guarda el secreto ahora: no se vuelve a mostrar."
                                    }
                                }
                            }
                        }
                    },
                    "401": {
                        "$ref": "#/components/responses/NoAutenticado"
                    },
                    "422": {
                        "$ref": "#/components/responses/Validacion"
                    }
                }
            }
        },
        "/webhooks/{id}": {
            "delete": {
                "tags": [
                    "Webhooks"
                ],
                "summary": "Borrar un webhook (y su historial)",
                "operationId": "borrarWebhook",
                "parameters": [
                    {
                        "name": "id",
                        "in": "path",
                        "required": true,
                        "schema": {
                            "type": "integer"
                        }
                    }
                ],
                "responses": {
                    "200": {
                        "description": "Borrado",
                        "content": {
                            "application/json": {
                                "example": {
                                    "success": true,
                                    "data": {
                                        "id": 2,
                                        "borrado": true
                                    }
                                }
                            }
                        }
                    },
                    "401": {
                        "$ref": "#/components/responses/NoAutenticado"
                    },
                    "404": {
                        "$ref": "#/components/responses/NoEncontrado"
                    }
                }
            }
        },
        "/webhooks/{id}/entregas": {
            "get": {
                "tags": [
                    "Webhooks"
                ],
                "summary": "Entregas de un webhook",
                "operationId": "entregasWebhook",
                "parameters": [
                    {
                        "name": "id",
                        "in": "path",
                        "required": true,
                        "schema": {
                            "type": "integer"
                        }
                    },
                    {
                        "$ref": "#/components/parameters/Page"
                    },
                    {
                        "$ref": "#/components/parameters/PerPage"
                    }
                ],
                "responses": {
                    "200": {
                        "description": "Página de entregas",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "type": "object",
                                    "properties": {
                                        "success": {
                                            "const": true
                                        },
                                        "data": {
                                            "type": "array",
                                            "items": {
                                                "$ref": "#/components/schemas/Entrega"
                                            }
                                        },
                                        "meta": {
                                            "$ref": "#/components/schemas/Meta"
                                        }
                                    }
                                }
                            }
                        }
                    },
                    "401": {
                        "$ref": "#/components/responses/NoAutenticado"
                    },
                    "404": {
                        "$ref": "#/components/responses/NoEncontrado"
                    }
                }
            }
        },
        "/webhooks/entregas/{id}/reenviar": {
            "post": {
                "tags": [
                    "Webhooks"
                ],
                "summary": "Reenviar una entrega ya",
                "operationId": "reenviarEntrega",
                "parameters": [
                    {
                        "name": "id",
                        "in": "path",
                        "required": true,
                        "schema": {
                            "type": "integer"
                        }
                    },
                    {
                        "$ref": "#/components/parameters/IdempotencyKey"
                    }
                ],
                "responses": {
                    "202": {
                        "description": "En cola",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "type": "object",
                                    "properties": {
                                        "success": {
                                            "const": true
                                        },
                                        "data": {
                                            "$ref": "#/components/schemas/Entrega"
                                        }
                                    }
                                }
                            }
                        }
                    },
                    "401": {
                        "$ref": "#/components/responses/NoAutenticado"
                    },
                    "404": {
                        "$ref": "#/components/responses/NoEncontrado"
                    }
                }
            }
        }
    },
    "webhooks": {
        "evento": {
            "post": {
                "summary": "Aviso a tu URL",
                "description": "Cabeceras: `X-SFP-Signature: t=<unix>,v1=<hex HMAC-SHA256(secreto, \"t.cuerpo\")>`, `X-SFP-Delivery` (uuid) y\n`X-SFP-Event`. Responde 2xx en menos de 10 s; si no, reintentamos a 1 m, 5 m, 30 m, 2 h, 6 h y 24 h.\n",
                "requestBody": {
                    "content": {
                        "application/json": {
                            "schema": {
                                "$ref": "#/components/schemas/Aviso"
                            },
                            "example": {
                                "id": "2f6c1d9e-6a0e-4f0e-9d7e-2b3c4d5e6f70",
                                "evento": "saldo.bajo",
                                "creado": "2026-11-03T10:00:00-05:00",
                                "socio_id": 3,
                                "data": {
                                    "saldo": 660,
                                    "porcentaje_usado": 80,
                                    "umbral": 80
                                }
                            }
                        }
                    }
                },
                "responses": {
                    "200": {
                        "description": "Recibido"
                    }
                }
            }
        }
    },
    "components": {
        "securitySchemes": {
            "bearer": {
                "type": "http",
                "scheme": "bearer",
                "description": "Token `sfp_pat_<48>` de POST /token (1 hora)."
            }
        },
        "parameters": {
            "IdempotencyKey": {
                "name": "Idempotency-Key",
                "in": "header",
                "description": "Hasta 255 caracteres visibles (un UUID). Se recuerda 24 h.",
                "schema": {
                    "type": "string",
                    "maxLength": 255
                }
            },
            "IdEmpresa": {
                "name": "id",
                "in": "path",
                "required": true,
                "description": "El id de la empresa en esta API (el de GET /empresas)",
                "schema": {
                    "type": "integer"
                }
            },
            "Page": {
                "name": "page",
                "in": "query",
                "schema": {
                    "type": "integer",
                    "minimum": 1,
                    "default": 1
                }
            },
            "PerPage": {
                "name": "per_page",
                "in": "query",
                "schema": {
                    "type": "integer",
                    "minimum": 1,
                    "maximum": 100,
                    "default": 20
                }
            }
        },
        "responses": {
            "UnaEmpresa": {
                "description": "La empresa",
                "content": {
                    "application/json": {
                        "schema": {
                            "type": "object",
                            "properties": {
                                "success": {
                                    "const": true
                                },
                                "data": {
                                    "$ref": "#/components/schemas/Empresa"
                                }
                            }
                        }
                    }
                }
            },
            "PeticionInvalida": {
                "description": "`json_invalido` o `idempotencia_invalida`",
                "content": {
                    "application/json": {
                        "schema": {
                            "$ref": "#/components/schemas/Error"
                        }
                    }
                }
            },
            "NoAutenticado": {
                "description": "`token_invalido`, `token_vencido` o `token_en_url`; 403 `socio_suspendido` si la cuenta de socio está suspendida",
                "content": {
                    "application/json": {
                        "schema": {
                            "$ref": "#/components/schemas/Error"
                        },
                        "example": {
                            "success": false,
                            "code": "token_vencido",
                            "message": "El token de acceso venció (dura 60 minutos). Pide otro con POST /socios/v1/token."
                        }
                    }
                }
            },
            "NoEncontrado": {
                "description": "`no_encontrado` (no existe o no es tuya)",
                "content": {
                    "application/json": {
                        "schema": {
                            "$ref": "#/components/schemas/Error"
                        },
                        "example": {
                            "success": false,
                            "code": "no_encontrado",
                            "message": "La empresa no existe o no la puedes ver."
                        }
                    }
                }
            },
            "EmpresaNoLista": {
                "description": "`empresa_creandose` (con Retry-After) o `empresa_con_error`",
                "content": {
                    "application/json": {
                        "schema": {
                            "$ref": "#/components/schemas/Error"
                        }
                    }
                }
            },
            "Validacion": {
                "description": "`validacion` con los campos en `errors`",
                "content": {
                    "application/json": {
                        "schema": {
                            "$ref": "#/components/schemas/Error"
                        }
                    }
                }
            },
            "DemasiadasSolicitudes": {
                "description": "`demasiadas_solicitudes`, con Retry-After",
                "content": {
                    "application/json": {
                        "schema": {
                            "$ref": "#/components/schemas/Error"
                        }
                    }
                }
            }
        },
        "schemas": {
            "Error": {
                "type": "object",
                "required": [
                    "success",
                    "code",
                    "message"
                ],
                "properties": {
                    "success": {
                        "const": false
                    },
                    "code": {
                        "type": "string"
                    },
                    "message": {
                        "type": "string"
                    },
                    "errors": {
                        "type": "object",
                        "additionalProperties": {
                            "type": "array",
                            "items": {
                                "type": "string"
                            }
                        }
                    }
                }
            },
            "Meta": {
                "type": "object",
                "properties": {
                    "page": {
                        "type": "integer"
                    },
                    "per_page": {
                        "type": "integer"
                    },
                    "total": {
                        "type": "integer"
                    },
                    "last_page": {
                        "type": "integer"
                    }
                }
            },
            "PedidoToken": {
                "type": "object",
                "properties": {
                    "grant_type": {
                        "type": "string",
                        "enum": [
                            "client_credentials"
                        ]
                    },
                    "client_id": {
                        "type": "string"
                    },
                    "client_secret": {
                        "type": "string"
                    }
                }
            },
            "RespuestaToken": {
                "type": "object",
                "properties": {
                    "success": {
                        "const": true
                    },
                    "access_token": {
                        "type": "string"
                    },
                    "token_type": {
                        "const": "Bearer"
                    },
                    "expires_in": {
                        "type": "integer",
                        "description": "Segundos"
                    },
                    "expires_at": {
                        "type": "string",
                        "format": "date-time"
                    },
                    "data": {
                        "type": "object"
                    }
                }
            },
            "EstadoEmpresa": {
                "type": "string",
                "enum": [
                    "creando",
                    "por_verificar",
                    "lista",
                    "suspendida",
                    "error"
                ],
                "description": "creando: el alta corre (1 a 3 minutos). por_verificar: falta algo para emitir (mira `pendientes`).\nlista: ya emite. suspendida: la pausaste tú o la bloqueó la plataforma (mira `suspension`). error: el alta falló (escríbenos).\n"
            },
            "Empresa": {
                "type": "object",
                "properties": {
                    "id": {
                        "type": "integer"
                    },
                    "ruc": {
                        "type": "string"
                    },
                    "razon_social": {
                        "type": "string"
                    },
                    "subdominio": {
                        "type": "string"
                    },
                    "estado": {
                        "$ref": "#/components/schemas/EstadoEmpresa"
                    },
                    "pendientes": {
                        "type": "array",
                        "items": {
                            "type": "object",
                            "properties": {
                                "codigo": {
                                    "type": "string",
                                    "enum": [
                                        "ficha_ruc",
                                        "produccion",
                                        "certificado",
                                        "usuario_sol",
                                        "credenciales_pse"
                                    ]
                                },
                                "detalle": {
                                    "type": "string"
                                }
                            }
                        }
                    },
                    "envio": {
                        "type": [
                            "string",
                            "null"
                        ],
                        "enum": [
                            "sol_propio",
                            "pse",
                            "demo",
                            null
                        ],
                        "description": "sol_propio no descuenta de tu bolsa; pse sí"
                    },
                    "suspension": {
                        "type": [
                            "object",
                            "null"
                        ],
                        "properties": {
                            "por": {
                                "type": "string",
                                "enum": [
                                    "socio",
                                    "agencia"
                                ]
                            },
                            "motivo": {
                                "type": [
                                    "string",
                                    "null"
                                ]
                            },
                            "desde": {
                                "type": [
                                    "string",
                                    "null"
                                ],
                                "format": "date-time"
                            }
                        }
                    },
                    "web": {
                        "type": [
                            "string",
                            "null"
                        ],
                        "format": "uri"
                    },
                    "api_v1": {
                        "type": [
                            "string",
                            "null"
                        ],
                        "format": "uri"
                    },
                    "lista_desde": {
                        "type": [
                            "string",
                            "null"
                        ],
                        "format": "date-time"
                    },
                    "creada": {
                        "type": "string",
                        "format": "date-time"
                    }
                }
            },
            "Certificado": {
                "type": "object",
                "required": [
                    "pfx_base64",
                    "clave"
                ],
                "properties": {
                    "pfx_base64": {
                        "type": "string",
                        "description": "El archivo .pfx en base64 (hasta 1 MB), con su clave privada"
                    },
                    "clave": {
                        "type": "string"
                    }
                }
            },
            "Sol": {
                "type": "object",
                "required": [
                    "usuario",
                    "clave"
                ],
                "properties": {
                    "usuario": {
                        "type": "string",
                        "description": "Usuario SOL secundario (sin el RUC delante; también se acepta con él)"
                    },
                    "clave": {
                        "type": "string"
                    }
                }
            },
            "Direccion": {
                "type": "object",
                "required": [
                    "direccion",
                    "ubigeo"
                ],
                "properties": {
                    "direccion": {
                        "type": "string",
                        "maxLength": 200
                    },
                    "ubigeo": {
                        "type": "string",
                        "pattern": "^\\d{6}$",
                        "description": "INEI (150101 = Lima, Lima, Lima)"
                    }
                }
            },
            "AltaEmpresa": {
                "type": "object",
                "required": [
                    "ruc",
                    "razon_social",
                    "administrador"
                ],
                "properties": {
                    "ruc": {
                        "type": "string",
                        "pattern": "^(10|15|16|17|20)\\d{9}$"
                    },
                    "razon_social": {
                        "type": "string",
                        "maxLength": 255
                    },
                    "nombre_comercial": {
                        "type": "string",
                        "maxLength": 255
                    },
                    "subdominio": {
                        "type": "string",
                        "pattern": "^[a-z0-9][a-z0-9-]{1,28}[a-z0-9]$",
                        "description": "Si no va, se arma del nombre"
                    },
                    "regimen_tributario": {
                        "type": "string",
                        "enum": [
                            "general",
                            "rmt",
                            "rer",
                            "nrus",
                            "sin_negocio"
                        ]
                    },
                    "direccion": {
                        "$ref": "#/components/schemas/Direccion"
                    },
                    "administrador": {
                        "type": "object",
                        "required": [
                            "nombre",
                            "correo"
                        ],
                        "properties": {
                            "nombre": {
                                "type": "string",
                                "maxLength": 120
                            },
                            "correo": {
                                "type": "string",
                                "format": "email"
                            },
                            "celular": {
                                "type": "string"
                            },
                            "contrasena": {
                                "type": "string",
                                "minLength": 8,
                                "maxLength": 64
                            }
                        }
                    },
                    "certificado": {
                        "$ref": "#/components/schemas/Certificado"
                    },
                    "sol": {
                        "$ref": "#/components/schemas/Sol"
                    },
                    "envio": {
                        "type": "string",
                        "enum": [
                            "sol_propio",
                            "pse"
                        ]
                    }
                }
            },
            "CambioEmpresa": {
                "type": "object",
                "properties": {
                    "nombre_comercial": {
                        "type": "string"
                    },
                    "direccion": {
                        "$ref": "#/components/schemas/Direccion"
                    },
                    "administrador": {
                        "type": "object",
                        "properties": {
                            "nombre": {
                                "type": "string"
                            }
                        }
                    },
                    "contacto": {
                        "type": "object",
                        "properties": {
                            "nombre": {
                                "type": "string"
                            },
                            "correo": {
                                "type": "string",
                                "format": "email"
                            },
                            "celular": {
                                "type": "string"
                            }
                        }
                    },
                    "certificado": {
                        "$ref": "#/components/schemas/Certificado"
                    },
                    "sol": {
                        "$ref": "#/components/schemas/Sol"
                    },
                    "envio": {
                        "type": "string",
                        "enum": [
                            "sol_propio",
                            "pse"
                        ]
                    }
                }
            },
            "Uso": {
                "type": "object",
                "properties": {
                    "mes": {
                        "type": "string"
                    },
                    "emitidos": {
                        "type": "object",
                        "additionalProperties": {
                            "type": "integer"
                        }
                    },
                    "descontado_de_la_bolsa": {
                        "type": "object",
                        "properties": {
                            "total": {
                                "type": "integer"
                            },
                            "por_concepto": {
                                "type": "object",
                                "properties": {
                                    "comprobante": {
                                        "type": "integer"
                                    },
                                    "resumen": {
                                        "type": "integer"
                                    },
                                    "baja": {
                                        "type": "integer"
                                    },
                                    "guia": {
                                        "type": "integer"
                                    }
                                }
                            }
                        }
                    },
                    "activa": {
                        "type": "boolean",
                        "description": "Emitió algo este mes (cuenta para la cuota)"
                    }
                }
            },
            "Clave": {
                "type": "object",
                "properties": {
                    "id": {
                        "type": "integer"
                    },
                    "nombre": {
                        "type": "string"
                    },
                    "prefijo": {
                        "type": "string"
                    },
                    "permisos": {
                        "type": "array",
                        "items": {
                            "type": "string"
                        }
                    },
                    "establecimiento_id": {
                        "type": [
                            "integer",
                            "null"
                        ]
                    },
                    "vence": {
                        "type": [
                            "string",
                            "null"
                        ],
                        "format": "date"
                    },
                    "ultimo_uso": {
                        "type": [
                            "string",
                            "null"
                        ],
                        "format": "date-time"
                    },
                    "estado": {
                        "type": "string",
                        "enum": [
                            "activa",
                            "vencida",
                            "revocada"
                        ]
                    },
                    "creada": {
                        "type": "string",
                        "format": "date-time"
                    }
                }
            },
            "Bolsa": {
                "type": "object",
                "properties": {
                    "id": {
                        "type": "integer"
                    },
                    "comprobantes": {
                        "type": "integer"
                    },
                    "usados": {
                        "type": "integer"
                    },
                    "quedan": {
                        "type": "integer"
                    },
                    "precio": {
                        "type": "number"
                    },
                    "comprada": {
                        "type": "string",
                        "format": "date"
                    },
                    "vence": {
                        "type": "string",
                        "format": "date"
                    },
                    "estado": {
                        "type": "string",
                        "enum": [
                            "vigente",
                            "agotada",
                            "vencida"
                        ]
                    }
                }
            },
            "Cuota": {
                "type": "object",
                "properties": {
                    "id": {
                        "type": "integer"
                    },
                    "mes": {
                        "type": "string"
                    },
                    "empresas_activas": {
                        "type": "integer"
                    },
                    "monto_por_empresa": {
                        "type": "number"
                    },
                    "monto": {
                        "type": "number"
                    },
                    "moneda": {
                        "const": "PEN"
                    },
                    "incluye_igv": {
                        "const": true
                    },
                    "estado": {
                        "type": "string",
                        "enum": [
                            "pendiente",
                            "pagado",
                            "anulado"
                        ]
                    },
                    "vence": {
                        "type": "string",
                        "format": "date"
                    },
                    "vencida": {
                        "type": "boolean"
                    },
                    "pagado": {
                        "type": [
                            "string",
                            "null"
                        ],
                        "format": "date"
                    }
                }
            },
            "Saldo": {
                "type": "object",
                "properties": {
                    "saldo": {
                        "type": "integer",
                        "description": "Comprobantes disponibles (puede ser negativo: resúmenes y bajas enviados sin saldo)"
                    },
                    "en_bolsas_vigentes": {
                        "type": "integer"
                    },
                    "por_cobrar_en_la_siguiente_recarga": {
                        "type": "integer"
                    },
                    "porcentaje_usado": {
                        "type": "integer"
                    },
                    "proximo_vencimiento": {
                        "type": [
                            "object",
                            "null"
                        ],
                        "properties": {
                            "fecha": {
                                "type": "string",
                                "format": "date"
                            },
                            "unidades": {
                                "type": "integer"
                            }
                        }
                    },
                    "bolsas": {
                        "type": "array",
                        "items": {
                            "$ref": "#/components/schemas/Bolsa"
                        }
                    },
                    "cuotas_pendientes": {
                        "type": "array",
                        "items": {
                            "$ref": "#/components/schemas/Cuota"
                        }
                    },
                    "precios": {
                        "type": "array",
                        "items": {
                            "type": "object",
                            "properties": {
                                "comprobantes": {
                                    "type": "integer"
                                },
                                "precio": {
                                    "type": "number"
                                },
                                "moneda": {
                                    "const": "PEN"
                                },
                                "incluye_igv": {
                                    "const": true
                                }
                            }
                        }
                    },
                    "validez_meses": {
                        "type": "integer"
                    }
                }
            },
            "Movimiento": {
                "type": "object",
                "properties": {
                    "id": {
                        "type": "integer"
                    },
                    "tipo": {
                        "type": "string",
                        "enum": [
                            "consumo",
                            "recarga",
                            "ajuste"
                        ]
                    },
                    "unidades": {
                        "type": "integer"
                    },
                    "concepto": {
                        "type": [
                            "string",
                            "null"
                        ],
                        "enum": [
                            "comprobante",
                            "resumen",
                            "baja",
                            "guia",
                            null
                        ]
                    },
                    "tipo_documento": {
                        "type": [
                            "string",
                            "null"
                        ]
                    },
                    "referencia": {
                        "type": [
                            "string",
                            "null"
                        ]
                    },
                    "empresa_id": {
                        "type": [
                            "integer",
                            "null"
                        ]
                    },
                    "bolsa_id": {
                        "type": [
                            "integer",
                            "null"
                        ]
                    },
                    "fecha": {
                        "type": "string",
                        "format": "date-time"
                    }
                }
            },
            "EventoSocio": {
                "type": "string",
                "enum": [
                    "empresa.lista",
                    "empresa.suspendida",
                    "empresa.reactivada",
                    "empresa.error",
                    "saldo.bajo",
                    "saldo.agotado",
                    "cuota.pendiente",
                    "cuota.por_vencer",
                    "cuota.vencida"
                ]
            },
            "Webhook": {
                "type": "object",
                "properties": {
                    "id": {
                        "type": "integer"
                    },
                    "url": {
                        "type": "string",
                        "format": "uri"
                    },
                    "eventos": {
                        "type": "array",
                        "items": {
                            "$ref": "#/components/schemas/EventoSocio"
                        }
                    },
                    "descripcion": {
                        "type": [
                            "string",
                            "null"
                        ]
                    },
                    "activo": {
                        "type": "boolean"
                    },
                    "ultima_entrega": {
                        "type": [
                            "object",
                            "null"
                        ]
                    },
                    "creado": {
                        "type": "string"
                    }
                }
            },
            "Entrega": {
                "type": "object",
                "properties": {
                    "id": {
                        "type": "integer"
                    },
                    "uuid": {
                        "type": "string"
                    },
                    "webhook_id": {
                        "type": "integer"
                    },
                    "evento": {
                        "$ref": "#/components/schemas/EventoSocio"
                    },
                    "estado": {
                        "type": "string",
                        "enum": [
                            "pendiente",
                            "reintentando",
                            "entregado",
                            "fallido"
                        ]
                    },
                    "intentos": {
                        "type": "integer"
                    },
                    "codigo_respuesta": {
                        "type": [
                            "integer",
                            "null"
                        ]
                    },
                    "error": {
                        "type": [
                            "string",
                            "null"
                        ]
                    },
                    "proximo_intento": {
                        "type": [
                            "string",
                            "null"
                        ]
                    },
                    "entregado": {
                        "type": [
                            "string",
                            "null"
                        ]
                    },
                    "creado": {
                        "type": "string"
                    }
                }
            },
            "Aviso": {
                "type": "object",
                "properties": {
                    "id": {
                        "type": "string",
                        "format": "uuid"
                    },
                    "evento": {
                        "$ref": "#/components/schemas/EventoSocio"
                    },
                    "creado": {
                        "type": "string",
                        "format": "date-time"
                    },
                    "socio_id": {
                        "type": "integer"
                    },
                    "data": {
                        "type": "object"
                    }
                }
            }
        }
    }
}
