{
    "openapi": "3.1.0",
    "info": {
        "title": "API Trebede - CRM (comercial: empresas, contactos y visitas)",
        "version": "1.0.0",
        "description": "API REST del CRM Trebede - modulo CRM (comercial: empresas, contactos y visitas). Esta clave solo da acceso a este modulo (mas /v1/estado para comprobar la conexion).\n\nAutenticacion: envia tu clave en la cabecera X-API-KEY. Las claves las facilita Trebede y determinan la empresa, el usuario y los modulos accesibles.\n\nRespuestas: JSON UTF-8 con {\"ok\":true,\"datos\":...,\"meta\":{...}} en exito y {\"ok\":false,\"error\":{\"codigo\":...,\"mensaje\":...}} en error. Fechas en formato AAAA-MM-DD. Paginacion con 'pagina' y 'por_pagina' (max 200); el total viene en meta.total.\n\nLimites: por defecto 60 peticiones/minuto y 5000/dia por clave (429 con Retry-After al superarlos).\n\nDocumentacion para personas: https://api.trebede.com/docs/crm",
        "contact": {
            "name": "Trebede",
            "email": "crm@trebede.com",
            "url": "https://www.trebede.com"
        }
    },
    "servers": [
        {
            "url": "https://api.trebede.com"
        }
    ],
    "security": [
        {
            "ApiKeyAuth": []
        }
    ],
    "tags": [
        {
            "name": "sistema",
            "description": "Sistema"
        },
        {
            "name": "crm",
            "description": "CRM (comercial: empresas, contactos y visitas)"
        }
    ],
    "paths": {
        "/v1/estado": {
            "get": {
                "operationId": "estado",
                "summary": "Comprueba la conexion y devuelve la identidad de la clave",
                "description": "Devuelve la version de la API, la empresa y el usuario asociados a la clave, los modulos permitidos y los limites de uso. Usalo para verificar que la clave funciona.",
                "tags": [
                    "sistema"
                ],
                "responses": {
                    "200": {
                        "description": "Respuesta correcta",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Exito"
                                }
                            }
                        }
                    },
                    "default": {
                        "description": "Error (400 peticion, 401 clave, 403 permiso, 404 no existe, 409 conflicto/duplicado, 422 parametros, 429 limite)",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Error"
                                }
                            }
                        }
                    }
                }
            }
        },
        "/v1/crm/empresas": {
            "get": {
                "operationId": "crm_empresas",
                "summary": "Busca empresas/clientes del CRM",
                "description": "Comprueba si existe un cliente y devuelve sus datos de contacto. Busca por nombre/referencia, telefono (tambien de sus contactos), NIF o mail. Sin filtros lista las ultimas modificadas.",
                "tags": [
                    "crm"
                ],
                "responses": {
                    "200": {
                        "description": "Respuesta correcta",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Exito"
                                }
                            }
                        }
                    },
                    "default": {
                        "description": "Error (400 peticion, 401 clave, 403 permiso, 404 no existe, 409 conflicto/duplicado, 422 parametros, 429 limite)",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Error"
                                }
                            }
                        }
                    }
                },
                "parameters": [
                    {
                        "name": "buscar",
                        "in": "query",
                        "required": false,
                        "description": "Texto a buscar en nombre o referencia",
                        "schema": {
                            "type": "string",
                            "maxLength": 110
                        }
                    },
                    {
                        "name": "telefono",
                        "in": "query",
                        "required": false,
                        "description": "Telefono exacto (empresa o contacto)",
                        "schema": {
                            "type": "string",
                            "maxLength": 25
                        }
                    },
                    {
                        "name": "nif",
                        "in": "query",
                        "required": false,
                        "description": "NIF exacto",
                        "schema": {
                            "type": "string",
                            "maxLength": 25
                        }
                    },
                    {
                        "name": "mail",
                        "in": "query",
                        "required": false,
                        "description": "Email exacto (empresa o contacto)",
                        "schema": {
                            "type": "string",
                            "maxLength": 50
                        }
                    },
                    {
                        "name": "pagina",
                        "in": "query",
                        "required": false,
                        "description": "Pagina (desde 1)",
                        "schema": {
                            "type": "integer"
                        }
                    },
                    {
                        "name": "por_pagina",
                        "in": "query",
                        "required": false,
                        "description": "Resultados por pagina (1-200, defecto 50)",
                        "schema": {
                            "type": "integer"
                        }
                    }
                ]
            },
            "post": {
                "operationId": "crm_empresa_crear",
                "summary": "Crea una empresa nueva en el CRM",
                "description": "Da de alta una empresa asignada al usuario de la clave. Si ya existe otra con el mismo nombre, referencia, NIF o telefono devuelve 409 con su id.",
                "tags": [
                    "crm"
                ],
                "responses": {
                    "200": {
                        "description": "Respuesta correcta",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Exito"
                                }
                            }
                        }
                    },
                    "default": {
                        "description": "Error (400 peticion, 401 clave, 403 permiso, 404 no existe, 409 conflicto/duplicado, 422 parametros, 429 limite)",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Error"
                                }
                            }
                        }
                    }
                },
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "type": "object",
                                "properties": {
                                    "nombre": {
                                        "type": "string",
                                        "maxLength": 110,
                                        "description": "Nombre de la empresa"
                                    },
                                    "referencia": {
                                        "type": "string",
                                        "maxLength": 110,
                                        "description": "Referencia externa"
                                    },
                                    "tfno": {
                                        "type": "string",
                                        "maxLength": 25,
                                        "description": "Telefono"
                                    },
                                    "movil": {
                                        "type": "string",
                                        "maxLength": 25,
                                        "description": "Movil"
                                    },
                                    "mail": {
                                        "type": "string",
                                        "maxLength": 50,
                                        "description": "Email"
                                    },
                                    "nif": {
                                        "type": "string",
                                        "maxLength": 25,
                                        "description": "NIF"
                                    },
                                    "direccion": {
                                        "type": "string",
                                        "maxLength": 100,
                                        "description": "Direccion"
                                    },
                                    "cp": {
                                        "type": "string",
                                        "maxLength": 11,
                                        "description": "Codigo postal"
                                    },
                                    "poblacion": {
                                        "type": "string",
                                        "maxLength": 50,
                                        "description": "Poblacion"
                                    },
                                    "provincia": {
                                        "type": "string",
                                        "maxLength": 50,
                                        "description": "Provincia"
                                    },
                                    "web": {
                                        "type": "string",
                                        "maxLength": 50,
                                        "description": "Web"
                                    },
                                    "actividad": {
                                        "type": "string",
                                        "maxLength": 50,
                                        "description": "Actividad/sector"
                                    },
                                    "observaciones": {
                                        "type": "string",
                                        "description": "Observaciones"
                                    }
                                },
                                "required": [
                                    "nombre"
                                ]
                            }
                        }
                    }
                }
            }
        },
        "/v1/crm/empresas/{id}": {
            "get": {
                "operationId": "crm_empresa",
                "summary": "Ficha de una empresa con sus contactos",
                "description": "Devuelve la ficha completa: telefono, mail, direccion, NIF, observaciones, comercial asignado y lista de contactos.",
                "tags": [
                    "crm"
                ],
                "responses": {
                    "200": {
                        "description": "Respuesta correcta",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Exito"
                                }
                            }
                        }
                    },
                    "default": {
                        "description": "Error (400 peticion, 401 clave, 403 permiso, 404 no existe, 409 conflicto/duplicado, 422 parametros, 429 limite)",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Error"
                                }
                            }
                        }
                    }
                },
                "parameters": [
                    {
                        "name": "id",
                        "in": "path",
                        "required": true,
                        "description": "Id de la empresa",
                        "schema": {
                            "type": "integer"
                        }
                    }
                ]
            }
        },
        "/v1/crm/empresas/{id}/historial": {
            "get": {
                "operationId": "crm_historial",
                "summary": "Historial de interacciones de una empresa",
                "description": "Devuelve las visitas, llamadas y notas de la empresa (agendadas y realizadas), con fecha, comercial, resultado y notas.",
                "tags": [
                    "crm"
                ],
                "responses": {
                    "200": {
                        "description": "Respuesta correcta",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Exito"
                                }
                            }
                        }
                    },
                    "default": {
                        "description": "Error (400 peticion, 401 clave, 403 permiso, 404 no existe, 409 conflicto/duplicado, 422 parametros, 429 limite)",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Error"
                                }
                            }
                        }
                    }
                },
                "parameters": [
                    {
                        "name": "id",
                        "in": "path",
                        "required": true,
                        "description": "Id de la empresa",
                        "schema": {
                            "type": "integer"
                        }
                    },
                    {
                        "name": "pagina",
                        "in": "query",
                        "required": false,
                        "description": "Pagina (desde 1)",
                        "schema": {
                            "type": "integer"
                        }
                    },
                    {
                        "name": "por_pagina",
                        "in": "query",
                        "required": false,
                        "description": "Resultados por pagina (1-200, defecto 50)",
                        "schema": {
                            "type": "integer"
                        }
                    }
                ]
            }
        },
        "/v1/crm/agenda": {
            "get": {
                "operationId": "crm_agenda",
                "summary": "Visitas pendientes en la agenda",
                "description": "Devuelve las visitas agendadas (no realizadas) del comercial entre dos fechas (por defecto los proximos 7 dias).",
                "tags": [
                    "crm"
                ],
                "responses": {
                    "200": {
                        "description": "Respuesta correcta",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Exito"
                                }
                            }
                        }
                    },
                    "default": {
                        "description": "Error (400 peticion, 401 clave, 403 permiso, 404 no existe, 409 conflicto/duplicado, 422 parametros, 429 limite)",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Error"
                                }
                            }
                        }
                    }
                },
                "parameters": [
                    {
                        "name": "desde",
                        "in": "query",
                        "required": false,
                        "description": "Fecha inicial (defecto hoy)",
                        "schema": {
                            "type": "string",
                            "format": "date",
                            "example": "2026-07-01"
                        }
                    },
                    {
                        "name": "hasta",
                        "in": "query",
                        "required": false,
                        "description": "Fecha final (defecto desde+6 dias)",
                        "schema": {
                            "type": "string",
                            "format": "date",
                            "example": "2026-07-01"
                        }
                    },
                    {
                        "name": "comercial",
                        "in": "query",
                        "required": false,
                        "description": "Id de otro comercial (requiere permiso de ver todos)",
                        "schema": {
                            "type": "integer"
                        }
                    },
                    {
                        "name": "pagina",
                        "in": "query",
                        "required": false,
                        "description": "Pagina (desde 1)",
                        "schema": {
                            "type": "integer"
                        }
                    },
                    {
                        "name": "por_pagina",
                        "in": "query",
                        "required": false,
                        "description": "Resultados por pagina (1-200, defecto 50)",
                        "schema": {
                            "type": "integer"
                        }
                    }
                ]
            }
        },
        "/v1/crm/personas": {
            "get": {
                "operationId": "crm_personas",
                "summary": "Busca contactos (personas)",
                "description": "Devuelve contactos por nombre, telefono o mail, con la empresa a la que pertenecen.",
                "tags": [
                    "crm"
                ],
                "responses": {
                    "200": {
                        "description": "Respuesta correcta",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Exito"
                                }
                            }
                        }
                    },
                    "default": {
                        "description": "Error (400 peticion, 401 clave, 403 permiso, 404 no existe, 409 conflicto/duplicado, 422 parametros, 429 limite)",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Error"
                                }
                            }
                        }
                    }
                },
                "parameters": [
                    {
                        "name": "buscar",
                        "in": "query",
                        "required": false,
                        "description": "Texto a buscar en nombre y apellidos",
                        "schema": {
                            "type": "string",
                            "maxLength": 110
                        }
                    },
                    {
                        "name": "telefono",
                        "in": "query",
                        "required": false,
                        "description": "Telefono exacto",
                        "schema": {
                            "type": "string",
                            "maxLength": 25
                        }
                    },
                    {
                        "name": "mail",
                        "in": "query",
                        "required": false,
                        "description": "Email exacto",
                        "schema": {
                            "type": "string",
                            "maxLength": 50
                        }
                    },
                    {
                        "name": "pagina",
                        "in": "query",
                        "required": false,
                        "description": "Pagina (desde 1)",
                        "schema": {
                            "type": "integer"
                        }
                    },
                    {
                        "name": "por_pagina",
                        "in": "query",
                        "required": false,
                        "description": "Resultados por pagina (1-200, defecto 50)",
                        "schema": {
                            "type": "integer"
                        }
                    }
                ]
            }
        },
        "/v1/crm/apreciaciones": {
            "get": {
                "operationId": "crm_apreciaciones",
                "summary": "Resultados de visita disponibles (apreciaciones)",
                "description": "Devuelve la lista de resultados con los que se puede anotar una visita (Venta, Presupuesto, No interesa...). Usala antes de anotar un resultado.",
                "tags": [
                    "crm"
                ],
                "responses": {
                    "200": {
                        "description": "Respuesta correcta",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Exito"
                                }
                            }
                        }
                    },
                    "default": {
                        "description": "Error (400 peticion, 401 clave, 403 permiso, 404 no existe, 409 conflicto/duplicado, 422 parametros, 429 limite)",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Error"
                                }
                            }
                        }
                    }
                }
            }
        },
        "/v1/crm/contactos": {
            "post": {
                "operationId": "crm_contacto_crear",
                "summary": "Crea un contacto en una empresa",
                "description": "Da de alta una persona de contacto en una empresa visible para el usuario. Si ya existe un contacto con ese mail devuelve 409.",
                "tags": [
                    "crm"
                ],
                "responses": {
                    "200": {
                        "description": "Respuesta correcta",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Exito"
                                }
                            }
                        }
                    },
                    "default": {
                        "description": "Error (400 peticion, 401 clave, 403 permiso, 404 no existe, 409 conflicto/duplicado, 422 parametros, 429 limite)",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Error"
                                }
                            }
                        }
                    }
                },
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "type": "object",
                                "properties": {
                                    "empresa": {
                                        "type": "integer",
                                        "description": "Id de la empresa"
                                    },
                                    "nombre": {
                                        "type": "string",
                                        "maxLength": 110,
                                        "description": "Nombre"
                                    },
                                    "apellido1": {
                                        "type": "string",
                                        "maxLength": 50,
                                        "description": "Primer apellido"
                                    },
                                    "apellido2": {
                                        "type": "string",
                                        "maxLength": 50,
                                        "description": "Segundo apellido"
                                    },
                                    "cargo": {
                                        "type": "string",
                                        "maxLength": 50,
                                        "description": "Cargo"
                                    },
                                    "mail": {
                                        "type": "string",
                                        "maxLength": 50,
                                        "description": "Email"
                                    },
                                    "movil": {
                                        "type": "string",
                                        "maxLength": 50,
                                        "description": "Movil"
                                    },
                                    "tfno": {
                                        "type": "string",
                                        "maxLength": 50,
                                        "description": "Telefono"
                                    }
                                },
                                "required": [
                                    "empresa",
                                    "nombre"
                                ]
                            }
                        }
                    }
                }
            }
        },
        "/v1/crm/visitas": {
            "post": {
                "operationId": "crm_visita_crear",
                "summary": "Planifica una visita en la agenda",
                "description": "Crea una visita agendada para una empresa: fecha, hora opcional, duracion y notas. Por defecto se asigna al usuario de la clave; asignarla a otro comercial requiere permiso de ver todos. Sincroniza con Google Calendar si esta configurado.",
                "tags": [
                    "crm"
                ],
                "responses": {
                    "200": {
                        "description": "Respuesta correcta",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Exito"
                                }
                            }
                        }
                    },
                    "default": {
                        "description": "Error (400 peticion, 401 clave, 403 permiso, 404 no existe, 409 conflicto/duplicado, 422 parametros, 429 limite)",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Error"
                                }
                            }
                        }
                    }
                },
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "type": "object",
                                "properties": {
                                    "empresa": {
                                        "type": "integer",
                                        "description": "Id de la empresa a visitar"
                                    },
                                    "fecha": {
                                        "type": "string",
                                        "format": "date",
                                        "example": "2026-07-01",
                                        "description": "Fecha de la visita (AAAA-MM-DD)"
                                    },
                                    "hora": {
                                        "type": "string",
                                        "maxLength": 5,
                                        "description": "Hora HH:MM (opcional)"
                                    },
                                    "duracion": {
                                        "type": "integer",
                                        "description": "Duracion en minutos (defecto 60)"
                                    },
                                    "notas": {
                                        "type": "string",
                                        "description": "Objetivo o notas de la visita"
                                    },
                                    "comercial": {
                                        "type": "integer",
                                        "description": "Id de otro comercial (requiere ver todos)"
                                    },
                                    "contacto": {
                                        "type": "integer",
                                        "description": "Id del contacto de la empresa"
                                    }
                                },
                                "required": [
                                    "empresa",
                                    "fecha"
                                ]
                            }
                        }
                    }
                }
            }
        },
        "/v1/crm/visitas/{id}/resultado": {
            "post": {
                "operationId": "crm_visita_resultado",
                "summary": "Anota el resultado de una visita (la cierra)",
                "description": "Marca una visita agendada como realizada: guarda las notas de lo ocurrido y opcionalmente el resultado (apreciacion), moviendo la empresa de fase de embudo si procede. Las automatizaciones especificas por cliente del CRM no se ejecutan por API.",
                "tags": [
                    "crm"
                ],
                "responses": {
                    "200": {
                        "description": "Respuesta correcta",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Exito"
                                }
                            }
                        }
                    },
                    "default": {
                        "description": "Error (400 peticion, 401 clave, 403 permiso, 404 no existe, 409 conflicto/duplicado, 422 parametros, 429 limite)",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Error"
                                }
                            }
                        }
                    }
                },
                "parameters": [
                    {
                        "name": "id",
                        "in": "path",
                        "required": true,
                        "description": "Id de la visita",
                        "schema": {
                            "type": "integer"
                        }
                    }
                ],
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "type": "object",
                                "properties": {
                                    "notas": {
                                        "type": "string",
                                        "description": "Que ha pasado en la visita"
                                    },
                                    "resultado": {
                                        "type": "integer",
                                        "description": "Id del resultado (ver GET /v1/crm/apreciaciones)"
                                    },
                                    "resultado_nombre": {
                                        "type": "string",
                                        "maxLength": 110,
                                        "description": "Nombre del resultado si no se conoce el id"
                                    }
                                },
                                "required": [
                                    "notas"
                                ]
                            }
                        }
                    }
                }
            }
        }
    },
    "components": {
        "securitySchemes": {
            "ApiKeyAuth": {
                "type": "apiKey",
                "in": "header",
                "name": "X-API-KEY"
            }
        },
        "schemas": {
            "Exito": {
                "type": "object",
                "properties": {
                    "ok": {
                        "type": "boolean",
                        "example": true
                    },
                    "datos": {
                        "description": "Objeto o lista con el resultado"
                    },
                    "meta": {
                        "type": "object",
                        "description": "Paginacion: pagina, por_pagina, total"
                    }
                }
            },
            "Error": {
                "type": "object",
                "properties": {
                    "ok": {
                        "type": "boolean",
                        "example": false
                    },
                    "error": {
                        "type": "object",
                        "properties": {
                            "codigo": {
                                "type": "string",
                                "example": "parametro_invalido"
                            },
                            "mensaje": {
                                "type": "string"
                            }
                        }
                    }
                }
            }
        }
    }
}