{"openapi":"3.0.0","paths":{"/v1/me":{"get":{"description":"Devuelve los permisos efectivos otorgados por el Personal Access Token autenticado.","operationId":"MeController_getMe","parameters":[],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/MeResponseDto"}}}},"401":{"description":"Token inválido, revocado o expirado"}},"security":[{"PAT":[]}],"summary":"Obtener permisos efectivos del token","tags":["me"]}},"/v1/me/projects":{"get":{"operationId":"MeController_listProjects","parameters":[],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"type":"object"}}}}},"security":[{"PAT":[]}],"summary":"Listar projects de la company autenticada. Útil para que el CLI elija project context.","tags":["me"]}},"/v1/me/token":{"delete":{"description":"Marca el PAT con el que se autenticó esta request como revocado. Próximas requests con el mismo token devolverán 401.","operationId":"MeController_revokeCurrentToken","parameters":[],"responses":{"204":{"description":""},"401":{"description":"Token inválido, revocado o expirado"}},"security":[{"PAT":[]}],"summary":"Revocar el token actualmente autenticado (logout server-side)","tags":["me"]}},"/v1/messages":{"post":{"description":"The `message` object is discriminated by `type`: text, image, video, audio, document, sticker, location, contacts, reaction, template, buttons, list, cta_url, catalog, carousel or flow. Not every channel carries every type — an unsupported combination returns 422 MESSAGE_TYPE_NOT_SUPPORTED_FOR_CHANNEL listing what the channel does accept. Pick a ready-to-send body from the examples below.","operationId":"PublicMessagesController_send","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SendMessageDto"},"examples":{"text":{"summary":"text — free-form message","description":"Only reaches a recipient whose last inbound message is under 24 hours old.","value":{"channel":"whatsapp","to":"+5491155555555","message":{"type":"text","body":"Hola Juan, ¿pudiste revisar la propuesta?","preview_url":true}}},"image":{"summary":"image — by public URL","description":"Use `media_id` instead of `link` for an uploaded file.","value":{"channel":"whatsapp","to":"+5491155555555","message":{"type":"image","link":"https://cdn.example.com/promo.png","caption":"Promo de marzo"}}},"video":{"summary":"video — by public URL","value":{"channel":"whatsapp","to":"+5491155555555","message":{"type":"video","link":"https://cdn.example.com/demo.mp4","caption":"Cómo activar tu cuenta"}}},"audio":{"summary":"audio — voice note","description":"Omit `voice` or set it to false to send a plain audio file.","value":{"channel":"whatsapp","to":"+5491155555555","message":{"type":"audio","link":"https://cdn.example.com/nota.ogg","voice":true}}},"document":{"summary":"document — by uploaded media_id","value":{"channel":"whatsapp","to":"+5491155555555","message":{"type":"document","media_id":"1234567890123456","filename":"factura-A-1042.pdf","caption":"Tu factura de marzo"}}},"sticker":{"summary":"sticker — WebP","value":{"channel":"whatsapp","to":"+5491155555555","message":{"type":"sticker","link":"https://cdn.example.com/gracias.webp"}}},"location":{"summary":"location — map pin (WhatsApp only)","value":{"channel":"whatsapp","to":"+5491155555555","message":{"type":"location","latitude":-33.4489,"longitude":-70.6693,"name":"Sucursal Centro","address":"Av. Libertador 1234, Santiago"}}},"contacts":{"summary":"contacts — share a vCard (WhatsApp only)","value":{"channel":"whatsapp","to":"+5491155555555","message":{"type":"contacts","contacts":[{"name":{"formatted_name":"Camila Rojas","first_name":"Camila","last_name":"Rojas"},"phones":[{"phone":"+56912345678","type":"WORK"}],"emails":[{"email":"camila@example.com","type":"WORK"}],"org":{"company":"Keebai","title":"Account Manager"}}]}}},"reaction":{"summary":"reaction — emoji on a previous message","description":"Send an empty `emoji` to clear a reaction.","value":{"channel":"whatsapp","to":"+5491155555555","message":{"type":"reaction","message_id":"wamid.HBgLNTQ5MTE1NTU1NTU1FQIAERgSN0EyRjc4","emoji":"👍"}}},"template":{"summary":"template — approved template (WhatsApp only)","description":"The only type that reaches a closed 24-hour window.","value":{"channel":"whatsapp","to":"+5491155555555","message":{"type":"template","name":"welcome_v2","language":"es","variables":{"nombre":"Juan","monto":"1500"}}}},"template_with_flow":{"summary":"template — with a Flow button","description":"Binds a Flow to one of the template FLOW buttons. `flow_token` is echoed back on the whatsapp.flow.response webhook.","value":{"channel":"whatsapp","to":"+5491155555555","message":{"type":"template","name":"encuesta_post_visita","language":"es","variables":{"nombre":"Juan"},"flow":{"flow_token":"csat-8f21c4","button_index":0,"flow_action_data":{"ticket_id":"A-1042"}}}}},"buttons":{"summary":"buttons — up to 3 quick replies","value":{"channel":"whatsapp","to":"+5491155555555","message":{"type":"buttons","body_text":"¿Confirmas tu reserva para el viernes a las 21:00?","buttons":[{"id":"confirm","title":"Confirmar"},{"id":"reschedule","title":"Reprogramar"},{"id":"cancel","title":"Cancelar"}],"header":{"type":"text","text":"Restaurante La Mela"},"footer_text":"Responde antes de las 18:00"}}},"list":{"summary":"list — tappable menu","value":{"channel":"whatsapp","to":"+5491155555555","message":{"type":"list","body_text":"Elige el horario que te acomode.","button_text":"Ver horarios","sections":[{"title":"Viernes 2","rows":[{"id":"fri-20","title":"20:00","description":"Mesa junto a la ventana"},{"id":"fri-21","title":"21:00","description":"Salón principal"}]},{"title":"Sábado 3","rows":[{"id":"sat-20","title":"20:00"}]}],"footer_text":"Restaurante La Mela"}}},"cta_url":{"summary":"cta_url — button that opens a link","value":{"channel":"whatsapp","to":"+5491155555555","message":{"type":"cta_url","body_text":"Dejaste productos en tu carrito. Retoma la compra cuando quieras.","display_text":"Ir al carrito","url":"https://tienda.example.com/checkout/abc123","footer_text":"El carrito expira en 24 horas"}}},"catalog":{"summary":"catalog — open the Meta catalog (WhatsApp only)","value":{"channel":"whatsapp","to":"+5491155555555","message":{"type":"catalog","body_text":"Mira nuestro catálogo de otoño.","thumbnail_product_retailer_id":"SKU-1042","footer_text":"Envíos a todo el país"}}},"carousel":{"summary":"carousel — media cards with their own buttons","description":"Meta rejects .webp images on carousel headers.","value":{"channel":"whatsapp","to":"+5491155555555","message":{"type":"carousel","body_text":"Novedades de la semana","cards":[{"header":{"type":"image","link":"https://cdn.example.com/producto-1.png"},"body_text":"Zapatillas running — 20% off","action":{"display_text":"Ver","url":"https://tienda.example.com/p/1"}},{"header":{"type":"image","link":"https://cdn.example.com/producto-2.png"},"body_text":"Mochila urbana — 15% off","action":{"display_text":"Ver","url":"https://tienda.example.com/p/2"}}]}}},"flow":{"summary":"flow — published WhatsApp Flow (WhatsApp only)","description":"Create and publish the Flow first with POST /v1/flows. Needs an open 24-hour window; outside it, attach the Flow to a template instead.","value":{"channel":"whatsapp","to":"+5491155555555","message":{"type":"flow","flow_id":"1234567890123456","flow_token":"reserva-8f21c4","flow_cta":"Reservar","body_text":"Reserva tu mesa en menos de un minuto.","header_text":"Restaurante La Mela","footer_text":"Cupos limitados","flow_action":"navigate","flow_action_payload":{"screen":"WELCOME","data":{"customer_name":"Juan"}}}}},"reply_to_message":{"summary":"text — quoting a previous message","description":"Any type accepts `context` to render as a quoted reply.","value":{"channel":"whatsapp","to":"+5491155555555","context":{"message_id":"wamid.HBgLNTQ5MTE1NTU1NTU1FQIAERgSN0EyRjc4"},"message":{"type":"text","body":"Sí, ese mismo pedido."}}},"instagram":{"summary":"text — on Instagram instead of WhatsApp","description":"The recipient is the Instagram-scoped id of the sender, not a phone number.","value":{"channel":"instagram","to":"17841400000000000","message":{"type":"text","body":"¡Gracias por escribirnos!"}}},"pick_channel_explicitly":{"summary":"text — picking one of several channels","description":"Needed only when the project has more than one active channel of that type.","value":{"channel":"whatsapp","to":"+5491155555555","channel_id":"665f1a2b3c4d5e6f70819234","meta_data":{"order_id":"A-1042"},"message":{"type":"text","body":"Hola Juan"}}}}}}},"responses":{"202":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SingleSendResponse"}}}}},"security":[{"PAT":[]}],"summary":"Send a message on any connected channel","tags":["messages"]}},"/v1/messages/mark-read":{"post":{"description":"WhatsApp Cloud API only.","operationId":"PublicMessagesController_markRead","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/MarkReadDto"}}}},"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/MarkReadResponse"}}}}},"security":[{"PAT":[]}],"summary":"Mark a received message as read (optionally show typing)","tags":["messages"]}},"/v1/messages/raw":{"post":{"description":"WhatsApp Cloud API only.","operationId":"PublicMessagesController_sendRaw","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SendRawDto"}}}},"responses":{"202":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SingleSendResponse"}}}}},"security":[{"PAT":[]}],"summary":"Escape hatch: forward a raw Meta Graph API body to /{phone_number_id}/messages","tags":["messages"]}},"/v1/messages/bulk":{"post":{"description":"WhatsApp Cloud API only. Runs as an asynchronous job.","operationId":"PublicMessagesController_sendBulk","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SendBulkDto"}}}},"responses":{"202":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/BulkDispatchResponse"}}}}},"security":[{"PAT":[]}],"summary":"Schedule a bulk template broadcast to many recipients","tags":["messages"]}},"/v1/messages/bulk/{broadcastId}":{"get":{"operationId":"PublicMessagesController_getBulkStatus","parameters":[{"name":"broadcastId","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/BulkStatusResponse"}}}}},"security":[{"PAT":[]}],"summary":"Status of a previously scheduled bulk broadcast","tags":["messages"]}},"/v1/media/upload":{"post":{"operationId":"PublicMediaController_uploadMedia","parameters":[],"requestBody":{"required":true,"content":{"multipart/form-data":{"schema":{"$ref":"#/components/schemas/UploadMediaDto"}}}},"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/MediaUploadResponse"}}}}},"security":[{"PAT":[]}],"summary":"Upload a media file to WhatsApp. Returns a media_id usable in send-{image,video,audio,document,sticker} endpoints.","tags":["media"]}},"/v1/media/{mediaId}":{"get":{"operationId":"PublicMediaController_getMedia","parameters":[{"name":"mediaId","required":true,"in":"path","schema":{"type":"string"}},{"name":"phone_number_id","required":true,"in":"query","schema":{"example":"100000000000001","type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/MediaMetadataResponse"}}}}},"security":[{"PAT":[]}],"summary":"Get WhatsApp media metadata","tags":["media"]},"delete":{"operationId":"PublicMediaController_deleteMedia","parameters":[{"name":"mediaId","required":true,"in":"path","schema":{"type":"string"}},{"name":"phone_number_id","required":true,"in":"query","schema":{"example":"100000000000001","type":"string"}}],"responses":{"204":{"description":""}},"security":[{"PAT":[]}],"summary":"Delete a previously uploaded WhatsApp media","tags":["media"]}},"/v1/media/{mediaId}/download":{"get":{"operationId":"PublicMediaController_downloadMedia","parameters":[{"name":"mediaId","required":true,"in":"path","schema":{"type":"string"}},{"name":"phone_number_id","required":true,"in":"query","schema":{"example":"100000000000001","type":"string"}}],"responses":{"200":{"description":"Contenido binario del media.","content":{"application/octet-stream":{"schema":{"type":"string","format":"binary"}}}}},"security":[{"PAT":[]}],"summary":"Download the binary contents of a WhatsApp media","tags":["media"]}},"/v1/flows":{"post":{"description":"Registers the Flow at Meta and uploads its Flow JSON. The Flow starts in draft: publish it before sending it to real recipients.","operationId":"PublicFlowsController_create","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateFlowDto"}}}},"responses":{"201":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/FlowResponseDto"}}}}},"security":[{"PAT":[]}],"summary":"Create a WhatsApp Flow","tags":["flows"]},"get":{"operationId":"PublicFlowsController_list","parameters":[{"name":"channel_id","required":false,"in":"query","description":"Keebai channel id. Optional when the tenant has exactly one active channel of the given type; required to disambiguate otherwise.","schema":{"example":"665f1a2b3c4d5e6f70819234","type":"string"}},{"name":"skip","required":false,"in":"query","schema":{"minimum":0,"default":0,"type":"number"}},{"name":"limit","required":false,"in":"query","schema":{"minimum":1,"maximum":200,"default":100,"type":"number"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/FlowListResponseDto"}}}}},"security":[{"PAT":[]}],"summary":"List the WhatsApp Flows of the project","tags":["flows"]}},"/v1/flows/{id}":{"get":{"operationId":"PublicFlowsController_getById","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/FlowResponseDto"}}}}},"security":[{"PAT":[]}],"summary":"Get a WhatsApp Flow by id","tags":["flows"]},"put":{"description":"Sending flow_data re-uploads the Flow JSON at Meta. A published Flow must be republished for the change to reach recipients.","operationId":"PublicFlowsController_update","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateFlowDto"}}}},"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/FlowResponseDto"}}}}},"security":[{"PAT":[]}],"summary":"Update a WhatsApp Flow","tags":["flows"]},"delete":{"description":"Meta only allows deleting Flows that are still in draft.","operationId":"PublicFlowsController_remove","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"204":{"description":""}},"security":[{"PAT":[]}],"summary":"Delete a WhatsApp Flow","tags":["flows"]}},"/v1/flows/{id}/publish":{"post":{"description":"Meta validates the Flow JSON on publish. A published Flow can no longer be edited — create a new version instead.","operationId":"PublicFlowsController_publish","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/FlowResponseDto"}}}}},"security":[{"PAT":[]}],"summary":"Publish a WhatsApp Flow","tags":["flows"]}},"/v1/templates":{"get":{"operationId":"PublicTemplatesController_list","parameters":[{"name":"page","required":false,"in":"query","schema":{"default":0,"type":"number"}},{"name":"limit","required":false,"in":"query","schema":{"maximum":100,"default":50,"type":"number"}},{"name":"status","required":false,"in":"query","schema":{"default":"APPROVED","type":"string","enum":["PENDING","IN_REVIEW","REJECTED","APPROVED","PAUSED","DISABLED","IN_APPEAL"]}},{"name":"channel_id","required":false,"in":"query","schema":{"type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PaginatedTemplatesResponse"}}}}},"security":[{"PAT":[]}],"summary":"Listar templates aprobados de la company","tags":["templates"]},"post":{"operationId":"PublicTemplatesController_create","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateTemplateDto"}}}},"responses":{"201":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PublicTemplateDto"}}}}},"security":[{"PAT":[]}],"summary":"Crear un template de WhatsApp y enviarlo a Meta para aprobación","tags":["templates"]}},"/v1/templates/{id}":{"patch":{"operationId":"PublicTemplatesController_update","parameters":[{"name":"id","required":true,"in":"path","description":"ObjectId del template","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateTemplateDto"}}}},"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PublicTemplateDto"}}}}},"security":[{"PAT":[]}],"summary":"Editar un template existente","tags":["templates"]}},"/v1/webhooks":{"post":{"description":"Devuelve el secret raw UNA SOLA VEZ. Guárdalo de inmediato — no se puede recuperar.","operationId":"PublicWebhooksController_create","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateWebhookDto"}}}},"responses":{"201":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/WebhookCreatedResponseDto"}}}}},"security":[{"PAT":[]}],"summary":"Crear una subscripción de webhook saliente","tags":["webhooks"]},"get":{"operationId":"PublicWebhooksController_list","parameters":[],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/WebhookListResponseDto"}}}}},"security":[{"PAT":[]}],"summary":"Listar subscripciones de webhooks de la company","tags":["webhooks"]}},"/v1/webhooks/{id}":{"get":{"operationId":"PublicWebhooksController_getById","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/WebhookResponseDto"}}}}},"security":[{"PAT":[]}],"summary":"Obtener una subscripción","tags":["webhooks"]},"patch":{"operationId":"PublicWebhooksController_update","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateWebhookDto"}}}},"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/WebhookResponseDto"}}}}},"security":[{"PAT":[]}],"summary":"Actualizar una subscripción","tags":["webhooks"]},"delete":{"operationId":"PublicWebhooksController_delete","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"204":{"description":""}},"security":[{"PAT":[]}],"summary":"Eliminar una subscripción","tags":["webhooks"]}},"/v1/webhooks/{id}/rotate-secret":{"post":{"operationId":"PublicWebhooksController_rotateSecret","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/WebhookCreatedResponseDto"}}}}},"security":[{"PAT":[]}],"summary":"Rotar el secret. El secret anterior queda inválido inmediatamente.","tags":["webhooks"]}},"/v1/webhooks/{id}/test":{"post":{"operationId":"PublicWebhooksController_test","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/TestWebhookDto"}}}},"responses":{"202":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/WebhookTestAcceptedResponseDto"}}}}},"security":[{"PAT":[]}],"summary":"Disparar un evento sintético hacia la URL configurada (para pruebas).","tags":["webhooks"]}},"/v1/webhooks/{id}/deliveries":{"get":{"operationId":"PublicWebhooksController_listDeliveries","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}},{"name":"limit","required":false,"in":"query","schema":{"maximum":200,"default":50,"type":"number"}},{"name":"cursor","required":false,"in":"query","description":"Cursor de paginación (delivery id).","schema":{"type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DeliveryListResponseDto"}}}}},"security":[{"PAT":[]}],"summary":"Historial de deliveries de la subscripción.","tags":["webhooks"]}},"/v1/channels":{"get":{"operationId":"PublicChannelsController_list","parameters":[{"name":"type","required":true,"in":"query","schema":{"type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PublicChannelListResponseDto"}}}}},"security":[{"PAT":[]}],"summary":"Listar canales activos de la company.","tags":["channels"]}},"/v1/channels/{id}":{"get":{"operationId":"PublicChannelsController_getById","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PublicChannelResponseDto"}}}}},"security":[{"PAT":[]}],"summary":"Obtener un canal por id.","tags":["channels"]}},"/v1/channels/whatsapp/connect":{"post":{"operationId":"PublicChannelsController_initiateWhatsappConnect","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/WhatsappConnectRequestDto"}}}},"responses":{"201":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PublicConnectSessionResponseDto"}}}}},"security":[{"PAT":[]}],"summary":"Inicia un flow de conexión de WhatsApp Business desde el CLI. Devuelve una URL del portal donde el usuario completa el embedded signup.","tags":["channels"]}},"/v1/channels/whatsapp/connect/{sessionId}":{"get":{"operationId":"PublicChannelsController_pollWhatsappConnect","parameters":[{"name":"sessionId","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PublicConnectSessionPollResponseDto"}}}}},"security":[{"PAT":[]}],"summary":"Polling: estado de la sesión de conexión. Cuando status=completed devuelve el canal creado.","tags":["channels"]}},"/v1/whatsapp/numbers":{"get":{"operationId":"PublicWhatsappNumbersController_list","parameters":[],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"type":"object"}}}}},"security":[{"PAT":[]}],"summary":"Lista los números de WhatsApp Business conectados a la company.","tags":["whatsapp"]}},"/v1/knowledge/tree":{"get":{"operationId":"PublicKnowledgeController_getTree","parameters":[],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/KnowledgeTreeResponseDto"}}}}},"security":[{"PAT":[]}],"summary":"Obtener el árbol completo de carpetas y documentos de la base de conocimientos.","tags":["knowledge"]}},"/v1/knowledge/folders":{"post":{"operationId":"PublicKnowledgeController_createFolder","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateFolderDto"}}}},"responses":{"201":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/KnowledgeNodeDto"}}}}},"security":[{"PAT":[]}],"summary":"Crear una carpeta en la base de conocimientos.","tags":["knowledge"]}},"/v1/knowledge/documents":{"post":{"operationId":"PublicKnowledgeController_createDocument","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateDocumentDto"}}}},"responses":{"201":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/KnowledgeNodeDto"}}}}},"security":[{"PAT":[]}],"summary":"Crear un documento desde markdown. El contenido se convierte a BlockNote y se reindexa para búsquedas.","tags":["knowledge"]}},"/v1/knowledge/nodes/{id}":{"delete":{"operationId":"PublicKnowledgeController_deleteNode","parameters":[{"name":"id","required":true,"in":"path","description":"ObjectId del nodo a eliminar.","schema":{"type":"string"}}],"responses":{"204":{"description":""}},"security":[{"PAT":[]}],"summary":"Eliminar un nodo (carpeta o documento). Si es carpeta, elimina sus descendientes.","tags":["knowledge"]}},"/v1/knowledge/search":{"post":{"operationId":"PublicKnowledgeController_search","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SearchKnowledgeDto"}}}},"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SearchKnowledgeResponseDto"}}}}},"security":[{"PAT":[]}],"summary":"Buscar en la base de conocimientos por full-text, vector o híbrido.","tags":["knowledge"]}},"/v1/knowledge/assignments":{"post":{"operationId":"PublicKnowledgeController_assign","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/AssignKnowledgeDto"}}}},"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AssignKnowledgeResponseDto"}}}}},"security":[{"PAT":[]}],"summary":"Asignar nodos de la base de conocimientos a todos los workers de un agente.","tags":["knowledge"]}},"/v1/contacts":{"get":{"description":"Devuelve los contactos de la company del token, del más reciente al más antiguo. El listado no filtra por project y siempre excluye los contactos fusionados y el canal playground.","operationId":"PublicContactsController_list","parameters":[{"name":"search","required":false,"in":"query","description":"Búsqueda full-text sobre nombre, apellido, usuario, teléfono y email.","schema":{"type":"string"}},{"name":"phone","required":false,"in":"query","description":"Filtrar por teléfono exacto","schema":{"type":"string"}},{"name":"channel_id","required":false,"in":"query","description":"ObjectId del canal","schema":{"type":"string"}},{"name":"channel_type","required":false,"in":"query","schema":{"type":"string","enum":["web","whatsapp","facebook","messenger","instagram","tiktok","telegram","email","phone"]}},{"name":"date_from","required":false,"in":"query","description":"Fecha ISO 8601. Filtra por última actividad del contacto.","schema":{"type":"string"}},{"name":"date_to","required":false,"in":"query","description":"Fecha ISO 8601","schema":{"type":"string"}},{"name":"limit","required":false,"in":"query","schema":{"minimum":1,"maximum":200,"default":50,"type":"number"}},{"name":"offset","required":false,"in":"query","schema":{"minimum":0,"default":0,"type":"number"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PublicContactListResponseDto"}}}}},"security":[{"PAT":[]}],"summary":"Listar contactos","tags":["contacts"]},"post":{"description":"La company y el project se toman del token; enviarlos en el body devuelve 400. Un contacto ya existente con el mismo user_id y canal devuelve 400.","operationId":"PublicContactsController_create","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/PublicContactCreateDto"}}}},"responses":{"201":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PublicContactEnvelopeDto"}}}}},"security":[{"PAT":[]}],"summary":"Crear un contacto","tags":["contacts"]}},"/v1/contacts/{id}":{"get":{"operationId":"PublicContactsController_get","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PublicContactEnvelopeDto"}}}}},"security":[{"PAT":[]}],"summary":"Obtener detalle de un contacto","tags":["contacts"]},"patch":{"description":"Actualización parcial. Enviar una cadena vacía no limpia el campo, y custom_fields se mergea con lo existente.","operationId":"PublicContactsController_update","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/PublicContactUpdateDto"}}}},"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PublicContactEnvelopeDto"}}}}},"security":[{"PAT":[]}],"summary":"Actualizar un contacto","tags":["contacts"]},"delete":{"description":"Borra el contacto y su historial de logs. Es permanente y no borra las conversaciones asociadas.","operationId":"PublicContactsController_remove","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"204":{"description":"Contacto eliminado"}},"security":[{"PAT":[]}],"summary":"Eliminar un contacto","tags":["contacts"]}},"/v1/crm/customers":{"get":{"description":"Devuelve los clientes de la company del token. El listado no filtra por project.","operationId":"PublicCustomersController_list","parameters":[{"name":"search","required":false,"in":"query","description":"Búsqueda libre por nombre o email","schema":{"type":"string"}},{"name":"phone","required":false,"in":"query","description":"Filtrar por teléfono exacto","schema":{"type":"string"}},{"name":"limit","required":false,"in":"query","schema":{"minimum":1,"maximum":200,"default":50,"type":"number"}},{"name":"offset","required":false,"in":"query","schema":{"minimum":0,"default":0,"type":"number"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PublicCustomerListResponseDto"}}}}},"security":[{"PAT":[]}],"summary":"Listar clientes","tags":["crm-customers"]},"post":{"description":"La company y el project se toman del token; enviarlos en el body devuelve 400.","operationId":"PublicCustomersController_create","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/PublicCustomerCreateDto"}}}},"responses":{"201":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PublicCustomerEnvelopeDto"}}}}},"security":[{"PAT":[]}],"summary":"Crear un cliente","tags":["crm-customers"]}},"/v1/crm/customers/{id}":{"get":{"operationId":"PublicCustomersController_get","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PublicCustomerEnvelopeDto"}}}}},"security":[{"PAT":[]}],"summary":"Obtener detalle de un cliente","tags":["crm-customers"]},"patch":{"operationId":"PublicCustomersController_update","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/PublicCustomerUpdateDto"}}}},"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PublicCustomerEnvelopeDto"}}}}},"security":[{"PAT":[]}],"summary":"Actualizar un cliente","tags":["crm-customers"]},"delete":{"operationId":"PublicCustomersController_remove","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"204":{"description":"Cliente eliminado"}},"security":[{"PAT":[]}],"summary":"Eliminar un cliente","tags":["crm-customers"]}},"/v1/crm/tickets":{"get":{"description":"Devuelve los tickets de la company del token. El listado no filtra por project.","operationId":"PublicTicketsController_list","parameters":[{"name":"keyword","required":false,"in":"query","description":"Búsqueda libre sobre el ticket","schema":{"type":"string"}},{"name":"pipeline_id","required":false,"in":"query","description":"Filtrar por pipeline","schema":{"type":"string"}},{"name":"stage_ids","required":false,"in":"query","description":"Ids de etapa separados por coma","schema":{"type":"string"}},{"name":"tag_ids","required":false,"in":"query","description":"Ids de tag separados por coma","schema":{"type":"string"}},{"name":"chat_user_id","required":false,"in":"query","description":"Filtrar por chat user (contacto)","schema":{"type":"string"}},{"name":"assigned_to","required":false,"in":"query","description":"Filtrar por usuario asignado","schema":{"type":"string"}},{"name":"categories","required":false,"in":"query","description":"Categorías separadas por coma","schema":{"type":"string"}},{"name":"channel_ids","required":false,"in":"query","description":"Ids de canal separados por coma","schema":{"type":"string"}},{"name":"completed","required":false,"in":"query","description":"'true' devuelve sólo cerrados, 'false' sólo abiertos","schema":{"type":"string"}},{"name":"date_from","required":false,"in":"query","description":"Fecha de creación desde (YYYY-MM-DD)","schema":{"type":"string"}},{"name":"date_to","required":false,"in":"query","description":"Fecha de creación hasta (YYYY-MM-DD)","schema":{"type":"string"}},{"name":"limit","required":false,"in":"query","schema":{"minimum":1,"maximum":200,"default":50,"type":"number"}},{"name":"offset","required":false,"in":"query","schema":{"minimum":0,"default":0,"type":"number"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PublicTicketListResponseDto"}}}}},"security":[{"PAT":[]}],"summary":"Listar tickets","tags":["crm-tickets"]},"post":{"description":"La company y el project se toman del token; enviarlos en el body devuelve 400.","operationId":"PublicTicketsController_create","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/PublicTicketCreateDto"}}}},"responses":{"201":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PublicTicketEnvelopeDto"}}}}},"security":[{"PAT":[]}],"summary":"Crear un ticket","tags":["crm-tickets"]}},"/v1/crm/tickets/{id}":{"get":{"operationId":"PublicTicketsController_get","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PublicTicketEnvelopeDto"}}}}},"security":[{"PAT":[]}],"summary":"Obtener detalle de un ticket","tags":["crm-tickets"]},"patch":{"operationId":"PublicTicketsController_update","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/PublicTicketUpdateDto"}}}},"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PublicTicketUpdateResponseDto"}}}}},"security":[{"PAT":[]}],"summary":"Actualizar un ticket","tags":["crm-tickets"]},"delete":{"operationId":"PublicTicketsController_remove","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"204":{"description":"Ticket eliminado"}},"security":[{"PAT":[]}],"summary":"Eliminar un ticket","tags":["crm-tickets"]}},"/v1/crm/tickets/{id}/stage":{"post":{"description":"Mueve el ticket a la etapa indicada dentro de su pipeline y devuelve el estado resultante.","operationId":"PublicTicketsController_moveStage","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/PublicTicketStageDto"}}}},"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PublicTicketStageChangeResponseDto"}}}}},"security":[{"PAT":[]}],"summary":"Mover un ticket de etapa","tags":["crm-tickets"]}},"/v1/crm/tasks":{"get":{"description":"Devuelve las tareas de la company del token.","operationId":"PublicTasksController_list","parameters":[{"name":"status","required":false,"in":"query","description":"Filtrar por estado exacto","schema":{"type":"string"}},{"name":"limit","required":false,"in":"query","schema":{"minimum":1,"maximum":200,"default":50,"type":"number"}},{"name":"offset","required":false,"in":"query","schema":{"minimum":0,"default":0,"type":"number"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PublicTaskListResponseDto"}}}}},"security":[{"PAT":[]}],"summary":"Listar tareas","tags":["crm-tasks"]},"post":{"description":"La company se toma del token; enviarla en el body devuelve 400.","operationId":"PublicTasksController_create","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/PublicTaskCreateDto"}}}},"responses":{"201":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PublicTaskEnvelopeDto"}}}}},"security":[{"PAT":[]}],"summary":"Crear una tarea","tags":["crm-tasks"]}},"/v1/crm/tasks/{id}":{"get":{"operationId":"PublicTasksController_get","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PublicTaskEnvelopeDto"}}}}},"security":[{"PAT":[]}],"summary":"Obtener detalle de una tarea","tags":["crm-tasks"]},"patch":{"operationId":"PublicTasksController_update","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/PublicTaskUpdateDto"}}}},"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PublicTaskEnvelopeDto"}}}}},"security":[{"PAT":[]}],"summary":"Actualizar una tarea","tags":["crm-tasks"]},"delete":{"operationId":"PublicTasksController_remove","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"204":{"description":"Tarea eliminada"}},"security":[{"PAT":[]}],"summary":"Eliminar una tarea","tags":["crm-tasks"]}},"/v1/crm/notes":{"get":{"description":"Devuelve las notas de la company del token.","operationId":"PublicNotesController_list","parameters":[{"name":"chat_user","required":false,"in":"query","description":"Filtrar por chat user (contacto)","schema":{"type":"string"}},{"name":"ticket_id","required":false,"in":"query","description":"Filtrar por ticket","schema":{"type":"string"}},{"name":"type","required":false,"in":"query","schema":{"type":"string","enum":["note","call","email","meeting"]}},{"name":"limit","required":false,"in":"query","schema":{"minimum":1,"maximum":200,"default":50,"type":"number"}},{"name":"offset","required":false,"in":"query","schema":{"minimum":0,"default":0,"type":"number"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PublicNoteListResponseDto"}}}}},"security":[{"PAT":[]}],"summary":"Listar notas","tags":["crm-notes"]},"post":{"description":"La company, el project y el autor se toman del token; enviarlos en el body devuelve 400.","operationId":"PublicNotesController_create","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/PublicNoteCreateDto"}}}},"responses":{"201":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PublicNoteEnvelopeDto"}}}}},"security":[{"PAT":[]}],"summary":"Crear una nota","tags":["crm-notes"]}},"/v1/crm/notes/{id}":{"get":{"operationId":"PublicNotesController_get","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PublicNoteEnvelopeDto"}}}}},"security":[{"PAT":[]}],"summary":"Obtener detalle de una nota","tags":["crm-notes"]},"patch":{"operationId":"PublicNotesController_update","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/PublicNoteUpdateDto"}}}},"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PublicNoteEnvelopeDto"}}}}},"security":[{"PAT":[]}],"summary":"Actualizar una nota","tags":["crm-notes"]},"delete":{"operationId":"PublicNotesController_remove","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"204":{"description":"Nota eliminada"}},"security":[{"PAT":[]}],"summary":"Eliminar una nota","tags":["crm-notes"]}},"/v1/webhook/events":{"post":{"description":"Registra un evento sobre el ticket abierto del contacto; si no tiene uno, se abre. Los campos asociados al tipo de evento validan `data` y sus valores se escriben en el ticket y en la ficha del contacto. La company y el project se toman del token; enviarlos en el body devuelve 400.","operationId":"PublicWebhookEventsController_ingest","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/PublicWebhookEventCreateDto"}}}},"responses":{"202":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PublicEventEnvelopeDto"}}}},"422":{"description":"El evento no se registró: contacto inexistente, tipo de evento desconocido o `data` inválido."}},"security":[{"PAT":[]}],"summary":"Emitir un evento del CRM","tags":["webhook-ingest"]}},"/v1/ecommerce/products":{"get":{"description":"Devuelve los productos de la company del token, ordenados por nombre. Incluye tanto los cargados en Keebai como los sincronizados desde una integración.","operationId":"PublicEcommerceController_listProducts","parameters":[{"name":"limit","required":false,"in":"query","schema":{"minimum":1,"maximum":200,"default":50,"type":"number"}},{"name":"offset","required":false,"in":"query","schema":{"minimum":0,"default":0,"type":"number"}},{"name":"search","required":false,"in":"query","description":"Búsqueda full-text sobre el catálogo","schema":{"type":"string"}},{"name":"type","required":false,"in":"query","description":"Origen del producto: interno o el de una integración","schema":{"type":"string"}},{"name":"category","required":false,"in":"query","description":"ObjectId de la categoría","schema":{"type":"string"}},{"name":"available","required":false,"in":"query","description":"true: solo productos activos con stock disponible","schema":{"type":"string","enum":["true","false"]}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PublicProductListResponseDto"}}}}},"security":[{"PAT":[]}],"summary":"Listar productos del catálogo","tags":["ecommerce"]}},"/v1/ecommerce/products/{id}":{"get":{"operationId":"PublicEcommerceController_getProduct","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PublicProductEnvelopeDto"}}}}},"security":[{"PAT":[]}],"summary":"Obtener detalle de un producto","tags":["ecommerce"]}},"/v1/ecommerce/carts":{"get":{"description":"Devuelve los carritos de la company, incluidos los abandonados. Filtrable por origen, integración y estado de recuperación.","operationId":"PublicEcommerceController_listCarts","parameters":[{"name":"limit","required":false,"in":"query","schema":{"minimum":1,"maximum":200,"default":50,"type":"number"}},{"name":"offset","required":false,"in":"query","schema":{"minimum":0,"default":0,"type":"number"}},{"name":"source","required":false,"in":"query","description":"Origen del carrito","schema":{"type":"string"}},{"name":"integration_id","required":false,"in":"query","description":"ObjectId de la integración de origen","schema":{"type":"string"}},{"name":"recovery_status","required":false,"in":"query","description":"Estado de recuperación del carrito abandonado","schema":{"type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PublicCartListResponseDto"}}}}},"security":[{"PAT":[]}],"summary":"Listar carritos","tags":["ecommerce"]}},"/v1/ecommerce/carts/{id}":{"get":{"operationId":"PublicEcommerceController_getCart","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PublicCartEnvelopeDto"}}}}},"security":[{"PAT":[]}],"summary":"Obtener detalle de un carrito","tags":["ecommerce"]}},"/v1/ecommerce/carts/abandoned":{"post":{"description":"Registra un checkout que el cliente dejó sin completar para que el agente lo retome. El carrito se identifica por `external_id` dentro de la tienda conectada: reenviar el mismo identificador actualiza el carrito en vez de duplicarlo.","operationId":"PublicEcommerceController_ingestAbandonedCart","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/PublicAbandonedCartDto"}}}},"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PublicAbandonedCartAckDto"}}}}},"security":[{"PAT":[]}],"summary":"Registrar un carrito abandonado","tags":["ecommerce"]}},"/v1/ecommerce/sales":{"get":{"description":"Devuelve las ventas de la company, filtrables por estado, estado de pago, contacto y rango de fechas.","operationId":"PublicEcommerceController_listSales","parameters":[{"name":"limit","required":false,"in":"query","schema":{"minimum":1,"maximum":200,"default":50,"type":"number"}},{"name":"offset","required":false,"in":"query","schema":{"minimum":0,"default":0,"type":"number"}},{"name":"status","required":false,"in":"query","schema":{"type":"string","enum":["completed","cancelled","refunded"]}},{"name":"payment_status","required":false,"in":"query","schema":{"type":"string","enum":["pending","paid","partially_paid","refunded"]}},{"name":"chat_user_id","required":false,"in":"query","description":"Filtrar por contacto","schema":{"type":"string"}},{"name":"from","required":false,"in":"query","description":"Fecha ISO 8601, inclusive","schema":{"type":"string"}},{"name":"to","required":false,"in":"query","description":"Fecha ISO 8601, inclusive","schema":{"type":"string"}},{"name":"search","required":false,"in":"query","description":"Búsqueda libre sobre la venta","schema":{"type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PublicSaleListResponseDto"}}}}},"security":[{"PAT":[]}],"summary":"Listar ventas","tags":["ecommerce"]}},"/v1/ecommerce/sales/{id}":{"get":{"operationId":"PublicEcommerceController_getSale","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PublicSaleEnvelopeDto"}}}}},"security":[{"PAT":[]}],"summary":"Obtener detalle de una venta","tags":["ecommerce"]}},"/v1/loyalty/programs":{"get":{"description":"Devuelve los programas de la company del token, del más nuevo al más viejo. El campo rules solo trae poblada la variante que corresponde al type del programa.","operationId":"PublicLoyaltyController_listPrograms","parameters":[{"name":"limit","required":false,"in":"query","schema":{"minimum":1,"maximum":200,"default":50,"type":"number"}},{"name":"offset","required":false,"in":"query","schema":{"minimum":0,"default":0,"type":"number"}},{"name":"status","required":false,"in":"query","schema":{"type":"string","enum":["draft","active","archived"]}},{"name":"type","required":false,"in":"query","schema":{"type":"string","enum":["points","stamps","tiers"]}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PublicProgramListResponseDto"}}}}},"security":[{"PAT":[]}],"summary":"Listar programas de fidelidad","tags":["loyalty"]}},"/v1/loyalty/programs/{id}":{"get":{"operationId":"PublicLoyaltyController_getProgram","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PublicProgramEnvelopeDto"}}}}},"security":[{"PAT":[]}],"summary":"Obtener un programa de fidelidad","tags":["loyalty"]}},"/v1/loyalty/templates":{"get":{"description":"Devuelve los templates del programa indicado, de la versión más nueva a la más vieja. El diseño de la tarjeta se edita desde el portal; acá es de solo lectura.","operationId":"PublicLoyaltyController_listTemplates","parameters":[{"name":"program_id","required":true,"in":"query","description":"ObjectId del programa cuyos templates se listan. Los templates siempre se consultan por programa","schema":{"type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PublicTemplateListResponseDto"}}}}},"security":[{"PAT":[]}],"summary":"Listar templates de wallet de un programa","tags":["loyalty"]}},"/v1/loyalty/templates/{id}":{"get":{"operationId":"PublicLoyaltyController_getTemplate","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PublicTemplateEnvelopeDto"}}}}},"security":[{"PAT":[]}],"summary":"Obtener un template de wallet","tags":["loyalty"]}},"/v1/loyalty/memberships":{"get":{"description":"Devuelve las membresías de la company, filtrables por programa, cliente, teléfono, nombre o estado. El saldo de puntos puede leerse 0 si el programa vence puntos y ya pasó el plazo.","operationId":"PublicLoyaltyController_listMemberships","parameters":[{"name":"limit","required":false,"in":"query","schema":{"minimum":1,"maximum":200,"default":50,"type":"number"}},{"name":"offset","required":false,"in":"query","schema":{"minimum":0,"default":0,"type":"number"}},{"name":"program_id","required":false,"in":"query","description":"ObjectId del programa","schema":{"type":"string"}},{"name":"customer_id","required":false,"in":"query","description":"Identificador del cliente elegido por el integrador al inscribir","schema":{"type":"string"}},{"name":"phone","required":false,"in":"query","description":"Teléfono del cliente. Busca por subsecuencia de dígitos, así que +56 9 1234 5678 matchea con 912345678","schema":{"type":"string"}},{"name":"name","required":false,"in":"query","description":"Búsqueda parcial por nombre","schema":{"type":"string"}},{"name":"status","required":false,"in":"query","schema":{"type":"string","enum":["active","suspended","revoked"]}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PublicMembershipListResponseDto"}}}}},"security":[{"PAT":[]}],"summary":"Listar membresías","tags":["loyalty"]},"post":{"description":"Crea la membresía y le asigna un serial. Toda membresía queda ligada a un cliente del CRM: envía el id de uno existente, o el nombre más teléfono o correo y se busca o se crea. Inscribir dos veces al mismo cliente en el mismo programa devuelve 409.","operationId":"PublicLoyaltyController_enrollMembership","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/PublicMembershipEnrollDto"}}}},"responses":{"201":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PublicMembershipEnvelopeDto"}}}}},"security":[{"PAT":[]}],"summary":"Inscribir un cliente en un programa","tags":["loyalty"]}},"/v1/loyalty/memberships/{id}":{"get":{"operationId":"PublicLoyaltyController_getMembership","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PublicMembershipEnvelopeDto"}}}}},"security":[{"PAT":[]}],"summary":"Obtener una membresía","tags":["loyalty"]}},"/v1/loyalty/memberships/{id}/ledger":{"get":{"description":"Historial de acumulaciones, canjes y ajustes, del más nuevo al más viejo. Cada entrada guarda el saldo resultante en balance_after.","operationId":"PublicLoyaltyController_listLedger","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}},{"name":"limit","required":false,"in":"query","schema":{"minimum":1,"maximum":200,"default":50,"type":"number"}},{"name":"offset","required":false,"in":"query","schema":{"minimum":0,"default":0,"type":"number"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PublicLedgerListResponseDto"}}}}},"security":[{"PAT":[]}],"summary":"Listar los movimientos de una membresía","tags":["loyalty"]},"post":{"description":"Acumula, canjea o ajusta el saldo, y actualiza el pase en la wallet del cliente. La métrica la decide el tipo del programa, no el request. El saldo nunca baja de cero.","operationId":"PublicLoyaltyController_recordLedgerEntry","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/PublicLedgerRecordDto"}}}},"responses":{"201":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PublicLedgerEntryEnvelopeDto"}}}}},"security":[{"PAT":[]}],"summary":"Registrar un movimiento de puntos o sellos","tags":["loyalty"]}},"/v1/loyalty/memberships/{id}/passes/google":{"post":{"description":"Devuelve el link para agregar la tarjeta a Google Wallet. Llamarlo de nuevo sobre la misma membresía reutiliza el pase existente.","operationId":"PublicLoyaltyController_issueGooglePass","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"201":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PublicGooglePassDto"}}}}},"security":[{"PAT":[]}],"summary":"Emitir el pase de Google Wallet","tags":["loyalty"]}},"/v1/loyalty/memberships/{id}/passes/apple/link":{"post":{"description":"Devuelve un link público de descarga del .pkpass, apto para QR o para mandar por WhatsApp. Requiere que las credenciales de Apple Wallet estén cargadas; si no, responde 400.","operationId":"PublicLoyaltyController_issueApplePassLink","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"201":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PublicApplePassLinkDto"}}}}},"security":[{"PAT":[]}],"summary":"Emitir el link de descarga del pase de Apple Wallet","tags":["loyalty"]}},"/v1/loyalty/memberships/{id}/passes/notify":{"post":{"description":"Manda un push a los dispositivos que tienen el pase agregado. Las membresías sin pase registrado cuentan como skipped, no como error.","operationId":"PublicLoyaltyController_notifyPass","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/PublicPassNotifyDto"}}}},"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PublicPassNotifyResultDto"}}}}},"security":[{"PAT":[]}],"summary":"Notificar al cliente en su wallet","tags":["loyalty"]}},"/v1/loyalty/memberships/{id}/passes/notifications":{"get":{"description":"Historial de los mensajes mandados a la wallet, del más nuevo al más viejo, con a cuántos dispositivos llegó cada uno.","operationId":"PublicLoyaltyController_listPassNotifications","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PublicPassNotificationListResponseDto"}}}}},"security":[{"PAT":[]}],"summary":"Listar las notificaciones enviadas a una membresía","tags":["loyalty"]}},"/v1/agents":{"get":{"operationId":"PublicAgentsController_list","parameters":[{"name":"q","required":false,"in":"query","description":"Filtro por nombre (búsqueda parcial, case-insensitive).","schema":{"type":"string"}},{"name":"page","required":false,"in":"query","schema":{"minimum":1,"default":1,"type":"number"}},{"name":"limit","required":false,"in":"query","schema":{"minimum":1,"maximum":100,"default":25,"type":"number"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PaginatedAgentsResponse"}}}}},"security":[{"PAT":[]}],"summary":"Listar y buscar agentes activos de la company.","tags":["agents"]},"post":{"description":"El agente nace con un bloque de personalidad y uno de politica de respuesta ya adjuntos y vacios, porque sin ellos no responde nada util. Un modelo no soportado devuelve 400 INVALID_MODEL.","operationId":"PublicAgentsController_create","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/PublicAgentCreateDto"}}}},"responses":{"201":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PublicAgentEnvelopeDto"}}}}},"security":[{"PAT":[]}],"summary":"Crear un agente","tags":["agents"]}},"/v1/agents/prompt-types":{"get":{"description":"La fuente de verdad de los valores validos de `section`, `goal.type` y `channels`. Sale de la plataforma y no de una lista fija de esta API, asi que una seccion nueva aparece aca sin que haya que publicar una version. Cada fila trae ademas `tip`, que dice como se escribe esa seccion.","operationId":"PublicAgentsController_listPromptTypes","parameters":[{"name":"kind","required":false,"in":"query","description":"Familia del catalogo. Sin esto vuelven todas: secciones, objetivos y canales.","schema":{"type":"string","enum":["section","goal","channel"]}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PublicPromptTypeListResponseDto"}}}}},"security":[{"PAT":[]}],"summary":"El catalogo: que secciones, objetivos y canales existen","tags":["agents"]}},"/v1/agents/{id}":{"get":{"description":"Devuelve el agente con su modelo, sus nodos de conocimiento y las referencias ordenadas a los bloques que arman su prompt. Las referencias solo traen ids: la metadata de cada bloque se lee en GET /v1/agents/{id}/blocks.","operationId":"PublicAgentsController_get","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PublicAgentEnvelopeDto"}}}}},"security":[{"PAT":[]}],"summary":"Obtener un agente","tags":["agents"]},"patch":{"description":"Actualiza solo los campos presentes en el body. Los bloques no se tocan por aca: se manejan con los endpoints de /blocks.","operationId":"PublicAgentsController_update","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/PublicAgentUpdateDto"}}}},"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PublicAgentEnvelopeDto"}}}}},"security":[{"PAT":[]}],"summary":"Actualizar un agente","tags":["agents"]},"delete":{"description":"Borra el agente de forma permanente. Sus bloques sobreviven y quedan en el catalogo: esto desarma el cableado, no limpia lo que habia detras.","operationId":"PublicAgentsController_remove","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"204":{"description":""}},"security":[{"PAT":[]}],"summary":"Eliminar un agente","tags":["agents"]}},"/v1/agents/{id}/tools":{"put":{"description":"Fija la lista completa. Un id que no exista en la company devuelve 404 AGENT_TOOL_NOT_FOUND: guardarlo seria un 200 sin efecto, porque el agente ignora una herramienta que no encuentra.","operationId":"PublicAgentsController_setTools","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/PublicAgentToolsDto"}}}},"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PublicAgentEnvelopeDto"}}}}},"security":[{"PAT":[]}],"summary":"Reemplazar las herramientas del agente","tags":["agents"]}},"/v1/agents/{id}/tools/{toolId}":{"post":{"description":"Agrega una sin tocar el resto. Es idempotente: si ya la tenia, no pasa nada. Existe para no obligarte a leer, mezclar y reescribir la lista entera, que es como dos clientes simultaneos pierden un cambio.","operationId":"PublicAgentsController_attachTool","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}},{"name":"toolId","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PublicAgentEnvelopeDto"}}}}},"security":[{"PAT":[]}],"summary":"Darle una herramienta al agente","tags":["agents"]},"delete":{"description":"La herramienta sigue existiendo en la company: esto la desasigna, no la borra.","operationId":"PublicAgentsController_detachTool","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}},{"name":"toolId","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PublicAgentEnvelopeDto"}}}}},"security":[{"PAT":[]}],"summary":"Quitarle una herramienta al agente","tags":["agents"]}},"/v1/agents/{id}/knowledge":{"put":{"description":"Fija la lista completa de nodos que puede consultar.","operationId":"PublicAgentsController_setKnowledge","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/PublicAgentKnowledgeDto"}}}},"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PublicAgentEnvelopeDto"}}}}},"security":[{"PAT":[]}],"summary":"Reemplazar el conocimiento del agente","tags":["agents"]}},"/v1/agents/{id}/knowledge/{nodeId}":{"post":{"description":"Agrega uno sin tocar el resto. Idempotente.","operationId":"PublicAgentsController_attachKnowledge","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}},{"name":"nodeId","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PublicAgentEnvelopeDto"}}}}},"security":[{"PAT":[]}],"summary":"Sumarle un nodo de conocimiento","tags":["agents"]},"delete":{"description":"El nodo sigue en la base de conocimiento; esto lo desasigna.","operationId":"PublicAgentsController_detachKnowledge","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}},{"name":"nodeId","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PublicAgentEnvelopeDto"}}}}},"security":[{"PAT":[]}],"summary":"Sacarle un nodo de conocimiento","tags":["agents"]}},"/v1/agents/{id}/channels":{"put":{"description":"Fija la lista completa. Habilitar un canal en el agente NO lo conecta: la cuenta tiene que estar conectada a la company aparte, y sin las dos mitades no llega ningun mensaje.","operationId":"PublicAgentsController_setChannels","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/PublicAgentChannelsDto"}}}},"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PublicAgentEnvelopeDto"}}}}},"security":[{"PAT":[]}],"summary":"Reemplazar los canales del agente","tags":["agents"]}},"/v1/agents/{id}/channels/{channelType}":{"post":{"description":"Agrega uno sin tocar el resto. Idempotente. Un tipo que no este en el catalogo devuelve 404 CHANNEL_TYPE_NOT_FOUND.","operationId":"PublicAgentsController_attachChannel","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}},{"name":"channelType","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PublicAgentEnvelopeDto"}}}}},"security":[{"PAT":[]}],"summary":"Habilitar un canal en el agente","tags":["agents"]},"delete":{"description":"El agente deja de responder ahi, y un cliente que escriba por ese canal no recibe nada.","operationId":"PublicAgentsController_detachChannel","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}},{"name":"channelType","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PublicAgentEnvelopeDto"}}}}},"security":[{"PAT":[]}],"summary":"Deshabilitar un canal en el agente","tags":["agents"]}},"/v1/agents/{id}/reengagement":{"put":{"description":"Cada cuanto vuelve el agente sobre una conversacion que se enfrio. `max_attempts: 0` lo apaga. El motor solo garantiza el latido —cuando despertarlo y cuantas veces—: QUE hacer en cada intento lo decide el agente en ese turno, con la conversacion a la vista.","operationId":"PublicAgentsController_setReengagement","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/PublicReengagementDto"}}}},"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PublicAgentEnvelopeDto"}}}}},"security":[{"PAT":[]}],"summary":"Configurar el reenganche","tags":["agents"]}},"/v1/agents/{id}/query":{"post":{"description":"Corre un turno como si fueras un cliente. SIEMPRE en modo prueba: las herramientas que escriben —agendar, cobrar, abrir un ticket— se simulan y no tocan nada real, y la conversacion no queda en el historial del negocio. La respuesta dice cuales se llamaron y cuales se simularon. Para conversaciones reales con clientes estan los canales, no esta ruta.","operationId":"PublicAgentsController_query","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/PublicAgentQueryDto"}}}},"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PublicAgentQueryResponseDto"}}}}},"security":[{"PAT":[]}],"summary":"Escribirle al agente y ver que responde","tags":["agents"]}},"/v1/agents/{id}/prompts":{"get":{"description":"Las secciones escritas por el negocio: quien es, que no hace, cuando deriva, sus ejemplos. Que secciones existen y que va en cada una lo dice `GET /v1/prompt-types?kind=section`.","operationId":"PublicAgentsController_listPrompts","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PublicPromptListResponseDto"}}}}},"security":[{"PAT":[]}],"summary":"Listar las secciones del prompt de un agente","tags":["agents"]}},"/v1/agents/{id}/prompts/{section}":{"put":{"description":"Reemplaza el texto de ESA seccion y deja el resto como estaba. La crea si no existia. Cada guardado deja una version nueva en el historial. Una seccion que no este en el catalogo devuelve 404 PROMPT_SECTION_NOT_FOUND: guardarla igual seria un 200 sin ningun efecto en el agente.","operationId":"PublicAgentsController_setPrompt","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}},{"name":"section","required":true,"in":"path","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/PublicPromptWriteDto"}}}},"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PublicAgentEnvelopeDto"}}}}},"security":[{"PAT":[]}],"summary":"Escribir una seccion del prompt","tags":["agents"]},"delete":{"description":"Saca la seccion del prompt del agente. Su historial de versiones queda.","operationId":"PublicAgentsController_removePrompt","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}},{"name":"section","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PublicAgentEnvelopeDto"}}}}},"security":[{"PAT":[]}],"summary":"Borrar una seccion del prompt","tags":["agents"]}},"/v1/agents/{id}/prompts/{section}/versions":{"get":{"description":"Las versiones de esa seccion, de la mas nueva a la mas vieja. Se escribe una en cada guardado que cambia el texto: guardar sin cambiar nada no infla el historial.","operationId":"PublicAgentsController_listPromptVersions","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}},{"name":"section","required":true,"in":"path","schema":{"type":"string"}},{"name":"limit","required":false,"in":"query","schema":{"minimum":1,"maximum":200,"default":50,"type":"number"}},{"name":"offset","required":false,"in":"query","schema":{"minimum":0,"default":0,"type":"number"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PublicPromptVersionListResponseDto"}}}}},"security":[{"PAT":[]}],"summary":"Historial de una seccion","tags":["agents"]}},"/v1/agents/{id}/prompts/{section}/versions/{versionId}":{"get":{"operationId":"PublicAgentsController_getPromptVersion","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}},{"name":"section","required":true,"in":"path","schema":{"type":"string"}},{"name":"versionId","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PublicPromptVersionDto"}}}}},"security":[{"PAT":[]}],"summary":"Leer una version de una seccion","tags":["agents"]}},"/v1/agents/{id}/prompts/{section}/versions/{versionId}/restore":{"post":{"description":"Deja el texto de esa version como el vigente. No muta el historial: crea una version nueva que copia la vieja y anota de cual salio, asi que restaurar tambien se puede deshacer.","operationId":"PublicAgentsController_restorePromptVersion","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}},{"name":"section","required":true,"in":"path","schema":{"type":"string"}},{"name":"versionId","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"201":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PublicPromptVersionDto"}}}}},"security":[{"PAT":[]}],"summary":"Restaurar una version","tags":["agents"]}},"/v1/tools":{"get":{"description":"Devuelve las funciones de webhook de la company. Las funciones son de company, no de proyecto. Los valores de headers y de query string vuelven enmascarados; las claves se ven.","operationId":"PublicToolsController_list","parameters":[{"name":"limit","required":false,"in":"query","schema":{"minimum":1,"maximum":200,"default":50,"type":"number"}},{"name":"offset","required":false,"in":"query","schema":{"minimum":0,"default":0,"type":"number"}},{"name":"active_only","required":false,"in":"query","description":"Devuelve solo las funciones activas.","schema":{"default":false,"type":"boolean"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PublicToolListResponseDto"}}}}},"security":[{"PAT":[]}],"summary":"Listar funciones de webhook","tags":["tools"]},"post":{"description":"Crea una funcion que el agente puede llamar. La URL tiene que ser https publica: se rechazan loopback, rangos privados, hosts internos del cluster y placeholders en el host.","operationId":"PublicToolsController_create","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/PublicToolCreateDto"}}}},"responses":{"201":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PublicToolEnvelopeDto"}}}}},"security":[{"PAT":[]}],"summary":"Crear una funcion de webhook","tags":["tools"]}},"/v1/tools/{id}":{"get":{"description":"Los valores secretos de headers y query vuelven enmascarados como ***; las claves si se ven.","operationId":"PublicToolsController_get","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PublicToolEnvelopeDto"}}}}},"security":[{"PAT":[]}],"summary":"Obtener una funcion de webhook","tags":["tools"]},"put":{"description":"Actualiza solo los campos presentes. Dentro de context, omitir headers o params preserva los guardados y mandarlos los reemplaza enteros. Devolver el '***' de una lectura da 400 en vez de pisar la credencial.","operationId":"PublicToolsController_update","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/PublicToolUpdateDto"}}}},"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PublicToolEnvelopeDto"}}}}},"security":[{"PAT":[]}],"summary":"Actualizar una funcion de webhook","tags":["tools"]},"delete":{"description":"Falla con 409 AGENT_TOOL_IN_USE mientras algun agente todavia la tenga asignada, y el error dice cual.","operationId":"PublicToolsController_remove","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"204":{"description":""}},"security":[{"PAT":[]}],"summary":"Eliminar una funcion de webhook","tags":["tools"]}},"/v1/scheduling/branches":{"get":{"operationId":"PublicBranchesController_list","parameters":[{"name":"search","required":false,"in":"query","description":"Búsqueda libre por nombre","schema":{"type":"string"}},{"name":"skip","required":false,"in":"query","schema":{"minimum":0,"default":0,"type":"number"}},{"name":"limit","required":false,"in":"query","schema":{"minimum":1,"maximum":200,"default":50,"type":"number"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PublicBranchListResponseDto"}}}}},"security":[{"PAT":[]}],"summary":"Listar sucursales activas del tenant","tags":["scheduling-branches"]}},"/v1/scheduling/branches/{id}":{"get":{"operationId":"PublicBranchesController_getById","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PublicBranchResponseDto"}}}}},"security":[{"PAT":[]}],"summary":"Obtener detalle de una sucursal","tags":["scheduling-branches"]}},"/v1/scheduling/sectors":{"get":{"operationId":"PublicSectorsController_list","parameters":[{"name":"search","required":false,"in":"query","description":"Búsqueda libre por nombre","schema":{"type":"string"}},{"name":"skip","required":false,"in":"query","schema":{"minimum":0,"default":0,"type":"number"}},{"name":"limit","required":false,"in":"query","schema":{"minimum":1,"maximum":200,"default":50,"type":"number"}}],"responses":{"200":{"description":""}},"security":[{"PAT":[]}],"summary":"Listar sectores del local","tags":["scheduling-sectors"]}},"/v1/scheduling/services":{"get":{"operationId":"PublicServicesController_list","parameters":[{"name":"branchId","required":false,"in":"query","description":"Filtrar por sucursal","schema":{"type":"string"}},{"name":"search","required":false,"in":"query","schema":{"type":"string"}},{"name":"status","required":false,"in":"query","description":"Estado del servicio (active/inactive)","schema":{"type":"string"}},{"name":"skip","required":false,"in":"query","schema":{"minimum":0,"default":0,"type":"number"}},{"name":"limit","required":false,"in":"query","schema":{"minimum":1,"maximum":200,"default":50,"type":"number"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/PublicServiceResponseDto"}}}}}},"security":[{"PAT":[]}],"summary":"Listar servicios disponibles del tenant","tags":["scheduling-services"]}},"/v1/scheduling/services/{id}":{"get":{"operationId":"PublicServicesController_getById","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PublicServiceResponseDto"}}}}},"security":[{"PAT":[]}],"summary":"Obtener detalle de un servicio","tags":["scheduling-services"]}},"/v1/scheduling/professionals":{"get":{"operationId":"PublicProfessionalsController_list","parameters":[{"name":"branchId","required":false,"in":"query","description":"Filtrar por sucursal","schema":{"type":"string"}},{"name":"serviceId","required":false,"in":"query","description":"Filtrar por servicio prestado","schema":{"type":"string"}},{"name":"search","required":false,"in":"query","schema":{"type":"string"}},{"name":"status","required":false,"in":"query","description":"Estado (active/inactive/on_leave)","schema":{"type":"string"}},{"name":"skip","required":false,"in":"query","schema":{"minimum":0,"default":0,"type":"number"}},{"name":"limit","required":false,"in":"query","schema":{"minimum":1,"maximum":200,"default":50,"type":"number"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/PublicProfessionalResponseDto"}}}}}},"security":[{"PAT":[]}],"summary":"Listar profesionales del tenant","tags":["scheduling-professionals"]}},"/v1/scheduling/professionals/{id}":{"get":{"operationId":"PublicProfessionalsController_getById","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PublicProfessionalResponseDto"}}}}},"security":[{"PAT":[]}],"summary":"Obtener detalle de un profesional","tags":["scheduling-professionals"]}},"/v1/scheduling/availability":{"get":{"description":"Retorna los slots libres para un servicio en una fecha puntual.","operationId":"PublicAvailabilityController_byDate","parameters":[{"name":"serviceId","required":true,"in":"query","description":"Servicio (requerido)","schema":{"type":"string"}},{"name":"date","required":true,"in":"query","description":"Fecha en formato YYYY-MM-DD","schema":{"example":"2026-05-02","type":"string"}},{"name":"branchId","required":false,"in":"query","description":"Sucursal (default: primera del tenant)","schema":{"type":"string"}},{"name":"professionalId","required":false,"in":"query","description":"Profesional específico","schema":{"type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PublicAvailabilityResponseDto"}}}}},"security":[{"PAT":[]}],"summary":"Disponibilidad por fecha específica","tags":["scheduling-availability"]}},"/v1/scheduling/availability/range":{"get":{"description":"Retorna los slots libres día a día entre `from` y `to` (inclusive).","operationId":"PublicAvailabilityController_byRange","parameters":[{"name":"serviceId","required":true,"in":"query","description":"Servicio (requerido)","schema":{"type":"string"}},{"name":"from","required":true,"in":"query","description":"Fecha desde (YYYY-MM-DD)","schema":{"type":"string"}},{"name":"to","required":true,"in":"query","description":"Fecha hasta (YYYY-MM-DD, máximo 14 días desde from)","schema":{"type":"string"}},{"name":"branchId","required":false,"in":"query","schema":{"type":"string"}},{"name":"professionalId","required":false,"in":"query","schema":{"type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PublicAvailabilityRangeResponseDto"}}}}},"security":[{"PAT":[]}],"summary":"Disponibilidad por rango de fechas (máximo 14 días)","tags":["scheduling-availability"]}},"/v1/scheduling/availability/next":{"get":{"description":"Busca los próximos slots libres a partir de `fromDate` (default: hoy) recorriendo hasta `maxDays` días.","operationId":"PublicAvailabilityController_next","parameters":[{"name":"serviceId","required":true,"in":"query","description":"Servicio (requerido)","schema":{"type":"string"}},{"name":"branchId","required":false,"in":"query","schema":{"type":"string"}},{"name":"professionalId","required":false,"in":"query","schema":{"type":"string"}},{"name":"fromDate","required":false,"in":"query","description":"Fecha desde (YYYY-MM-DD)","schema":{"type":"string"}},{"name":"maxDays","required":false,"in":"query","schema":{"minimum":1,"maximum":60,"default":14,"type":"number"}},{"name":"limit","required":false,"in":"query","schema":{"minimum":1,"maximum":20,"default":5,"type":"number"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PublicNextAvailabilityResponseDto"}}}}},"security":[{"PAT":[]}],"summary":"Próximas horas disponibles más cercanas","tags":["scheduling-availability"]}},"/v1/scheduling/appointments/{id}":{"get":{"operationId":"PublicAppointmentsController_getById","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PublicAppointmentResponseDto"}}}}},"security":[{"PAT":[]}],"summary":"Obtener detalle de una cita","tags":["scheduling-appointments"]}},"/v1/scheduling/appointments":{"post":{"description":"Crea una nueva cita en estado pendiente con datos del cliente embebidos.","operationId":"PublicAppointmentsController_create","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/PublicAppointmentCreateDto"}}}},"responses":{"201":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PublicAppointmentResponseDto"}}}}},"security":[{"PAT":[]}],"summary":"Crear una cita","tags":["scheduling-appointments"]}},"/v1/scheduling/appointments/{id}/confirm":{"post":{"description":"Sólo permite confirmar citas en estado `pending`. Devuelve 409 en caso contrario.","operationId":"PublicAppointmentsController_confirm","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PublicAppointmentResponseDto"}}}}},"security":[{"PAT":[]}],"summary":"Confirmar una cita","tags":["scheduling-appointments"]}},"/v1/scheduling/appointments/{id}/cancel":{"post":{"description":"Marca la cita como cancelada con la razón opcional indicada.","operationId":"PublicAppointmentsController_cancel","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CancelAppointmentDto"}}}},"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PublicAppointmentResponseDto"}}}}},"security":[{"PAT":[]}],"summary":"Suspender (cancelar) una cita","tags":["scheduling-appointments"]}},"/v1/scheduling/booking/availability":{"get":{"operationId":"PublicBookingController_availability","parameters":[],"responses":{"200":{"description":""}},"security":[{"PAT":[]}],"summary":"Consultar horarios para reservar o modificar una cita","tags":["scheduling-booking"]}},"/v1/scheduling/booking/appointments":{"post":{"operationId":"PublicBookingController_create","parameters":[{"name":"idempotency-key","required":true,"in":"header","schema":{"type":"string"}},{"name":"Idempotency-Key","in":"header","required":true,"schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CustomerBookingCreateDto"}}}},"responses":{"201":{"description":""}},"security":[{"PAT":[]}],"summary":"Reservar con validación de disponibilidad y saldo de sesiones","tags":["scheduling-booking"]},"get":{"operationId":"PublicBookingController_list","parameters":[],"responses":{"200":{"description":""}},"security":[{"PAT":[]}],"summary":"Buscar citas nativas y externas de un cliente","tags":["scheduling-booking"]}},"/v1/scheduling/booking/pending-reminder-confirmations":{"get":{"operationId":"PublicBookingController_pending","parameters":[],"responses":{"200":{"description":""}},"security":[{"PAT":[]}],"summary":"Consultar citas con recordatorio pendiente de confirmación","tags":["scheduling-booking"]}},"/v1/scheduling/booking/appointments/{id}":{"get":{"operationId":"PublicBookingController_get","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":""}},"security":[{"PAT":[]}],"summary":"Consultar una cita validando pertenencia al cliente","tags":["scheduling-booking"]},"patch":{"operationId":"PublicBookingController_modify","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CustomerBookingModifyDto"}}}},"responses":{"200":{"description":""}},"security":[{"PAT":[]}],"summary":"Modificar la misma cita con validación de pertenencia y disponibilidad","tags":["scheduling-booking"]}},"/v1/scheduling/booking/appointments/{id}/confirm":{"post":{"operationId":"PublicBookingController_confirm","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":""}},"security":[{"PAT":[]}],"summary":"Confirmar una cita del cliente","tags":["scheduling-booking"]}},"/v1/scheduling/booking/appointments/{id}/cancel":{"post":{"operationId":"PublicBookingController_cancel","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CustomerBookingCancelDto"}}}},"responses":{"200":{"description":""}},"security":[{"PAT":[]}],"summary":"Cancelar una cita del cliente y restituir su sesión cuando corresponda","tags":["scheduling-booking"]}},"/v1/scheduling/payment-links":{"post":{"operationId":"PublicPaymentLinksController_create","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CustomerBookingPaymentLinkDto"}}}},"responses":{"200":{"description":""}},"security":[{"PAT":[]}],"summary":"Generar un link de pago por las citas con saldo del cliente o por un monto acordado","tags":["scheduling-booking"]}},"/v1/restaurants/menu-items":{"get":{"description":"Devuelve la carta de la company del token aplanada: un ítem por plato, con su sección, su precio y sus alérgenos.","operationId":"PublicRestaurantsController_listMenuItems","parameters":[{"name":"search","required":false,"in":"query","description":"Filtra por nombre, descripción o sección.","schema":{"type":"string"}},{"name":"limit","required":false,"in":"query","schema":{"maximum":200,"default":50,"type":"number"}},{"name":"offset","required":false,"in":"query","schema":{"default":0,"type":"number"}}],"responses":{"200":{"description":""}},"security":[{"PAT":[]}],"summary":"Listar los platos de la carta","tags":["restaurants"]}},"/v1/tenants":{"post":{"operationId":"PublicTenantsController_create","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/TenantCreateDto"}}}},"responses":{"201":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PublicTenantResponseDto"}}}}},"security":[{"PAT":[]}],"summary":"Crear un tenant (cliente final del developer).","tags":["tenants"]},"get":{"operationId":"PublicTenantsController_list","parameters":[{"name":"search","required":true,"in":"query","schema":{"type":"string"}},{"name":"cursor","required":true,"in":"query","schema":{"type":"string"}},{"name":"limit","required":true,"in":"query","schema":{"type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PublicTenantListResponseDto"}}}}},"security":[{"PAT":[]}],"summary":"Listar tenants.","tags":["tenants"]}},"/v1/tenants/{id}":{"get":{"operationId":"PublicTenantsController_getById","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PublicTenantResponseDto"}}}}},"security":[{"PAT":[]}],"summary":"Obtener tenant por id.","tags":["tenants"]},"patch":{"operationId":"PublicTenantsController_update","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/TenantUpdateDto"}}}},"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PublicTenantResponseDto"}}}}},"security":[{"PAT":[]}],"summary":"Editar tenant.","tags":["tenants"]},"delete":{"operationId":"PublicTenantsController_remove","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"204":{"description":""}},"security":[{"PAT":[]}],"summary":"Soft-delete del tenant.","tags":["tenants"]}},"/v1/tenants/{id}/whatsapp-configs":{"get":{"operationId":"PublicTenantsController_listWhatsappConfigs","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PublicTenantWhatsappConfigListResponseDto"}}}}},"security":[{"PAT":[]}],"summary":"Listar canales WhatsApp asociados al tenant.","tags":["tenants"]}},"/v1/tenants/{id}/setup-links":{"post":{"operationId":"PublicTenantsController_createSetupLink","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SetupLinkCreateDto"}}}},"responses":{"201":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PublicSetupLinkResponseDto"}}}}},"security":[{"PAT":[]}],"summary":"Generar un setup link para el tenant.","tags":["tenants"]},"get":{"operationId":"PublicTenantsController_listSetupLinks","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PublicSetupLinkListResponseDto"}}}}},"security":[{"PAT":[]}],"summary":"Listar setup links del tenant.","tags":["tenants"]}},"/v1/tenants/{id}/setup-links/{linkId}":{"patch":{"operationId":"PublicTenantsController_updateSetupLink","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}},{"name":"linkId","required":true,"in":"path","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SetupLinkUpdateDto"}}}},"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PublicSetupLinkResponseDto"}}}}},"security":[{"PAT":[]}],"summary":"Editar config de setup link (no rota el token).","tags":["tenants"]},"delete":{"operationId":"PublicTenantsController_revokeSetupLink","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}},{"name":"linkId","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"204":{"description":""}},"security":[{"PAT":[]}],"summary":"Revocar setup link. Token deja de ser válido.","tags":["tenants"]}},"/v1/setup/links/{token}":{"get":{"operationId":"PublicSetupController_getLink","parameters":[{"name":"token","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PublicSetupLinkConfigResponseDto"}}}}},"summary":"Config pública del setup link. Sin auth: el token del link autoriza.","tags":["setup"]}},"/v1/setup/links/{token}/start":{"post":{"operationId":"PublicSetupController_start","parameters":[{"name":"token","required":true,"in":"path","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/StartSetupLinkRequestDto"}}}},"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PublicStartSetupLinkResponseDto"}}}}},"summary":"Inicia el flujo de conexión (Embedded Signup, Coexistence o QR). Sin persistencia intermedia: el state HMAC firmado correlaciona el callback.","tags":["setup"]}},"/v1/setup/links/{token}/complete":{"post":{"operationId":"PublicSetupController_complete","parameters":[{"name":"token","required":true,"in":"path","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CompleteSetupLinkRequestDto"}}}},"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PublicCompleteSetupLinkResponseDto"}}}}},"summary":"Cierra el flujo Embedded Signup iniciado vía Facebook JS SDK. Recibe code + waba_id + phone_number_id, verifica state HMAC y crea el Channel.","tags":["setup"]}},"/v1/auth/cli/select-project":{"post":{"operationId":"CliSessionController_selectProject","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SelectProjectRequestDto"}}}},"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PublicCliSelectProjectResponseDto"}}}}},"security":[{"PAT":[]}],"summary":"Cambia el project activo de la session CLI y emite un JWT nuevo. Sólo aceptable con un JWT del CLI (no con PAT).","tags":["cli-session"]}},"/v1/auth/cli/me":{"get":{"operationId":"CliSessionController_me","parameters":[],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PublicCliMeResponseDto"}}}}},"security":[{"PAT":[]}],"summary":"Datos de la session CLI actual (user, company, current project). Útil para `keebai whoami`.","tags":["cli-session"]}}},"info":{"title":"Keebai Public API","description":"Superficie pública REST autenticada con Personal Access Tokens (PAT).","version":"1.0.0","contact":{}},"tags":[],"servers":[{"url":"https://api.keebai.com","description":"Production"}],"components":{"securitySchemes":{"PAT":{"scheme":"bearer","bearerFormat":"kbai_pk_<hex>","type":"http","description":"Personal Access Token con prefijo `kbai_pk_`. Generar desde el portal con permiso `developer.manage_tokens`."}},"schemas":{"MeResponseDto":{"type":"object","properties":{"permissions":{"description":"Permisos efectivos del token: intersección entre los scopes del token y los permisos actuales del usuario.","example":["conversations.read","contacts.read"],"type":"array","items":{"type":"string"}}},"required":["permissions"]},"TextMessagePayloadDto":{"type":"object","properties":{"type":{"type":"string","enum":["text"]},"body":{"type":"string","example":"Hola, tu pedido va en camino.","maxLength":4096},"preview_url":{"type":"boolean","description":"Render a link preview for the first URL in the body."}},"required":["type","body"]},"ImageMessagePayloadDto":{"type":"object","properties":{"link":{"type":"string","description":"Public HTTPS URL to the file."},"media_id":{"type":"string","description":"Previously-uploaded media id (POST /v1/media/upload)."},"type":{"type":"string","enum":["image"]},"caption":{"type":"string","maxLength":1024}},"required":["type"]},"VideoMessagePayloadDto":{"type":"object","properties":{"link":{"type":"string","description":"Public HTTPS URL to the file."},"media_id":{"type":"string","description":"Previously-uploaded media id (POST /v1/media/upload)."},"type":{"type":"string","enum":["video"]},"caption":{"type":"string","maxLength":1024}},"required":["type"]},"AudioMessagePayloadDto":{"type":"object","properties":{"link":{"type":"string","description":"Public HTTPS URL to the file."},"media_id":{"type":"string","description":"Previously-uploaded media id (POST /v1/media/upload)."},"type":{"type":"string","enum":["audio"]},"voice":{"type":"boolean","description":"Send as a voice note (PTT) instead of an audio file."}},"required":["type"]},"DocumentMessagePayloadDto":{"type":"object","properties":{"link":{"type":"string","description":"Public HTTPS URL to the file."},"media_id":{"type":"string","description":"Previously-uploaded media id (POST /v1/media/upload)."},"type":{"type":"string","enum":["document"]},"filename":{"type":"string","maxLength":240},"caption":{"type":"string","maxLength":1024}},"required":["type"]},"StickerMessagePayloadDto":{"type":"object","properties":{"link":{"type":"string","description":"Public HTTPS URL to the file."},"media_id":{"type":"string","description":"Previously-uploaded media id (POST /v1/media/upload)."},"type":{"type":"string","enum":["sticker"]}},"required":["type"]},"LocationMessagePayloadDto":{"type":"object","properties":{"type":{"type":"string","enum":["location"]},"latitude":{"type":"number","example":-33.4489},"longitude":{"type":"number","example":-70.6693},"name":{"type":"string","maxLength":1000},"address":{"type":"string","maxLength":1000}},"required":["type","latitude","longitude"]},"ContactNameDto":{"type":"object","properties":{"formatted_name":{"type":"string"},"first_name":{"type":"string"},"last_name":{"type":"string"}},"required":["formatted_name"]},"ContactPhoneDto":{"type":"object","properties":{"phone":{"type":"string"},"type":{"type":"string"},"wa_id":{"type":"string"}},"required":["phone"]},"ContactEmailDto":{"type":"object","properties":{"email":{"type":"string"},"type":{"type":"string"}},"required":["email"]},"ContactUrlDto":{"type":"object","properties":{"url":{"type":"string"},"type":{"type":"string"}},"required":["url"]},"ContactOrgDto":{"type":"object","properties":{"company":{"type":"string"},"department":{"type":"string"},"title":{"type":"string"}}},"ContactCardDto":{"type":"object","properties":{"name":{"$ref":"#/components/schemas/ContactNameDto"},"phones":{"type":"array","items":{"$ref":"#/components/schemas/ContactPhoneDto"}},"emails":{"type":"array","items":{"$ref":"#/components/schemas/ContactEmailDto"}},"urls":{"type":"array","items":{"$ref":"#/components/schemas/ContactUrlDto"}},"org":{"$ref":"#/components/schemas/ContactOrgDto"},"birthday":{"type":"string","example":"1990-03-24"}},"required":["name"]},"ContactsMessagePayloadDto":{"type":"object","properties":{"type":{"type":"string","enum":["contacts"]},"contacts":{"minItems":1,"maxItems":20,"type":"array","items":{"$ref":"#/components/schemas/ContactCardDto"}}},"required":["type","contacts"]},"ReactionMessagePayloadDto":{"type":"object","properties":{"type":{"type":"string","enum":["reaction"]},"message_id":{"type":"string","description":"Provider message id (wamid.* on WhatsApp) to react to."},"emoji":{"type":"string","description":"Emoji to send as reaction. Empty string clears a previous reaction.","example":"👍"}},"required":["type","message_id","emoji"]},"TemplateFlowButtonDto":{"type":"object","properties":{"flow_token":{"type":"string","description":"Opaque correlation id echoed back on the flow response webhook. Must be unique per send.","example":"srv-9f2c41"},"button_index":{"type":"number","description":"Zero-based index of the FLOW button in the template.","default":0},"flow_action_data":{"type":"object","description":"Initial screen data handed to the Flow when it opens. Only used when the template button was created with flow_action=navigate.","example":{"ticket_id":"A-1"}}},"required":["flow_token"]},"TemplateMessagePayloadDto":{"type":"object","properties":{"type":{"type":"string","enum":["template"]},"name":{"type":"string","example":"welcome_v2"},"language":{"type":"string","example":"es"},"variables":{"type":"object","example":{"nombre":"Juan","monto":"1500"},"description":"Named template variables (Meta parameter_name)."},"flow":{"$ref":"#/components/schemas/TemplateFlowButtonDto"}},"required":["type","name","language"]},"InteractiveHeaderDto":{"type":"object","properties":{"type":{"type":"string","enum":["text"]},"text":{"type":"string","maxLength":60}},"required":["type","text"]},"InteractiveButtonDto":{"type":"object","properties":{"id":{"type":"string","maxLength":256},"title":{"type":"string","maxLength":20}},"required":["id","title"]},"ButtonsMessagePayloadDto":{"type":"object","properties":{"body_text":{"type":"string","maxLength":1024},"header":{"$ref":"#/components/schemas/InteractiveHeaderDto"},"footer_text":{"type":"string","maxLength":60},"type":{"type":"string","enum":["buttons"]},"buttons":{"minItems":1,"maxItems":3,"type":"array","items":{"$ref":"#/components/schemas/InteractiveButtonDto"}}},"required":["body_text","type","buttons"]},"InteractiveListRowDto":{"type":"object","properties":{"id":{"type":"string"},"title":{"type":"string","maxLength":24},"description":{"type":"string","maxLength":72}},"required":["id","title"]},"InteractiveListSectionDto":{"type":"object","properties":{"title":{"type":"string","maxLength":24},"rows":{"minItems":1,"maxItems":10,"type":"array","items":{"$ref":"#/components/schemas/InteractiveListRowDto"}}},"required":["rows"]},"ListMessagePayloadDto":{"type":"object","properties":{"body_text":{"type":"string","maxLength":1024},"header":{"$ref":"#/components/schemas/InteractiveHeaderDto"},"footer_text":{"type":"string","maxLength":60},"type":{"type":"string","enum":["list"]},"button_text":{"type":"string","maxLength":20,"description":"Label of the button that opens the list."},"sections":{"minItems":1,"maxItems":10,"type":"array","items":{"$ref":"#/components/schemas/InteractiveListSectionDto"}}},"required":["body_text","type","button_text","sections"]},"CtaUrlMessagePayloadDto":{"type":"object","properties":{"body_text":{"type":"string","maxLength":1024},"header":{"$ref":"#/components/schemas/InteractiveHeaderDto"},"footer_text":{"type":"string","maxLength":60},"type":{"type":"string","enum":["cta_url"]},"display_text":{"type":"string","maxLength":20},"url":{"type":"string"}},"required":["body_text","type","display_text","url"]},"CatalogMessagePayloadDto":{"type":"object","properties":{"body_text":{"type":"string","maxLength":1024},"header":{"$ref":"#/components/schemas/InteractiveHeaderDto"},"footer_text":{"type":"string","maxLength":60},"type":{"type":"string","enum":["catalog"]},"thumbnail_product_retailer_id":{"type":"string","description":"Retailer id of the product used as the catalog thumbnail."}},"required":["body_text","type"]},"CarouselCardHeaderDto":{"type":"object","properties":{"type":{"type":"string","enum":["image","video"]},"link":{"type":"string","description":"Public HTTPS URL of the card media. Meta rejects .webp images on carousel headers."}},"required":["type","link"]},"CarouselCardActionDto":{"type":"object","properties":{"display_text":{"type":"string","maxLength":20},"url":{"type":"string"}},"required":["display_text","url"]},"CarouselCardDto":{"type":"object","properties":{"header":{"$ref":"#/components/schemas/CarouselCardHeaderDto"},"body_text":{"type":"string","maxLength":1024},"action":{"$ref":"#/components/schemas/CarouselCardActionDto"}},"required":["header","action"]},"CarouselMessagePayloadDto":{"type":"object","properties":{"body_text":{"type":"string","maxLength":1024},"header":{"$ref":"#/components/schemas/InteractiveHeaderDto"},"footer_text":{"type":"string","maxLength":60},"type":{"type":"string","enum":["carousel"]},"cards":{"minItems":1,"maxItems":10,"type":"array","items":{"$ref":"#/components/schemas/CarouselCardDto"}}},"required":["body_text","type","cards"]},"FlowActionPayloadDto":{"type":"object","properties":{"screen":{"type":"string","description":"Name of the first screen to open, as declared in the Flow JSON.","example":"WELCOME"},"data":{"type":"object","description":"Initial data injected into that screen.","example":{"customer_name":"Juan"}}},"required":["screen"]},"FlowMessagePayloadDto":{"type":"object","properties":{"type":{"type":"string","enum":["flow"]},"flow_id":{"type":"string","description":"Meta Flow id, as returned by POST /v1/flows.","example":"1234567890123456"},"flow_token":{"type":"string","description":"Opaque correlation id echoed back on the flow response webhook. Must be unique per send.","example":"srv-9f2c41"},"flow_cta":{"type":"string","description":"Label of the button that opens the Flow.","maxLength":20,"example":"Reservar"},"flow_action":{"type":"string","enum":["navigate","data_exchange"],"default":"navigate","description":"`navigate` opens the screen named in flow_action_payload; `data_exchange` hands control to the Flow endpoint."},"flow_action_payload":{"description":"Required when flow_action is `navigate`.","allOf":[{"$ref":"#/components/schemas/FlowActionPayloadDto"}]},"mode":{"type":"string","enum":["draft","published"],"default":"published","description":"Send a Flow that has not been published yet. Draft mode only reaches numbers listed as testers on the WABA."},"body_text":{"type":"string","maxLength":1024},"header_text":{"type":"string","maxLength":60},"footer_text":{"type":"string","maxLength":60}},"required":["type","flow_id","flow_token","flow_cta","body_text"]},"MessageContextDto":{"type":"object","properties":{"message_id":{"type":"string","description":"Provider message id (wamid.* on WhatsApp) this message quotes as a reply."}},"required":["message_id"]},"SendMessageDto":{"type":"object","properties":{"channel":{"type":"string","enum":["whatsapp","instagram","messenger"],"example":"whatsapp","description":"Channel the message is delivered through."},"channel_id":{"type":"string","example":"665f1a2b3c4d5e6f70819234","description":"Keebai channel id. Optional when the tenant has exactly one active channel of the given type; required to disambiguate otherwise."},"phone_number_id":{"type":"string","example":"100000000000001","description":"WhatsApp-only alias for channel_id: the Meta phone_number_id of the sending number. Ignored on other channels."},"to":{"type":"string","example":"+5491155555555","description":"Recipient. E.164 phone number on whatsapp; the Meta-scoped id (IGSID / PSID) on instagram and messenger."},"context":{"$ref":"#/components/schemas/MessageContextDto"},"meta_data":{"type":"object","description":"Free-form metadata persisted with the message. Returned on webhooks for correlation."},"message":{"oneOf":[{"$ref":"#/components/schemas/TextMessagePayloadDto"},{"$ref":"#/components/schemas/ImageMessagePayloadDto"},{"$ref":"#/components/schemas/VideoMessagePayloadDto"},{"$ref":"#/components/schemas/AudioMessagePayloadDto"},{"$ref":"#/components/schemas/DocumentMessagePayloadDto"},{"$ref":"#/components/schemas/StickerMessagePayloadDto"},{"$ref":"#/components/schemas/LocationMessagePayloadDto"},{"$ref":"#/components/schemas/ContactsMessagePayloadDto"},{"$ref":"#/components/schemas/ReactionMessagePayloadDto"},{"$ref":"#/components/schemas/TemplateMessagePayloadDto"},{"$ref":"#/components/schemas/ButtonsMessagePayloadDto"},{"$ref":"#/components/schemas/ListMessagePayloadDto"},{"$ref":"#/components/schemas/CtaUrlMessagePayloadDto"},{"$ref":"#/components/schemas/CatalogMessagePayloadDto"},{"$ref":"#/components/schemas/CarouselMessagePayloadDto"},{"$ref":"#/components/schemas/FlowMessagePayloadDto"}],"discriminator":{"propertyName":"type","mapping":{"text":"#/components/schemas/TextMessagePayloadDto","image":"#/components/schemas/ImageMessagePayloadDto","video":"#/components/schemas/VideoMessagePayloadDto","audio":"#/components/schemas/AudioMessagePayloadDto","document":"#/components/schemas/DocumentMessagePayloadDto","sticker":"#/components/schemas/StickerMessagePayloadDto","location":"#/components/schemas/LocationMessagePayloadDto","contacts":"#/components/schemas/ContactsMessagePayloadDto","reaction":"#/components/schemas/ReactionMessagePayloadDto","template":"#/components/schemas/TemplateMessagePayloadDto","buttons":"#/components/schemas/ButtonsMessagePayloadDto","list":"#/components/schemas/ListMessagePayloadDto","cta_url":"#/components/schemas/CtaUrlMessagePayloadDto","catalog":"#/components/schemas/CatalogMessagePayloadDto","carousel":"#/components/schemas/CarouselMessagePayloadDto","flow":"#/components/schemas/FlowMessagePayloadDto"}}}},"required":["channel","to","message"]},"SingleSendResponse":{"type":"object","properties":{"message_id":{"type":"string","description":"Meta message_id (wamid.*) of the sent WhatsApp message."},"status":{"type":"string","example":"sent"},"sent_at":{"type":"string","description":"ISO-8601 timestamp of the dispatch."}},"required":["message_id","status","sent_at"]},"MarkReadDto":{"type":"object","properties":{"channel_id":{"type":"string","example":"665f1a2b3c4d5e6f70819234","description":"Keebai channel id. Optional when the tenant has exactly one active channel of the given type; required to disambiguate otherwise."},"phone_number_id":{"type":"string","example":"100000000000001","description":"WhatsApp-only alias for channel_id: the Meta phone_number_id of the sending number. Ignored on other channels."},"message_id":{"type":"string","description":"Meta message_id (wamid.*) to mark as read."},"typing_indicator":{"type":"string","enum":["text","off"]}},"required":["message_id"]},"MarkReadResponse":{"type":"object","properties":{"success":{"type":"boolean"}},"required":["success"]},"SendRawDto":{"type":"object","properties":{"channel_id":{"type":"string","example":"665f1a2b3c4d5e6f70819234","description":"Keebai channel id. Optional when the tenant has exactly one active channel of the given type; required to disambiguate otherwise."},"phone_number_id":{"type":"string","example":"100000000000001","description":"WhatsApp-only alias for channel_id: the Meta phone_number_id of the sending number. Ignored on other channels."},"body":{"type":"object","description":"Raw Meta Graph API messages body. Sent as-is to /{phone_number_id}/messages. Use only when POST /v1/messages has no matching type."},"meta_data":{"type":"object","description":"Free-form metadata persisted with the message. Returned on webhooks for correlation."}},"required":["body"]},"BulkRecipientDto":{"type":"object","properties":{"to":{"type":"string","example":"+5491155555555"},"variables":{"type":"object","example":{"nombre":"Juan"}},"meta_data":{"type":"object","description":"Free-form metadata persisted with the message. Returned on webhooks for correlation."}},"required":["to"]},"SendBulkDto":{"type":"object","properties":{"channel_id":{"type":"string","example":"665f1a2b3c4d5e6f70819234","description":"Keebai channel id. Optional when the tenant has exactly one active channel of the given type; required to disambiguate otherwise."},"phone_number_id":{"type":"string","example":"100000000000001","description":"WhatsApp-only alias for channel_id: the Meta phone_number_id of the sending number. Ignored on other channels."},"template_name":{"type":"string","example":"welcome_v2"},"language":{"type":"string","example":"es"},"campaign_name":{"type":"string","example":"Onboarding marzo 2026"},"recipients":{"minItems":1,"maxItems":5000,"type":"array","items":{"$ref":"#/components/schemas/BulkRecipientDto"}}},"required":["template_name","language","recipients"]},"BulkDispatchResponse":{"type":"object","properties":{"broadcast_id":{"type":"string"},"status":{"type":"string","example":"scheduled"},"total_recipients":{"type":"number"},"scheduled_at":{"type":"string","nullable":true}},"required":["broadcast_id","status","total_recipients"]},"BulkStatusResponse":{"type":"object","properties":{"broadcast_id":{"type":"string"},"status":{"type":"string"},"total_recipients":{"type":"number"},"sent":{"type":"number"},"failed":{"type":"number"},"pending":{"type":"number"},"started_at":{"type":"string","nullable":true},"completed_at":{"type":"string","nullable":true}},"required":["broadcast_id","status","total_recipients","sent","failed","pending"]},"UploadMediaDto":{"type":"object","properties":{"phone_number_id":{"type":"string","example":"100000000000001"},"type":{"type":"string","example":"image/png"},"filename":{"type":"string"}},"required":["phone_number_id","type"]},"MediaUploadResponse":{"type":"object","properties":{"media_id":{"type":"string"},"mime_type":{"type":"string"},"size":{"type":"number"}},"required":["media_id","mime_type","size"]},"MediaMetadataResponse":{"type":"object","properties":{"id":{"type":"string"},"url":{"type":"string"},"mime_type":{"type":"string"},"file_size":{"type":"number"},"sha256":{"type":"string"},"messaging_product":{"type":"string"}},"required":["id","url","mime_type","file_size"]},"CreateFlowDto":{"type":"object","properties":{"channel_id":{"type":"string","example":"665f1a2b3c4d5e6f70819234","description":"Keebai channel id. Optional when the tenant has exactly one active channel of the given type; required to disambiguate otherwise."},"phone_number_id":{"type":"string","example":"100000000000001","description":"WhatsApp-only alias for channel_id: the Meta phone_number_id of the sending number. Ignored on other channels."},"name":{"type":"string","example":"reserva-mesa","maxLength":100},"description":{"type":"string","maxLength":500},"categories":{"type":"array","default":["OTHER"],"items":{"type":"string","enum":["OTHER","SIGN_UP","SIGN_IN","APPOINTMENT_BOOKING","LEAD_GENERATION","CONTACT_US","CUSTOMER_SUPPORT","SURVEY"]}},"flow_data":{"type":"object","description":"Flow JSON as defined by Meta (version, screens, routing_model). Uploaded as the Flow asset on create.","example":{"version":"7.0","screens":[{"id":"WELCOME","title":"Reserva","terminal":true,"layout":{"type":"SingleColumnLayout","children":[]}}]}},"metadata":{"type":"object","description":"Free-form metadata stored alongside the Flow in Keebai."}},"required":["name","flow_data"]},"FlowResponseDto":{"type":"object","properties":{"id":{"type":"string","description":"Keebai flow id."},"channel_id":{"type":"string","description":"Keebai channel this Flow belongs to."},"name":{"type":"string"},"description":{"type":"string","nullable":true},"meta_flow_id":{"type":"string","nullable":true,"description":"Meta Flow id. Use it as `flow_id` when sending a message of type `flow`. Null until Meta accepts the Flow."},"categories":{"type":"array","items":{"type":"string","enum":["OTHER","SIGN_UP","SIGN_IN","APPOINTMENT_BOOKING","LEAD_GENERATION","CONTACT_US","CUSTOMER_SUPPORT","SURVEY"]}},"status":{"type":"string","enum":["draft","published","archived"]},"flow_data":{"type":"object","description":"Flow JSON currently stored in Keebai."},"metadata":{"type":"object"},"created_at":{"type":"string","format":"date-time","nullable":true},"updated_at":{"type":"string","format":"date-time","nullable":true}},"required":["id","channel_id","name","categories","status"]},"FlowListResponseDto":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/FlowResponseDto"}}},"required":["data"]},"UpdateFlowDto":{"type":"object","properties":{"name":{"type":"string","maxLength":100},"description":{"type":"string","maxLength":500},"categories":{"type":"array","items":{"type":"string","enum":["OTHER","SIGN_UP","SIGN_IN","APPOINTMENT_BOOKING","LEAD_GENERATION","CONTACT_US","CUSTOMER_SUPPORT","SURVEY"]}},"flow_data":{"type":"object","description":"Replacement Flow JSON. Re-uploaded as the Flow asset at Meta."},"metadata":{"type":"object"}}},"PublicTemplateDto":{"type":"object","properties":{"id":{"type":"string"},"name":{"type":"string"},"language":{"type":"string"},"status":{"type":"string"},"category":{"type":"string"},"parameter_format":{"type":"string"},"variables":{"type":"array","items":{"type":"string"}}},"required":["id","name","language","status","category","variables"]},"PaginatedTemplatesResponse":{"type":"object","properties":{"items":{"type":"array","items":{"$ref":"#/components/schemas/PublicTemplateDto"}},"page":{"type":"number"},"limit":{"type":"number"},"total":{"type":"number"}},"required":["items","page","limit","total"]},"TemplateButtonDto":{"type":"object","properties":{"type":{"type":"string","enum":["QUICK_REPLY","URL","PHONE_NUMBER","FLOW","VOICE_CALL","COPY_CODE","OTP"]},"text":{"type":"string","maxLength":25},"url":{"type":"string"},"phone_number":{"type":"string"},"example":{"type":"array","items":{"type":"string"}},"flow_id":{"type":"string"},"flow_action":{"type":"string","enum":["navigate","data_exchange"]},"coupon_code":{"type":"string"},"otp_type":{"type":"string","enum":["COPY_CODE","ONE_TAP","ZERO_TAP"]},"autofill_text":{"type":"string"},"package_name":{"type":"string"},"signature_hash":{"type":"string"}},"required":["type","text"]},"NamedParamDto":{"type":"object","properties":{"param_name":{"type":"string","example":"nombre"},"example":{"type":"string","example":"Juan"}},"required":["param_name","example"]},"TemplateExampleDto":{"type":"object","properties":{"header_text":{"type":"array","items":{"type":"string"}},"header_text_named_params":{"type":"array","items":{"$ref":"#/components/schemas/NamedParamDto"}},"header_handle":{"type":"array","items":{"type":"string"}},"body_text":{"type":"array","items":{"type":"string"}},"body_text_named_params":{"type":"array","items":{"$ref":"#/components/schemas/NamedParamDto"}}}},"TemplateComponentDto":{"type":"object","properties":{"type":{"type":"string","enum":["HEADER","BODY","FOOTER","BUTTONS"]},"format":{"type":"string","enum":["TEXT","IMAGE","VIDEO","DOCUMENT"]},"text":{"type":"string","maxLength":1024},"buttons":{"type":"array","items":{"$ref":"#/components/schemas/TemplateButtonDto"}},"example":{"$ref":"#/components/schemas/TemplateExampleDto"},"add_security_recommendation":{"type":"boolean"},"code_expiration_minutes":{"type":"number"}},"required":["type"]},"CreateTemplateDto":{"type":"object","properties":{"channel_id":{"type":"string","description":"ObjectId del canal WhatsApp donde se crea el template."},"name":{"type":"string","maxLength":512,"description":"Nombre del template. Solo minúsculas, números y guiones bajos.","example":"welcome_v2"},"language":{"type":"string","maxLength":10,"example":"es_CL"},"category":{"type":"string","enum":["MARKETING","UTILITY","AUTHENTICATION"]},"parameter_format":{"type":"string","enum":["NAMED","POSITIONAL"]},"components":{"type":"array","items":{"$ref":"#/components/schemas/TemplateComponentDto"}},"metadata":{"type":"object","additionalProperties":true}},"required":["channel_id","name","language","category","components"]},"UpdateTemplateDto":{"type":"object","properties":{"channel_id":{"type":"string","description":"ObjectId del canal WhatsApp dueño del template (requerido por upstream)."},"name":{"type":"string","maxLength":512},"language":{"type":"string","maxLength":10},"category":{"type":"string","enum":["MARKETING","UTILITY","AUTHENTICATION"]},"parameter_format":{"type":"string","enum":["NAMED","POSITIONAL"]},"components":{"type":"array","items":{"$ref":"#/components/schemas/TemplateComponentDto"}},"status":{"type":"string","enum":["PENDING","IN_REVIEW","REJECTED","APPROVED","PAUSED","DISABLED","IN_APPEAL"]},"metadata":{"type":"object","additionalProperties":true}},"required":["channel_id"]},"CreateWebhookDto":{"type":"object","properties":{"name":{"type":"string","example":"Producción - Notificaciones CRM"},"url":{"type":"string","example":"https://hooks.example.com/keebai"},"events":{"type":"array","description":"Eventos a los que se subscribe.","items":{"type":"string","enum":["whatsapp.message.received","whatsapp.message.sent","whatsapp.message.delivered","whatsapp.message.read","whatsapp.message.failed","whatsapp.template.status_updated","whatsapp.channel.connected","whatsapp.channel.disconnected","conversation.created","conversation.escalated_to_human","instagram.message.received","whatsapp.flow.response","crm.customer.created","crm.customer.updated","crm.customer.deleted","crm.ticket.created","crm.ticket.updated","crm.ticket.deleted","crm.ticket.stage_changed","crm.ticket.closed","crm.task.created","crm.task.updated","crm.task.deleted","crm.task.completed","crm.note.created","crm.note.updated","crm.note.deleted","scheduling.appointment.created","scheduling.appointment.updated","scheduling.appointment.confirmed","scheduling.appointment.cancelled","scheduling.appointment.rescheduled","scheduling.appointment.no_show","ecommerce.sale.created","ecommerce.sale.paid","ecommerce.sale.cancelled"]}},"headers":{"type":"object","description":"Headers extra a enviar en cada delivery.","example":{"X-Tenant-Origin":"crm"}},"is_active":{"type":"boolean","default":true}},"required":["name","url","events"]},"WebhookCreatedResponseDto":{"type":"object","properties":{"id":{"type":"string"},"name":{"type":"string"},"url":{"type":"string"},"events":{"type":"array","items":{"type":"string","enum":["whatsapp.message.received","whatsapp.message.sent","whatsapp.message.delivered","whatsapp.message.read","whatsapp.message.failed","whatsapp.template.status_updated","whatsapp.channel.connected","whatsapp.channel.disconnected","conversation.created","conversation.escalated_to_human","instagram.message.received","whatsapp.flow.response","crm.customer.created","crm.customer.updated","crm.customer.deleted","crm.ticket.created","crm.ticket.updated","crm.ticket.deleted","crm.ticket.stage_changed","crm.ticket.closed","crm.task.created","crm.task.updated","crm.task.deleted","crm.task.completed","crm.note.created","crm.note.updated","crm.note.deleted","scheduling.appointment.created","scheduling.appointment.updated","scheduling.appointment.confirmed","scheduling.appointment.cancelled","scheduling.appointment.rescheduled","scheduling.appointment.no_show","ecommerce.sale.created","ecommerce.sale.paid","ecommerce.sale.cancelled"]}},"is_active":{"type":"boolean"},"secret_prefix":{"type":"string","description":"Prefijo del secret para identificación visual."},"headers":{"type":"object"},"failure_count":{"type":"number"},"disabled_reason":{"type":"string","enum":["excessive_failures","manual"],"nullable":true},"last_delivery_at":{"type":"object","nullable":true},"created_at":{"type":"string"},"updated_at":{"type":"string"},"secret":{"type":"string","description":"Secret raw (whsec_...). Se muestra UNA SOLA VEZ. Guárdalo de inmediato — no se puede recuperar."}},"required":["id","name","url","events","is_active","secret_prefix","headers","failure_count","created_at","updated_at","secret"]},"WebhookResponseDto":{"type":"object","properties":{"id":{"type":"string"},"name":{"type":"string"},"url":{"type":"string"},"events":{"type":"array","items":{"type":"string","enum":["whatsapp.message.received","whatsapp.message.sent","whatsapp.message.delivered","whatsapp.message.read","whatsapp.message.failed","whatsapp.template.status_updated","whatsapp.channel.connected","whatsapp.channel.disconnected","conversation.created","conversation.escalated_to_human","instagram.message.received","whatsapp.flow.response","crm.customer.created","crm.customer.updated","crm.customer.deleted","crm.ticket.created","crm.ticket.updated","crm.ticket.deleted","crm.ticket.stage_changed","crm.ticket.closed","crm.task.created","crm.task.updated","crm.task.deleted","crm.task.completed","crm.note.created","crm.note.updated","crm.note.deleted","scheduling.appointment.created","scheduling.appointment.updated","scheduling.appointment.confirmed","scheduling.appointment.cancelled","scheduling.appointment.rescheduled","scheduling.appointment.no_show","ecommerce.sale.created","ecommerce.sale.paid","ecommerce.sale.cancelled"]}},"is_active":{"type":"boolean"},"secret_prefix":{"type":"string","description":"Prefijo del secret para identificación visual."},"headers":{"type":"object"},"failure_count":{"type":"number"},"disabled_reason":{"type":"string","enum":["excessive_failures","manual"],"nullable":true},"last_delivery_at":{"type":"object","nullable":true},"created_at":{"type":"string"},"updated_at":{"type":"string"}},"required":["id","name","url","events","is_active","secret_prefix","headers","failure_count","created_at","updated_at"]},"WebhookListResponseDto":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/WebhookResponseDto"}}},"required":["data"]},"UpdateWebhookDto":{"type":"object","properties":{"name":{"type":"string"},"url":{"type":"string"},"events":{"type":"array","items":{"type":"string","enum":["whatsapp.message.received","whatsapp.message.sent","whatsapp.message.delivered","whatsapp.message.read","whatsapp.message.failed","whatsapp.template.status_updated","whatsapp.channel.connected","whatsapp.channel.disconnected","conversation.created","conversation.escalated_to_human","instagram.message.received","whatsapp.flow.response","crm.customer.created","crm.customer.updated","crm.customer.deleted","crm.ticket.created","crm.ticket.updated","crm.ticket.deleted","crm.ticket.stage_changed","crm.ticket.closed","crm.task.created","crm.task.updated","crm.task.deleted","crm.task.completed","crm.note.created","crm.note.updated","crm.note.deleted","scheduling.appointment.created","scheduling.appointment.updated","scheduling.appointment.confirmed","scheduling.appointment.cancelled","scheduling.appointment.rescheduled","scheduling.appointment.no_show","ecommerce.sale.created","ecommerce.sale.paid","ecommerce.sale.cancelled"]}},"headers":{"type":"object"},"is_active":{"type":"boolean"}}},"TestWebhookDto":{"type":"object","properties":{"event_type":{"type":"string","enum":["whatsapp.message.received","whatsapp.message.sent","whatsapp.message.delivered","whatsapp.message.read","whatsapp.message.failed","whatsapp.template.status_updated","whatsapp.channel.connected","whatsapp.channel.disconnected","conversation.created","conversation.escalated_to_human","instagram.message.received","whatsapp.flow.response","crm.customer.created","crm.customer.updated","crm.customer.deleted","crm.ticket.created","crm.ticket.updated","crm.ticket.deleted","crm.ticket.stage_changed","crm.ticket.closed","crm.task.created","crm.task.updated","crm.task.deleted","crm.task.completed","crm.note.created","crm.note.updated","crm.note.deleted","scheduling.appointment.created","scheduling.appointment.updated","scheduling.appointment.confirmed","scheduling.appointment.cancelled","scheduling.appointment.rescheduled","scheduling.appointment.no_show","ecommerce.sale.created","ecommerce.sale.paid","ecommerce.sale.cancelled"]}},"required":["event_type"]},"WebhookTestAcceptedResponseDto":{"type":"object","properties":{"accepted":{"type":"boolean","description":"Siempre true: el evento quedó encolado."},"event_id":{"type":"string","description":"Id del evento sintético, para cruzarlo con el delivery"}},"required":["accepted","event_id"]},"DeliveryResponseDto":{"type":"object","properties":{"id":{"type":"string"},"subscription_id":{"type":"string"},"event_id":{"type":"string"},"event_type":{"type":"string","enum":["whatsapp.message.received","whatsapp.message.sent","whatsapp.message.delivered","whatsapp.message.read","whatsapp.message.failed","whatsapp.template.status_updated","whatsapp.channel.connected","whatsapp.channel.disconnected","conversation.created","conversation.escalated_to_human","instagram.message.received","whatsapp.flow.response","crm.customer.created","crm.customer.updated","crm.customer.deleted","crm.ticket.created","crm.ticket.updated","crm.ticket.deleted","crm.ticket.stage_changed","crm.ticket.closed","crm.task.created","crm.task.updated","crm.task.deleted","crm.task.completed","crm.note.created","crm.note.updated","crm.note.deleted","scheduling.appointment.created","scheduling.appointment.updated","scheduling.appointment.confirmed","scheduling.appointment.cancelled","scheduling.appointment.rescheduled","scheduling.appointment.no_show","ecommerce.sale.created","ecommerce.sale.paid","ecommerce.sale.cancelled"]},"status":{"type":"string","enum":["pending","success","failed","dead"]},"status_code":{"type":"object","nullable":true},"attempts":{"type":"number"},"last_error":{"type":"object","nullable":true},"delivered_at":{"type":"object","nullable":true},"duration_ms":{"type":"object","nullable":true},"created_at":{"type":"string"}},"required":["id","subscription_id","event_id","event_type","status","attempts","created_at"]},"DeliveryListResponseDto":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/DeliveryResponseDto"}},"next_cursor":{"type":"object","nullable":true}},"required":["data"]},"PublicChannelWhatsappDto":{"type":"object","properties":{"phone_number_id":{"type":"string","description":"phone_number_id emitido por Meta"},"phone_number":{"type":"string"},"business_account_id":{"type":"string"},"coexistence_enabled":{"type":"boolean"},"token_expires_at":{"type":"object","format":"date-time","nullable":true}},"required":["phone_number_id","phone_number","business_account_id","coexistence_enabled","token_expires_at"]},"PublicChannelInstagramDto":{"type":"object","properties":{"scope_id":{"type":"string"},"igb_business_account_id":{"type":"string"},"username":{"type":"string"},"token_expires_at":{"type":"object","format":"date-time","nullable":true}},"required":["scope_id","igb_business_account_id","username","token_expires_at"]},"PublicChannelResponseDto":{"type":"object","properties":{"id":{"type":"string","description":"ObjectId del canal"},"type":{"type":"string","description":"whatsapp | instagram | messenger …"},"name":{"type":"string"},"is_active":{"type":"boolean"},"whatsapp":{"$ref":"#/components/schemas/PublicChannelWhatsappDto"},"instagram":{"$ref":"#/components/schemas/PublicChannelInstagramDto"},"created_at":{"type":"string","format":"date-time"},"updated_at":{"type":"string","format":"date-time"}},"required":["id","type","name","is_active","created_at","updated_at"]},"PublicChannelListResponseDto":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/PublicChannelResponseDto"}}},"required":["data"]},"WhatsappConnectRequestDto":{"type":"object","properties":{"mode":{"type":"string","description":"Modo de conexión: `embedded_signup` abre el flujo de Meta en el portal.","enum":["embedded_signup"],"default":"embedded_signup"},"pipeline_id":{"type":"string","description":"Si se especifica, el canal recién creado se asocia automáticamente al pipeline. "},"coexistence_enabled":{"type":"boolean","description":"Activa el modo coexistencia (si el cliente ya tiene la app de WhatsApp Business activa). "},"name":{"type":"string","description":"Etiqueta visible del canal cuando se conecta por QR. Default: \"WhatsApp QR\"."}}},"PublicConnectSessionResponseDto":{"type":"object","properties":{"session_id":{"type":"string"},"provider":{"type":"string","description":"whatsapp"},"mode":{"type":"string","description":"embedded_signup | qr"},"verification_uri":{"type":"string","description":"URL del portal donde el usuario completa el Embedded Signup"},"stream_url":{"type":"string","description":"Ruta del stream SSE de pairing, sólo en modo qr"},"expires_in":{"type":"number","description":"Segundos hasta que la sesión expira"},"poll_interval":{"type":"number","description":"Segundos sugeridos entre polls"}},"required":["session_id","provider","mode","expires_in","poll_interval"]},"PublicConnectSessionPollResponseDto":{"type":"object","properties":{"session_id":{"type":"string"},"status":{"type":"string","description":"pending | completed | expired | failed"},"error":{"type":"string","description":"Detalle del fallo cuando status es failed"},"channel":{"description":"Canal creado. Sólo presente cuando status es completed.","allOf":[{"$ref":"#/components/schemas/PublicChannelResponseDto"}]}},"required":["session_id","status"]},"KnowledgeTreeNodeDto":{"type":"object","properties":{"id":{"type":"string"},"title":{"type":"string"},"node_type":{"type":"string","enum":["folder","document"]},"parent_id":{"type":"object","nullable":true},"position":{"type":"number"},"path_cache":{"type":"string"},"created_at":{"type":"string"},"updated_at":{"type":"string"},"children":{"type":"array","items":{"$ref":"#/components/schemas/KnowledgeTreeNodeDto"}}},"required":["id","title","node_type","position","path_cache","children"]},"KnowledgeTreeResponseDto":{"type":"object","properties":{"items":{"type":"array","items":{"$ref":"#/components/schemas/KnowledgeTreeNodeDto"}}},"required":["items"]},"CreateFolderDto":{"type":"object","properties":{"title":{"type":"string","description":"Título de la carpeta.","example":"Soporte","maxLength":200},"parent_id":{"type":"string","description":"ObjectId de la carpeta padre. Omitir para crear en la raíz."}},"required":["title"]},"KnowledgeNodeDto":{"type":"object","properties":{"id":{"type":"string"},"title":{"type":"string"},"node_type":{"type":"string","enum":["folder","document"]},"parent_id":{"type":"object","nullable":true},"position":{"type":"number"},"path_cache":{"type":"string"},"created_at":{"type":"string"},"updated_at":{"type":"string"}},"required":["id","title","node_type","position","path_cache"]},"CreateDocumentDto":{"type":"object","properties":{"title":{"type":"string","description":"Título del documento.","example":"Política de devolución","maxLength":200},"parent_id":{"type":"string","description":"ObjectId de la carpeta padre. Omitir para crear en la raíz."},"markdown":{"type":"string","description":"Contenido en Markdown. Se convierte a BlockNote JSON al guardar.","example":"# Política\n\nTexto de la política..."}},"required":["title","markdown"]},"SearchKnowledgeDto":{"type":"object","properties":{"query":{"type":"string","description":"Texto de búsqueda.","example":"¿cómo cancelar suscripción?"},"mode":{"type":"string","description":"Modo de búsqueda: full (full-text), vector (semántica) o hybrid (combinación con re-ranking).","enum":["full","hybrid","vector"],"example":"hybrid"},"top_k":{"type":"number","description":"Cantidad máxima de resultados (1-25).","example":5,"default":5},"node_ids":{"description":"Limita la búsqueda a estos node ids (carpetas o documentos).","type":"array","items":{"type":"string"}}},"required":["query","mode"]},"KnowledgeSearchResultItemDto":{"type":"object","properties":{"node_id":{"type":"string"},"title":{"type":"string"},"snippet":{"type":"string"},"score":{"type":"number"},"source":{"type":"string","enum":["full","vector"]}},"required":["node_id","score","source"]},"SearchKnowledgeResponseDto":{"type":"object","properties":{"mode":{"type":"string","enum":["full","hybrid","vector"]},"results":{"type":"array","items":{"$ref":"#/components/schemas/KnowledgeSearchResultItemDto"}}},"required":["mode","results"]},"AssignKnowledgeDto":{"type":"object","properties":{"agent_id":{"type":"string","description":"ObjectId del agente destino."},"node_ids":{"description":"ObjectIds de los nodos a asignar a todos los workers del agente.","type":"array","items":{"type":"string"}}},"required":["agent_id","node_ids"]},"AssignKnowledgeResponseDto":{"type":"object","properties":{"workers_updated":{"type":"number"}},"required":["workers_updated"]},"PublicContactResponseDto":{"type":"object","properties":{"_id":{"type":"string","description":"ObjectId del contacto"},"channel_type":{"type":"string","enum":["web","whatsapp","facebook","messenger","instagram","tiktok","telegram","email","phone"],"description":"Canal por el que existe el contacto"},"user_id":{"type":"string","description":"Identificador del contacto dentro de su canal"},"channel_id":{"type":"string","description":"ObjectId del canal concreto"},"external_id":{"type":"string","description":"Identificador en un sistema externo"},"username":{"type":"string"},"first_name":{"type":"string"},"last_name":{"type":"string"},"phone":{"type":"string"},"email":{"type":"string"},"profile_pic":{"type":"string"},"custom_fields":{"type":"object","description":"Campos personalizados de la company"},"tags":{"description":"Ids de tags","type":"array","items":{"type":"string"}},"is_attended":{"type":"boolean","description":"true cuando un agente humano tomó la conversación"},"last_attended_at":{"type":"string","format":"date-time"},"first_seen_at":{"type":"string","format":"date-time"},"last_seen_at":{"type":"string","format":"date-time"},"last_user_message_at":{"type":"string","format":"date-time"},"last_bot_response_at":{"type":"string","format":"date-time"},"last_agent_response_at":{"type":"string","format":"date-time"},"created_at":{"type":"string","format":"date-time"},"updated_at":{"type":"string","format":"date-time"}},"required":["_id","channel_type","user_id","custom_fields","tags","is_attended","first_seen_at","created_at","updated_at"]},"PublicContactListResponseDto":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/PublicContactResponseDto"}},"total":{"type":"number"},"limit":{"type":"number"},"offset":{"type":"number"}},"required":["data","total","limit","offset"]},"PublicContactEnvelopeDto":{"type":"object","properties":{"contact":{"$ref":"#/components/schemas/PublicContactResponseDto"}},"required":["contact"]},"PublicContactCreateDto":{"type":"object","properties":{"channel_type":{"type":"string","enum":["web","whatsapp","facebook","messenger","instagram","tiktok","telegram","email","phone"],"description":"Canal por el que existe el contacto. `playground` no se acepta en la API pública."},"user_id":{"type":"string","description":"Identificador del contacto dentro de ese canal. En WhatsApp es el wa_id (el teléfono sin +)."},"channel":{"type":"string","description":"ObjectId del canal concreto. Sin él, el contacto queda asociado sólo al tipo de canal."},"username":{"type":"string"},"first_name":{"type":"string"},"last_name":{"type":"string"},"phone":{"type":"string","description":"Teléfono en formato E.164"},"email":{"type":"string"},"profile_pic":{"type":"string","description":"URL de la foto de perfil"},"custom_fields":{"type":"object","description":"Campos personalizados de la company"}},"required":["channel_type","user_id"]},"PublicContactUpdateDto":{"type":"object","properties":{"username":{"type":"string"},"first_name":{"type":"string"},"last_name":{"type":"string"},"phone":{"type":"string","description":"Teléfono en formato E.164"},"email":{"type":"string"},"profile_pic":{"type":"string","description":"URL de la foto de perfil"},"custom_fields":{"type":"object","description":"Se mergea con los campos existentes; no reemplaza el objeto completo."}}},"PublicCustomerExternalIdResponseDto":{"type":"object","properties":{"provider":{"type":"string","description":"Sistema externo dueño del identificador"},"external_id":{"type":"string","description":"Identificador del cliente en ese sistema"}},"required":["provider","external_id"]},"PublicCustomerResponseDto":{"type":"object","properties":{"_id":{"type":"string","description":"ObjectId del cliente"},"name":{"type":"string"},"last_name":{"type":"string"},"email":{"type":"string"},"phone":{"type":"string"},"identification_number":{"type":"string"},"identification_type":{"type":"string","enum":["rut","dni","passport","other"]},"identification_country":{"type":"string","description":"Código de país ISO 3166-1 alpha-2"},"external_ids":{"type":"array","items":{"$ref":"#/components/schemas/PublicCustomerExternalIdResponseDto"}},"custom_fields":{"type":"object","description":"Campos personalizados de la company"},"tags":{"description":"Ids de tags del CRM","type":"array","items":{"type":"string"}},"accepts_marketing":{"type":"boolean"},"created_at":{"type":"string","format":"date-time"},"updated_at":{"type":"string","format":"date-time"}},"required":["_id","name","external_ids","custom_fields","tags","accepts_marketing","created_at","updated_at"]},"PublicCustomerListResponseDto":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/PublicCustomerResponseDto"}},"total":{"type":"number"},"limit":{"type":"number"},"offset":{"type":"number"}},"required":["data","total","limit","offset"]},"PublicCustomerEnvelopeDto":{"type":"object","properties":{"customer":{"$ref":"#/components/schemas/PublicCustomerResponseDto"}},"required":["customer"]},"PublicCustomerExternalIdDto":{"type":"object","properties":{"provider":{"type":"string","description":"Sistema externo dueño del identificador"},"external_id":{"type":"string","description":"Identificador del cliente en ese sistema"}},"required":["provider","external_id"]},"PublicCustomerCreateDto":{"type":"object","properties":{"name":{"type":"string","description":"Nombre del cliente"},"last_name":{"type":"string"},"email":{"type":"string"},"phone":{"type":"string"},"identification_number":{"type":"string","description":"Único por company cuando se informa"},"identification_type":{"type":"string","enum":["rut","dni","passport","other"]},"identification_country":{"type":"string","description":"Código de país ISO 3166-1 alpha-2"},"external_ids":{"type":"array","items":{"$ref":"#/components/schemas/PublicCustomerExternalIdDto"}},"custom_fields":{"type":"object","description":"Campos personalizados de la company"},"tags":{"description":"Ids de tags del CRM","type":"array","items":{"type":"string"}},"accepts_marketing":{"type":"boolean","default":false}},"required":["name"]},"PublicCustomerUpdateDto":{"type":"object","properties":{"name":{"type":"string"},"last_name":{"type":"string"},"email":{"type":"string"},"phone":{"type":"string"},"identification_number":{"type":"string"},"identification_type":{"type":"string","enum":["rut","dni","passport","other"]},"identification_country":{"type":"string"},"custom_fields":{"type":"object"},"tags":{"description":"Reemplaza la lista completa de tags","type":"array","items":{"type":"string"}},"accepts_marketing":{"type":"boolean"}}},"PublicTicketStageDto":{"type":"object","properties":{"stage_id":{"type":"string","description":"Etapa de destino dentro del pipeline"},"prioridad":{"type":"string","description":"Prioridad reportada al mover la etapa"},"contexto":{"type":"string","description":"Contexto del movimiento"},"problema":{"type":"string","description":"Problema detectado"},"recomendaciones":{"type":"string","description":"Recomendaciones para el operador"}},"required":["stage_id"]},"PublicTicketAssigneeDto":{"type":"object","properties":{"id":{"type":"string","description":"ObjectId del usuario"},"full_name":{"type":"string"},"email":{"type":"string"}},"required":["id"]},"PublicTicketTagDto":{"type":"object","properties":{"id":{"type":"string","description":"ObjectId del tag"},"name":{"type":"string"},"color":{"type":"string","description":"Color hex, ej. #1890ff"}},"required":["id","name"]},"PublicConversationSummaryDto":{"type":"object","properties":{"motivo":{"type":"string"},"estado":{"type":"string"},"proximos_pasos":{"type":"string"},"is_final":{"type":"boolean"}}},"PublicTicketResponseDto":{"type":"object","properties":{"_id":{"type":"string","description":"ObjectId del ticket"},"chat_user":{"type":"string","description":"ObjectId del chat user (contacto)"},"chat_user_name":{"type":"string"},"chat_user_avatar":{"type":"string"},"chat_user_channel":{"type":"string","description":"Canal de origen (whatsapp, instagram…)"},"chat_user_channel_id":{"type":"string"},"stage":{"description":"Etapa actual del pipeline. Ausente si el ticket no tiene una.","allOf":[{"$ref":"#/components/schemas/PublicTicketStageDto"}]},"is_closed":{"type":"boolean"},"resolution":{"type":"string","enum":["won","lost"]},"priority":{"type":"string","enum":["low","medium","high","urgent"]},"category":{"type":"string"},"assigned_to":{"$ref":"#/components/schemas/PublicTicketAssigneeDto"},"tags":{"type":"array","items":{"$ref":"#/components/schemas/PublicTicketTagDto"}},"custom_fields":{"type":"object"},"amount":{"type":"number"},"amount_currency":{"type":"string","description":"Moneda ISO 4217"},"amount_status":{"type":"string","enum":["estimated","confirmed"]},"conversation_summary":{"$ref":"#/components/schemas/PublicConversationSummaryDto"},"closed_at":{"type":"string","format":"date-time"},"created_at":{"type":"string","format":"date-time"},"updated_at":{"type":"string","format":"date-time"}},"required":["_id","chat_user","is_closed","priority","tags","custom_fields","created_at","updated_at"]},"PublicTicketListResponseDto":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/PublicTicketResponseDto"}},"total":{"type":"number"},"limit":{"type":"number"},"offset":{"type":"number"}},"required":["data","total","limit","offset"]},"PublicTicketEnvelopeDto":{"type":"object","properties":{"ticket":{"$ref":"#/components/schemas/PublicTicketResponseDto"}},"required":["ticket"]},"PublicTicketCreateDto":{"type":"object","properties":{"chat_user":{"type":"string","description":"Id del chat user (contacto) dueño del ticket"},"chat_user_name":{"type":"string"},"chat_user_avatar":{"type":"string"},"chat_user_channel":{"type":"string","description":"Canal de origen (whatsapp, instagram…)"},"chat_user_channel_id":{"type":"string"},"priority":{"type":"string","enum":["low","medium","high","urgent"],"default":"medium"},"category":{"type":"string"},"assigned_to":{"type":"string","description":"Id del usuario asignado"},"custom_fields":{"type":"object"},"amount":{"type":"number","description":"Valor monetario de la oportunidad"},"amount_currency":{"type":"string","description":"Moneda ISO 4217"},"amount_status":{"type":"string","enum":["estimated","confirmed"]},"stage":{"type":"string","description":"Etapa del pipeline. Si se omite, el ticket queda sin etapa asignada."}},"required":["chat_user"]},"PublicTicketUpdateDto":{"type":"object","properties":{"resolution":{"type":"string","enum":["won","lost"]},"is_closed":{"type":"boolean","description":"Cierra o reabre el ticket"},"priority":{"type":"string","enum":["low","medium","high","urgent"]},"category":{"type":"string"},"assigned_to":{"type":"string"},"custom_fields":{"type":"object"},"amount":{"type":"number"},"amount_currency":{"type":"string"},"amount_status":{"type":"string","enum":["estimated","confirmed"]},"tag_ids":{"description":"Reemplaza la lista completa de tags","type":"array","items":{"type":"string"}},"add_tag_ids":{"description":"Agrega tags sin tocar las existentes","type":"array","items":{"type":"string"}},"remove_tag_ids":{"description":"Quita tags sin tocar las demás","type":"array","items":{"type":"string"}},"conversation_summary":{"$ref":"#/components/schemas/PublicConversationSummaryDto"}}},"PublicTicketUpdateResponseDto":{"type":"object","properties":{"ticket":{"$ref":"#/components/schemas/PublicTicketResponseDto"},"just_closed":{"type":"boolean","description":"true sólo en la request que pasó el ticket de abierto a cerrado. Útil para disparar efectos una única vez."},"action":{"type":"string","description":"closed | updated"}},"required":["ticket","just_closed","action"]},"PublicTicketStageChangeResponseDto":{"type":"object","properties":{"ticket":{"$ref":"#/components/schemas/PublicTicketResponseDto"},"previous_stage_id":{"type":"string","description":"Etapa previa al movimiento"},"current_stage_id":{"type":"string","description":"Etapa resultante"},"stage_changed":{"type":"boolean","description":"false si el ticket ya estaba en esa etapa; la llamada es idempotente"},"is_human_stage":{"type":"boolean","description":"La etapa de destino espera intervención de una persona"},"stage_type":{"type":"string"},"next_stage_to_set":{"type":"string","description":"Presente cuando las reglas del pipeline piden avanzar de nuevo"}},"required":["ticket","current_stage_id","stage_changed"]},"PublicTaskResponseDto":{"type":"object","properties":{"_id":{"type":"string","description":"ObjectId de la tarea"},"title":{"type":"string"},"description":{"type":"string"},"status":{"type":"string","description":"Estado libre. Los valores del portal son pending, in_progress, completed y cancelled."},"priority":{"type":"string","enum":["low","medium","high","urgent"]},"assigned_to":{"type":"string","description":"ObjectId del usuario asignado"},"due_at":{"type":"string","format":"date-time"},"created_at":{"type":"string","format":"date-time"},"updated_at":{"type":"string","format":"date-time"}},"required":["_id","title","status","priority","created_at","updated_at"]},"PublicTaskListResponseDto":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/PublicTaskResponseDto"}},"total":{"type":"number"},"limit":{"type":"number"},"offset":{"type":"number"}},"required":["data","total","limit","offset"]},"PublicTaskEnvelopeDto":{"type":"object","properties":{"task":{"$ref":"#/components/schemas/PublicTaskResponseDto"}},"required":["task"]},"PublicTaskCreateDto":{"type":"object","properties":{"title":{"type":"string","description":"Título de la tarea"},"assigned_to":{"type":"string","description":"Id del usuario asignado"},"status":{"type":"string","description":"Estado libre. Los valores del portal son pending, in_progress, completed y cancelled.","default":"pending"},"priority":{"type":"string","enum":["low","medium","high","urgent"],"default":"medium"},"due_at":{"type":"string","description":"Vencimiento en ISO 8601"},"description":{"type":"string"}},"required":["title"]},"PublicTaskUpdateDto":{"type":"object","properties":{"title":{"type":"string"},"assigned_to":{"type":"string"},"status":{"type":"string"},"priority":{"type":"string","enum":["low","medium","high","urgent"]},"due_at":{"type":"string","description":"Vencimiento en ISO 8601"},"description":{"type":"string"}}},"PublicNoteResponseDto":{"type":"object","properties":{"_id":{"type":"string","description":"ObjectId de la nota"},"content":{"type":"string"},"type":{"type":"string","enum":["note","call","email","meeting"]},"chat_user":{"type":"string","description":"ObjectId del chat user (contacto)"},"ticket_id":{"type":"string","description":"ObjectId del ticket asociado"},"created_by":{"type":"string","description":"ObjectId del usuario que creó la nota"},"created_at":{"type":"string","format":"date-time"},"updated_at":{"type":"string","format":"date-time"}},"required":["_id","content","type","created_by","created_at","updated_at"]},"PublicNoteListResponseDto":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/PublicNoteResponseDto"}},"total":{"type":"number"},"limit":{"type":"number"},"offset":{"type":"number"}},"required":["data","total","limit","offset"]},"PublicNoteEnvelopeDto":{"type":"object","properties":{"note":{"$ref":"#/components/schemas/PublicNoteResponseDto"}},"required":["note"]},"PublicNoteCreateDto":{"type":"object","properties":{"content":{"type":"string","description":"Contenido de la nota"},"chat_user":{"type":"string","description":"Chat user (contacto) al que refiere"},"ticket_id":{"type":"string","description":"Ticket al que se adjunta la nota"},"type":{"type":"string","enum":["note","call","email","meeting"],"default":"note"}},"required":["content"]},"PublicNoteUpdateDto":{"type":"object","properties":{"content":{"type":"string"},"type":{"type":"string","enum":["note","call","email","meeting"]}}},"PublicWebhookEventCreateDto":{"type":"object","properties":{"type":{"type":"string","description":"Key del tipo de evento configurado en el portal, por ejemplo `custom.pedido_confirmado`."},"phone":{"type":"string","description":"Teléfono del contacto en formato canónico (sólo dígitos, con código de país y sin `+`). Alternativa a chat_user_id / customer_id / ticket_id."},"chat_user_id":{"type":"string","description":"ObjectId del contacto (chat user)"},"customer_id":{"type":"string","description":"ObjectId del cliente del CRM"},"ticket_id":{"type":"string","description":"ObjectId del ticket. Si viene, el evento se adjunta a ese ticket y no se resuelve el contacto."},"data":{"type":"object","description":"Valores de los campos asociados al tipo de evento, indexados por la key del campo. Los requeridos deben venir y cada valor debe respetar el tipo del campo.","additionalProperties":true},"summary":{"type":"string","description":"Texto corto del evento. Por defecto, el nombre del tipo."},"occurred_at":{"type":"string","description":"Momento en que ocurrió, ISO 8601. Por defecto, ahora.","format":"date-time"},"idempotency_key":{"type":"string","description":"Identificador único del evento en tu sistema. Reenviar el mismo valor no duplica el evento."}},"required":["type"]},"PublicEventResponseDto":{"type":"object","properties":{"_id":{"type":"string","description":"ObjectId del evento"},"type":{"type":"string","description":"Key del tipo de evento"},"ticket_id":{"type":"string","description":"ObjectId del ticket al que quedó adjunto"},"chat_user":{"type":"string","description":"ObjectId del contacto (chat user)"},"customer":{"type":"string","description":"ObjectId del cliente del CRM"},"summary":{"type":"string","description":"Texto corto del evento"},"data":{"type":"object","description":"Valores recibidos, tal cual quedaron registrados","additionalProperties":true},"occurred_at":{"type":"string","format":"date-time"},"idempotency_key":{"type":"string","description":"Clave de idempotencia recibida"}},"required":["_id","type","ticket_id","data","occurred_at"]},"PublicEventEnvelopeDto":{"type":"object","properties":{"event":{"$ref":"#/components/schemas/PublicEventResponseDto"},"duplicated":{"type":"boolean","description":"true cuando el `idempotency_key` ya existía: se devuelve el evento original y no se registra uno nuevo."}},"required":["event"]},"PublicProductVariantDto":{"type":"object","properties":{"external_id":{"type":"string"},"name":{"type":"string"},"price":{"type":"number"},"is_available":{"type":"boolean"}},"required":["external_id","name","price","is_available"]},"PublicProductResponseDto":{"type":"object","properties":{"_id":{"type":"string","description":"ObjectId del producto"},"name":{"type":"string"},"slug":{"type":"string"},"description":{"type":"string"},"sku":{"type":"string"},"price":{"type":"number"},"base_price":{"type":"number","description":"Precio base antes de variantes"},"currency":{"type":"string"},"stock":{"type":"number"},"stock_managed":{"type":"boolean","description":"true cuando el stock se descuenta al vender"},"type":{"type":"string","description":"Origen del producto"},"category_id":{"type":"string","description":"ObjectId de la categoría"},"external_id":{"type":"string","description":"Identificador en el sistema externo"},"variants":{"type":"array","items":{"$ref":"#/components/schemas/PublicProductVariantDto"}},"image_urls":{"type":"array","items":{"type":"string"}},"landing_url":{"type":"string"},"is_active":{"type":"boolean"},"created_at":{"type":"string","format":"date-time"},"updated_at":{"type":"string","format":"date-time"}},"required":["_id","name","price","currency","stock","stock_managed","type","variants","image_urls","is_active","created_at","updated_at"]},"PublicProductListResponseDto":{"type":"object","properties":{"total":{"type":"number"},"limit":{"type":"number"},"offset":{"type":"number"},"data":{"type":"array","items":{"$ref":"#/components/schemas/PublicProductResponseDto"}}},"required":["total","limit","offset","data"]},"PublicProductEnvelopeDto":{"type":"object","properties":{"product":{"$ref":"#/components/schemas/PublicProductResponseDto"}},"required":["product"]},"PublicCartItemDto":{"type":"object","properties":{"product_id":{"type":"string","description":"ObjectId del producto en Keebai"},"product_name":{"type":"string"},"sku":{"type":"string"},"quantity":{"type":"number"},"unit_price":{"type":"number"},"subtotal":{"type":"number"},"modifiers_summary":{"type":"string"},"comment":{"type":"string"}},"required":["product_name","quantity","unit_price","subtotal"]},"PublicCartResponseDto":{"type":"object","properties":{"_id":{"type":"string","description":"ObjectId del carrito"},"source":{"type":"string","description":"Origen del carrito"},"integration_id":{"type":"string","description":"ObjectId de la integración de origen"},"external_id":{"type":"string","description":"Identificador en el sistema externo"},"customer_id":{"type":"string","description":"ObjectId del contacto"},"customer_name":{"type":"string"},"customer_email":{"type":"string"},"customer_phone":{"type":"string"},"items":{"type":"array","items":{"$ref":"#/components/schemas/PublicCartItemDto"}},"total":{"type":"number"},"currency":{"type":"string"},"recovery_status":{"type":"string","description":"pending | contacted | recovered | discarded"},"recovery_url":{"type":"string","description":"URL para que el cliente retome el carrito"},"abandoned_at":{"type":"string","format":"date-time"},"completed_at":{"type":"string","format":"date-time"},"created_at":{"type":"string","format":"date-time"},"updated_at":{"type":"string","format":"date-time"}},"required":["_id","source","items","total","currency","recovery_status","created_at","updated_at"]},"PublicCartListResponseDto":{"type":"object","properties":{"total":{"type":"number"},"limit":{"type":"number"},"offset":{"type":"number"},"data":{"type":"array","items":{"$ref":"#/components/schemas/PublicCartResponseDto"}}},"required":["total","limit","offset","data"]},"PublicCartEnvelopeDto":{"type":"object","properties":{"cart":{"$ref":"#/components/schemas/PublicCartResponseDto"}},"required":["cart"]},"PublicAbandonedCartCustomerDto":{"type":"object","properties":{"name":{"type":"string","description":"Nombre del cliente"},"phone":{"type":"string","description":"Teléfono del cliente"},"email":{"type":"string","description":"Correo del cliente"},"external_id":{"type":"string","description":"Identificador del cliente en la tienda de origen"}}},"PublicAbandonedCartItemDto":{"type":"object","properties":{"name":{"type":"string","description":"Nombre del producto"},"quantity":{"type":"object","description":"Cantidad en el carrito"},"unit_price":{"type":"object","description":"Precio unitario"},"sku":{"type":"string"},"external_product_id":{"type":"string","description":"Id del producto en la tienda"},"external_variant_id":{"type":"string","description":"Id de la variante en la tienda"}},"required":["name","quantity"]},"PublicAbandonedCartDto":{"type":"object","properties":{"source":{"type":"string","description":"Plataforma de origen. Por defecto, la integración de ecommerce conectada."},"external_id":{"type":"string","description":"Identificador del checkout en la tienda"},"recovery_url":{"type":"string","description":"URL para que el cliente retome su compra"},"abandoned_at":{"type":"string","format":"date-time"},"customer":{"$ref":"#/components/schemas/PublicAbandonedCartCustomerDto"},"total":{"type":"object","description":"Total del carrito"},"currency":{"type":"string","description":"Moneda del carrito"},"items":{"type":"array","items":{"$ref":"#/components/schemas/PublicAbandonedCartItemDto"}}},"required":["external_id"]},"PublicAbandonedCartAckDto":{"type":"object","properties":{"stored":{"type":"boolean","description":"El carrito quedó registrado"},"external_id":{"type":"string","description":"Identificador del checkout en la tienda"},"provider":{"type":"string","description":"Plataforma de origen resuelta"},"integration_id":{"type":"string","description":"ObjectId de la integración de origen"},"items":{"type":"number","description":"Cantidad de líneas registradas"},"ticket_id":{"type":"string","description":"Ticket del contacto donde quedó registrado el carrito"},"chat_user_id":{"type":"string","description":"Contacto resuelto por teléfono"}},"required":["stored","external_id","provider","integration_id","items"]},"PublicSaleCustomerDto":{"type":"object","properties":{"name":{"type":"string"},"email":{"type":"string"},"phone":{"type":"string"},"chat_user_id":{"type":"string","description":"ObjectId del contacto"},"customer_id":{"type":"string","description":"ObjectId del cliente de CRM"}},"required":["name"]},"PublicSaleItemDto":{"type":"object","properties":{"kind":{"type":"string","description":"product | service | custom"},"name":{"type":"string"},"quantity":{"type":"number"},"unit_price":{"type":"number"},"subtotal":{"type":"number"}},"required":["kind"]},"PublicSaleAmountsDto":{"type":"object","properties":{"service_subtotal":{"type":"number"},"products_subtotal":{"type":"number"},"custom_subtotal":{"type":"number"},"net_subtotal":{"type":"number"},"tax_amount":{"type":"number"},"tip":{"type":"number"},"total":{"type":"number"}},"required":["service_subtotal","products_subtotal","custom_subtotal","net_subtotal","tax_amount","tip","total"]},"PublicSaleResponseDto":{"type":"object","properties":{"_id":{"type":"string","description":"ObjectId de la venta"},"sale_number":{"type":"number","description":"Correlativo legible de la venta"},"status":{"type":"string","enum":["completed","cancelled","refunded"]},"payment_status":{"type":"string","enum":["pending","paid","partially_paid","refunded"]},"currency":{"type":"string"},"customer":{"$ref":"#/components/schemas/PublicSaleCustomerDto"},"items":{"type":"array","items":{"$ref":"#/components/schemas/PublicSaleItemDto"}},"amounts":{"$ref":"#/components/schemas/PublicSaleAmountsDto"},"payment_method":{"type":"string"},"branch_id":{"type":"string","description":"Sucursal asociada"},"notes":{"type":"string"},"paid_at":{"type":"string","format":"date-time"},"cancelled_at":{"type":"string","format":"date-time"},"refunded_at":{"type":"string","format":"date-time"},"created_at":{"type":"string","format":"date-time"},"updated_at":{"type":"string","format":"date-time"}},"required":["_id","sale_number","status","payment_status","currency","customer","items","amounts","created_at","updated_at"]},"PublicSaleListResponseDto":{"type":"object","properties":{"total":{"type":"number"},"limit":{"type":"number"},"offset":{"type":"number"},"data":{"type":"array","items":{"$ref":"#/components/schemas/PublicSaleResponseDto"}}},"required":["total","limit","offset","data"]},"PublicSaleEnvelopeDto":{"type":"object","properties":{"sale":{"$ref":"#/components/schemas/PublicSaleResponseDto"}},"required":["sale"]},"PublicPointsRulesDto":{"type":"object","properties":{"points_per_currency_unit":{"type":"number","description":"Cuántos puntos otorga cada unidad de moneda gastada","example":1},"expiration_days":{"type":"number","description":"Días desde la inscripción tras los cuales el saldo se lee 0. Cero significa sin vencimiento","example":0}},"required":["points_per_currency_unit","expiration_days"]},"PublicStampsRulesDto":{"type":"object","properties":{"target":{"type":"number","description":"Sellos necesarios para el premio","example":10},"reward":{"type":"string","description":"Descripción libre del premio. No es una entidad, es texto","example":"Un café gratis"},"reset_on_redeem":{"type":"boolean","description":"Si los sellos vuelven a cero al canjear"}},"required":["target","reward","reset_on_redeem"]},"PublicTierLevelDto":{"type":"object","properties":{"key":{"type":"string","example":"gold"},"name":{"type":"string","example":"Oro"},"threshold":{"type":"number","description":"Puntos mínimos para alcanzar el nivel","example":5000},"benefits":{"example":["Envío gratis","Acceso anticipado"],"type":"array","items":{"type":"string"}}},"required":["key","name","threshold","benefits"]},"PublicTiersRulesDto":{"type":"object","properties":{"levels":{"type":"array","items":{"$ref":"#/components/schemas/PublicTierLevelDto"}}},"required":["levels"]},"PublicProgramRulesDto":{"type":"object","properties":{"points":{"$ref":"#/components/schemas/PublicPointsRulesDto"},"stamps":{"$ref":"#/components/schemas/PublicStampsRulesDto"},"tiers":{"$ref":"#/components/schemas/PublicTiersRulesDto"}}},"PublicProgramDto":{"type":"object","properties":{"_id":{"type":"string"},"name":{"type":"string","example":"Club Cafetería"},"type":{"type":"string","enum":["points","stamps","tiers"]},"status":{"type":"string","enum":["draft","active","archived"]},"description":{"type":"string","example":"Programa de sellos de la cafetería"},"rules":{"description":"Solo viene poblada la variante que corresponde al type","allOf":[{"$ref":"#/components/schemas/PublicProgramRulesDto"}]},"created_at":{"type":"string"},"updated_at":{"type":"string"}},"required":["_id","name","type","status","description","rules","created_at","updated_at"]},"PublicProgramListResponseDto":{"type":"object","properties":{"total":{"type":"number"},"limit":{"type":"number"},"offset":{"type":"number"},"data":{"type":"array","items":{"$ref":"#/components/schemas/PublicProgramDto"}}},"required":["total","limit","offset","data"]},"PublicProgramEnvelopeDto":{"type":"object","properties":{"program":{"$ref":"#/components/schemas/PublicProgramDto"}},"required":["program"]},"PublicTemplateListResponseDto":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/PublicTemplateDto"}},"total":{"type":"number"}},"required":["data","total"]},"PublicTemplateEnvelopeDto":{"type":"object","properties":{"template":{"$ref":"#/components/schemas/PublicTemplateDto"}},"required":["template"]},"PublicMembershipCustomerViewDto":{"type":"object","properties":{"id":{"type":"string","example":"crm-8842"},"name":{"type":"string","example":"Camila Rojas"},"phone":{"type":"string","example":"+56912345678"},"email":{"type":"string","example":"camila@ejemplo.cl"}},"required":["id"]},"PublicMembershipDto":{"type":"object","properties":{"_id":{"type":"string"},"program_id":{"type":"string"},"customer":{"$ref":"#/components/schemas/PublicMembershipCustomerViewDto"},"serial_number":{"type":"string","description":"Identificador del pase en Apple y Google. Es lo que codifica el código de barras por defecto"},"balance_points":{"type":"number","description":"Saldo de puntos. Si el programa vence puntos y ya pasó el plazo, se lee 0 sin que el ledger cambie","example":1240},"stamps_count":{"type":"number","example":7},"tier":{"type":"string","description":"Clave del nivel alcanzado. Vacío si el programa no es de tiers","example":"gold"},"status":{"type":"string","enum":["active","suspended","revoked"]},"enrolled_at":{"type":"string"},"created_at":{"type":"string"},"updated_at":{"type":"string"}},"required":["_id","program_id","serial_number","balance_points","stamps_count","tier","status","enrolled_at","created_at","updated_at"]},"PublicMembershipListResponseDto":{"type":"object","properties":{"total":{"type":"number"},"limit":{"type":"number"},"offset":{"type":"number"},"data":{"type":"array","items":{"$ref":"#/components/schemas/PublicMembershipDto"}}},"required":["total","limit","offset","data"]},"PublicMembershipEnvelopeDto":{"type":"object","properties":{"membership":{"$ref":"#/components/schemas/PublicMembershipDto"}},"required":["membership"]},"PublicMembershipCustomerDto":{"type":"object","properties":{"id":{"type":"string","description":"ObjectId de un cliente ya existente en el CRM. Si lo omitís, el cliente se busca o se crea con el nombre y el teléfono o correo que mandes","example":"665f1c2a9b4e5d0012a3b4c5"},"name":{"type":"string","example":"Camila Rojas"},"last_name":{"type":"string","example":"Rojas"},"phone":{"type":"string","description":"Obligatorio si no envías ni id ni email","example":"+56912345678"},"email":{"type":"string","example":"camila@ejemplo.cl"},"accepts_marketing":{"type":"boolean","description":"Consentimiento explícito para comunicaciones de marketing"}},"required":["name"]},"PublicMembershipEnrollDto":{"type":"object","properties":{"program_id":{"type":"string","description":"ObjectId del programa al que se inscribe"},"customer":{"description":"Datos del cliente. Toda membresía queda ligada a un cliente del CRM: se busca uno existente y, si no está, se crea","allOf":[{"$ref":"#/components/schemas/PublicMembershipCustomerDto"}]}},"required":["program_id","customer"]},"PublicLedgerEntryDto":{"type":"object","properties":{"_id":{"type":"string"},"membership_id":{"type":"string"},"program_id":{"type":"string"},"kind":{"type":"string","enum":["earn","redeem","adjust"]},"metric":{"type":"string","enum":["points","stamps"],"description":"Lo decide el tipo del programa, no el request"},"amount":{"type":"number","description":"Movimiento con signo: negativo en un canje","example":-50},"balance_after":{"type":"number","description":"Saldo resultante después del movimiento","example":1190},"source":{"type":"string","example":"pos-sucursal-centro"},"ref":{"type":"string","example":"boleta-99120"},"note":{"type":"string"},"created_at":{"type":"string"}},"required":["_id","membership_id","program_id","kind","metric","amount","balance_after","source","ref","note","created_at"]},"PublicLedgerListResponseDto":{"type":"object","properties":{"total":{"type":"number"},"limit":{"type":"number"},"offset":{"type":"number"},"data":{"type":"array","items":{"$ref":"#/components/schemas/PublicLedgerEntryDto"}}},"required":["total","limit","offset","data"]},"PublicLedgerRecordDto":{"type":"object","properties":{"kind":{"type":"string","enum":["earn","redeem","adjust"],"description":"earn suma, redeem resta, adjust respeta el signo de amount para correcciones"},"amount":{"type":"number","description":"Magnitud del movimiento. En earn y redeem se toma el valor absoluto; en adjust se respeta el signo","example":120},"source":{"type":"string","description":"De dónde vino el movimiento. Por defecto manual","example":"pos-sucursal-centro"},"ref":{"type":"string","description":"Referencia externa, por ejemplo el número de boleta","example":"boleta-99120"},"note":{"type":"string","example":"Compra de 12.000 en tienda"}},"required":["kind","amount"]},"PublicLedgerEntryEnvelopeDto":{"type":"object","properties":{"entry":{"$ref":"#/components/schemas/PublicLedgerEntryDto"}},"required":["entry"]},"PublicGooglePassDto":{"type":"object","properties":{"save_url":{"type":"string","description":"Link de Google Wallet para agregar el pase. Se le manda al cliente tal cual"},"provider_ref":{"type":"string","description":"Id del objeto en Google Wallet"}},"required":["save_url","provider_ref"]},"PublicApplePassLinkDto":{"type":"object","properties":{"download_url":{"type":"string","description":"Link público de descarga del .pkpass. Sirve para QR, WhatsApp o copiar y pegar"}},"required":["download_url"]},"PublicPassNotifyDto":{"type":"object","properties":{"header":{"type":"string","description":"Título del mensaje que ve el cliente en la wallet","example":"Te quedan 3 sellos"},"body":{"type":"string","description":"Cuerpo del mensaje","example":"Junta 3 sellos más y tu próximo café va por la casa."},"link_url":{"type":"string","description":"URL https a la que lleva el botón del mensaje","example":"https://tutienda.cl/promos"},"link_label":{"type":"string","example":"Ver promos"}},"required":["header","body"]},"PublicPassNotifyResultDto":{"type":"object","properties":{"notified":{"type":"number","description":"Dispositivos a los que llegó el mensaje","example":2},"skipped":{"type":"number","description":"Dispositivos omitidos por no tener un pase registrado","example":0}},"required":["notified","skipped"]},"PublicPassNotificationDto":{"type":"object","properties":{"_id":{"type":"string"},"header":{"type":"string"},"body":{"type":"string"},"link_url":{"type":"string"},"link_label":{"type":"string"},"channels":{"example":["google","apple"],"type":"array","items":{"type":"string"}},"delivered":{"type":"number","example":2},"created_at":{"type":"string"}},"required":["_id","header","body","link_url","link_label","channels","delivered","created_at"]},"PublicPassNotificationListResponseDto":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/PublicPassNotificationDto"}},"total":{"type":"number"}},"required":["data","total"]},"PublicAgentDto":{"type":"object","properties":{"id":{"type":"string"},"name":{"type":"string"},"description":{"type":"string"},"avatar_url":{"type":"string"},"model":{"type":"string"},"voice_response_enabled":{"type":"boolean","description":"Indica si la respuesta de voz está habilitada."},"created_at":{"type":"string"}},"required":["id","name","model","voice_response_enabled"]},"PaginatedAgentsResponse":{"type":"object","properties":{"items":{"type":"array","items":{"$ref":"#/components/schemas/PublicAgentDto"}},"page":{"type":"number"},"limit":{"type":"number"},"total":{"type":"number"}},"required":["items","page","limit","total"]},"PublicPromptTypeDto":{"type":"object","properties":{"kind":{"type":"string","enum":["section","goal","channel"]},"type":{"type":"string","example":"business_context"},"label":{"type":"string","example":"Contexto del negocio"},"description":{"type":"string"},"tip":{"type":"string","description":"Como se escribe esta seccion."},"placeholder":{"type":"string"},"toolkits":{"description":"Solo los objetivos: que herramientas enciende.","type":"array","items":{"type":"string"}},"channels":{"type":"array","items":{"type":"string"}},"goals":{"type":"array","items":{"type":"string"}},"order":{"type":"number"}},"required":["kind","type","label","description","tip","placeholder","toolkits","channels","goals","order"]},"PublicPromptTypeListResponseDto":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/PublicPromptTypeDto"}},"total":{"type":"number"}},"required":["data","total"]},"PublicAgentEnvelopeDto":{"type":"object","properties":{"agent":{"$ref":"#/components/schemas/PublicAgentDto"}},"required":["agent"]},"PublicAgentGoalDto":{"type":"object","properties":{"type":{"type":"string","description":"Tipo de objetivo, del catalogo (`GET /v1/prompt-types?kind=goal`). Decide que herramientas se encienden.","example":"appointment_management"},"instructions":{"type":"string","maxLength":600,"description":"Solo para el objetivo `custom`: que tiene que lograr el agente, escrito por el negocio."}},"required":["type"]},"PublicPromptDto":{"type":"object","properties":{"section":{"type":"string","description":"Tipo de seccion, del catalogo. Una seccion desconocida devuelve 404 PROMPT_SECTION_NOT_FOUND.","example":"business_context"},"label":{"type":"string","maxLength":150,"description":"Titulo propio de la seccion. Sin esto se usa el del catalogo."},"markdown":{"type":"string","description":"El texto de la seccion, en markdown.","example":"# Quienes somos\n\nBarberia en Providencia, atendemos con hora."}},"required":["section","markdown"]},"PublicAgentCreateDto":{"type":"object","properties":{"name":{"type":"string","maxLength":150,"example":"Agente de ventas"},"description":{"type":"string","maxLength":500},"model":{"type":"string","description":"Identificador del modelo. Se valida contra los modelos soportados; uno desconocido devuelve 400 INVALID_MODEL.","example":"openai/gpt-5"},"language":{"type":"string","description":"Locale del agente. El pais importa: `es-CL` y `es-MX` no conjugan igual.","example":"es-CL"},"timezone":{"type":"string","example":"America/Santiago"},"goal":{"$ref":"#/components/schemas/PublicAgentGoalDto"},"prompts":{"maxItems":20,"description":"Las secciones del prompt. Se pueden mandar aca al crear, o una por una con `PUT /v1/agents/{id}/prompts/{section}`.","type":"array","items":{"$ref":"#/components/schemas/PublicPromptDto"}},"channels":{"maxItems":10,"description":"Canales por los que atiende, del catalogo (`GET /v1/prompt-types?kind=channel`).","example":["whatsapp","webchat"],"type":"array","items":{"type":"string"}},"reengagement":{"type":"object","description":"Reenganche: cuantas veces vuelve sobre una conversacion enfriada y cada cuanto.","example":{"enabled":true,"max_attempts":2,"delay_minutes":1440}},"tools":{"maxItems":100,"description":"ObjectIds de herramientas (`GET /v1/tools`) que puede usar.","type":"array","items":{"type":"string"}},"knowledge_node_ids":{"maxItems":200,"description":"ObjectIds de nodos de la base de conocimiento a asignar.","type":"array","items":{"type":"string"}},"stages":{"maxItems":20,"description":"Etapas del embudo, por NOMBRE y en orden. Se crea un pipeline en el CRM con el nombre del agente y esas etapas, y el agente queda habilitado para mover tickets solo entre ellas. Sin esto no se crea ningun pipeline y el agente no mueve tickets.","example":["Nuevo","Contactado","Agendado","Cerrado"],"type":"array","items":{"type":"string"}}},"required":["name"]},"PublicAgentUpdateDto":{"type":"object","properties":{"name":{"type":"string","maxLength":150},"description":{"type":"string","maxLength":500},"model":{"type":"string","description":"Identificador del modelo. Se valida solo si cambia respecto del actual."},"language":{"type":"string","example":"es-CL"},"timezone":{"type":"string","example":"America/Santiago"},"goal":{"$ref":"#/components/schemas/PublicAgentGoalDto"},"prompts":{"maxItems":20,"description":"REEMPLAZA todas las secciones. Para cambiar una sola sin tocar el resto, usar `PUT /v1/agents/{id}/prompts/{section}`.","type":"array","items":{"$ref":"#/components/schemas/PublicPromptDto"}},"channels":{"maxItems":10,"type":"array","items":{"type":"string"}},"reengagement":{"type":"object"},"tools":{"maxItems":100,"type":"array","items":{"type":"string"}},"knowledge_node_ids":{"maxItems":200,"type":"array","items":{"type":"string"}},"is_active":{"type":"boolean"}}},"PublicAgentToolsDto":{"type":"object","properties":{"tools":{"maxItems":100,"description":"ObjectIds de herramientas. Reemplaza la lista completa.","type":"array","items":{"type":"string"}}},"required":["tools"]},"PublicAgentKnowledgeDto":{"type":"object","properties":{"knowledge_node_ids":{"maxItems":200,"description":"ObjectIds de nodos de conocimiento. Reemplaza la lista completa.","type":"array","items":{"type":"string"}}},"required":["knowledge_node_ids"]},"PublicAgentChannelsDto":{"type":"object","properties":{"channels":{"maxItems":10,"description":"Tipos de canal del catalogo. Reemplaza la lista completa. Uno que no este en el catalogo devuelve 404.","example":["whatsapp","webchat"],"type":"array","items":{"type":"string"}}},"required":["channels"]},"PublicReengagementDto":{"type":"object","properties":{"max_attempts":{"type":"number","minimum":0,"maximum":20,"description":"Cuantas veces vuelve sobre una conversacion que se enfrio. **0 lo apaga**: no hay un `enabled` aparte porque dos formas de apagar lo mismo terminan contradiciendose.","example":2},"first_wait_hours":{"type":"number","description":"Horas desde que la conversacion se enfria hasta el primer intento.","example":3},"between_hours":{"type":"number","description":"Horas entre un intento y el siguiente.","example":24},"allow_template":{"type":"boolean","description":"Si puede reabrir una conversacion de WhatsApp con una plantilla aprobada."},"template_name":{"type":"string","description":"Nombre de la plantilla aprobada a usar."},"template_language":{"type":"string","example":"es"},"allow_call":{"type":"boolean","description":"Si un intento puede ser una llamada en vez de un mensaje."},"conduct":{"type":"string","maxLength":500,"description":"Instruccion del negocio para el turno de reactivacion, si quiere acotarlo. Que hacer en cada intento lo decide el agente con la conversacion a la vista; esto lo encuadra."}},"required":["max_attempts"]},"PublicAgentQueryDto":{"type":"object","properties":{"message":{"type":"string","maxLength":2000,"description":"Lo que le escribiria un cliente.","example":"hola, tienen hora para mañana?"},"session_id":{"type":"string","description":"Para seguir una conversacion de prueba ya empezada. Solo acepta un id devuelto por este mismo endpoint; sin esto se abre una nueva."},"channel_type":{"type":"string","description":"Canal a simular. Cambia el largo y el formato de la respuesta: un correo no se escribe como un WhatsApp.","example":"whatsapp"}},"required":["message"]},"PublicAgentQueryResponseDto":{"type":"object","properties":{"session_id":{"type":"string","description":"Identificador de esta conversacion de prueba. Mandalo de vuelta para seguirla."},"status":{"type":"string","example":"completed"},"reply":{"description":"Los mensajes de texto que respondio, en orden. Un agente de WhatsApp suele responder en varios cortos.","type":"array","items":{"type":"string"}},"tools_called":{"description":"Las herramientas que llamo durante el turno.","type":"array","items":{"type":"string"}},"tools_simulated":{"description":"Cuales de esas se simularon. Todas las que escriben lo estan: por esta ruta el agente no toca los datos del negocio.","type":"array","items":{"type":"string"}},"duration_ms":{"type":"number"}},"required":["session_id","status","reply","tools_called","tools_simulated"]},"PublicPromptListResponseDto":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/PublicPromptDto"}},"total":{"type":"number"}},"required":["data","total"]},"PublicPromptWriteDto":{"type":"object","properties":{"label":{"type":"string","maxLength":150},"markdown":{"type":"string","description":"El texto completo de la seccion, en markdown."}},"required":["markdown"]},"PublicPromptVersionDto":{"type":"object","properties":{"_id":{"type":"string"},"agent_id":{"type":"string"},"section":{"type":"string","example":"business_context"},"version_number":{"type":"number","description":"Correlativo dentro de la seccion; el mayor es el vigente."},"markdown":{"type":"string"},"label":{"type":"object","nullable":true},"created_by":{"type":"object","nullable":true,"description":"Quien la guardo."},"restored_from":{"type":"object","nullable":true,"description":"Version de la que se copio, cuando esta nacio de una restauracion. Restaurar no muta: crea una version nueva."},"created_at":{"type":"string"}},"required":["_id","agent_id","section","version_number","markdown","label","created_by","restored_from","created_at"]},"PublicPromptVersionListResponseDto":{"type":"object","properties":{"limit":{"type":"number"},"offset":{"type":"number"},"has_more":{"type":"boolean","description":"Si hay al menos una pagina mas despues de esta."},"data":{"type":"array","items":{"$ref":"#/components/schemas/PublicPromptVersionDto"}}},"required":["limit","offset","has_more","data"]},"PublicToolParamResponseDto":{"type":"object","properties":{"name":{"type":"string"},"description":{"type":"string"},"type":{"type":"string","enum":["string","number","boolean","array","object"]},"required":{"type":"boolean"}},"required":["name","type","required"]},"PublicWebhookContextResponseDto":{"type":"object","properties":{"url":{"type":"string"},"method":{"type":"string","enum":["GET","POST","PUT","PATCH","DELETE"]},"headers":{"type":"object","additionalProperties":{"type":"string"},"description":"Headers configurados. Las claves se muestran y los valores vuelven siempre como '***'.","example":{"Authorization":"***"}},"params":{"type":"object","additionalProperties":{"type":"string"},"description":"Query string configurada, con los valores enmascarados igual que headers."},"body":{"type":"object","additionalProperties":true,"description":"Body de la request. No se enmascara: es la plantilla que rellena el modelo."},"timeout":{"type":"number"},"response_path":{"type":"string"}},"required":["url","method","headers","params","timeout"]},"PublicToolDto":{"type":"object","properties":{"_id":{"type":"string"},"name":{"type":"string"},"display_name":{"type":"string"},"description":{"type":"string"},"type":{"type":"string","example":"webhook"},"tool_params":{"type":"array","items":{"$ref":"#/components/schemas/PublicToolParamResponseDto"}},"context":{"$ref":"#/components/schemas/PublicWebhookContextResponseDto"},"tags":{"type":"array","items":{"type":"string"}},"is_active":{"type":"boolean"},"created_at":{"type":"string"},"updated_at":{"type":"string"}},"required":["_id","name","display_name","description","type","tool_params","context","tags","is_active","created_at","updated_at"]},"PublicToolListResponseDto":{"type":"object","properties":{"total":{"type":"number"},"limit":{"type":"number"},"offset":{"type":"number"},"data":{"type":"array","items":{"$ref":"#/components/schemas/PublicToolDto"}}},"required":["total","limit","offset","data"]},"PublicToolEnvelopeDto":{"type":"object","properties":{"tool":{"$ref":"#/components/schemas/PublicToolDto"}},"required":["tool"]},"PublicWebhookContextDto":{"type":"object","properties":{"url":{"type":"string","description":"URL https publica. Se rechazan loopback, rangos privados, hosts internos del cluster y placeholders en el host.","example":"https://erp.example.com/stock"},"method":{"type":"string","enum":["GET","POST","PUT","PATCH","DELETE"],"default":"POST"},"headers":{"type":"object","description":"Headers de la request. Los valores son de solo escritura: en lectura vuelven enmascarados. Omitir el campo en un update preserva los guardados; mandarlo los reemplaza completos.","example":{"Authorization":"Bearer sk_live_xxx"}},"params":{"type":"object","description":"Query string de la request. Mismo trato que headers: enmascarado en lectura."},"body":{"type":"object","description":"Body de la request. Acepta placeholders '{{arg}}' que se reemplazan con los argumentos del modelo.","example":{"sku":"{{sku}}"}},"timeout":{"type":"number","default":30,"minimum":1,"maximum":30,"description":"Segundos de espera antes de abortar la llamada."},"response_path":{"type":"string","maxLength":200,"description":"Ruta dentro del JSON de respuesta a extraer, por ejemplo 'data.items'. Sin esto se entrega la respuesta completa."}},"required":["url"]},"PublicToolParamDto":{"type":"object","properties":{"name":{"type":"string","maxLength":100,"description":"Nombre del argumento tal como lo va a pasar el modelo."},"description":{"type":"string","maxLength":500,"description":"Que significa el argumento. El modelo lee esto para decidir que mandar."},"type":{"type":"string","enum":["string","number","boolean","array","object"],"default":"string"},"required":{"type":"boolean","default":true}},"required":["name"]},"PublicToolCreateDto":{"type":"object","properties":{"name":{"type":"string","maxLength":100,"description":"Nombre tecnico, unico por company. Es el nombre con el que el modelo invoca la herramienta.","example":"consultar_stock"},"display_name":{"type":"string","maxLength":200,"example":"Consultar stock"},"description":{"type":"string","maxLength":1000,"description":"Para que sirve la herramienta. Es lo que lee el modelo para decidir cuando llamarla.","example":"Devuelve el stock disponible de un SKU en el ERP."},"context":{"$ref":"#/components/schemas/PublicWebhookContextDto"},"tool_params":{"maxItems":30,"type":"array","items":{"$ref":"#/components/schemas/PublicToolParamDto"}},"tags":{"maxItems":20,"type":"array","items":{"type":"string"}},"is_active":{"type":"boolean","default":true}},"required":["name","display_name","description","context"]},"PublicToolUpdateDto":{"type":"object","properties":{"name":{"type":"string","maxLength":100},"display_name":{"type":"string","maxLength":200},"description":{"type":"string","maxLength":1000},"context":{"$ref":"#/components/schemas/PublicWebhookContextDto"},"tool_params":{"maxItems":30,"type":"array","items":{"$ref":"#/components/schemas/PublicToolParamDto"}},"tags":{"maxItems":20,"type":"array","items":{"type":"string"}},"is_active":{"type":"boolean"}}},"PublicBranchResponseDto":{"type":"object","properties":{"id":{"type":"string","description":"ObjectId de la sucursal"},"name":{"type":"string"},"display_name":{"type":"string"},"description":{"type":"string"},"address":{"type":"object"},"contact":{"type":"object"},"timezone":{"type":"string","description":"IANA, ej. America/Santiago"},"status":{"type":"string"}},"required":["id","name"]},"PublicBranchListResponseDto":{"type":"object","properties":{"items":{"type":"array","items":{"$ref":"#/components/schemas/PublicBranchResponseDto"}},"total":{"type":"number"},"skip":{"type":"number"},"limit":{"type":"number"}},"required":["items","total","skip","limit"]},"PublicServiceResponseDto":{"type":"object","properties":{"id":{"type":"string","description":"ObjectId del servicio"},"name":{"type":"string"},"description":{"type":"string"},"duration_minutes":{"type":"number","description":"Duración en minutos"},"slot_interval_minutes":{"type":"number","description":"Granularidad de los slots, en minutos"},"price":{"type":"object","description":"{ amount, currency }"},"branches":{"description":"Sucursales donde se presta","type":"array","items":{"type":"string"}},"category":{"type":"string"},"color":{"type":"string"},"status":{"type":"string","description":"active | inactive"}},"required":["id","name","duration_minutes","status"]},"PublicProfessionalResponseDto":{"type":"object","properties":{"id":{"type":"string","description":"ObjectId del profesional"},"name":{"type":"string"},"last_name":{"type":"string"},"specialties":{"type":"array","items":{"type":"string"}},"cargo":{"type":"string"},"avatar":{"type":"string"},"branches":{"description":"Sucursales donde atiende","type":"array","items":{"type":"string"}},"status":{"type":"string","description":"active | inactive | on_leave"}},"required":["id","name"]},"PublicAvailabilityTimeSlotDto":{"type":"object","properties":{"time":{"type":"string","description":"Hora de inicio (HH:mm) en la zona de la sucursal"}},"required":["time"]},"PublicProfessionalAvailabilityDto":{"type":"object","properties":{"id":{"type":"string","description":"Id del profesional"},"name":{"type":"string"},"last_name":{"type":"string"},"timeSlots":{"type":"array","items":{"$ref":"#/components/schemas/PublicAvailabilityTimeSlotDto"}}},"required":["id","name","timeSlots"]},"PublicAvailabilityResponseDto":{"type":"object","properties":{"results":{"type":"array","items":{"$ref":"#/components/schemas/PublicProfessionalAvailabilityDto"}}},"required":["results"]},"PublicAvailabilityDayDto":{"type":"object","properties":{"date":{"type":"string","description":"YYYY-MM-DD"},"results":{"type":"array","items":{"$ref":"#/components/schemas/PublicProfessionalAvailabilityDto"}}},"required":["date","results"]},"PublicAvailabilityRangeResponseDto":{"type":"object","properties":{"from":{"type":"string","description":"YYYY-MM-DD"},"to":{"type":"string","description":"YYYY-MM-DD"},"days":{"type":"array","items":{"$ref":"#/components/schemas/PublicAvailabilityDayDto"}}},"required":["from","to","days"]},"PublicAvailabilityProfessionalRefDto":{"type":"object","properties":{"id":{"type":"string","description":"Id del profesional"},"name":{"type":"string"},"last_name":{"type":"string"}},"required":["id","name"]},"PublicNextSlotDto":{"type":"object","properties":{"date":{"type":"string","description":"YYYY-MM-DD"},"time":{"type":"string","description":"Hora de inicio (HH:mm) en la zona de la sucursal"}},"required":["date","time"]},"PublicNextAvailabilityItemDto":{"type":"object","properties":{"professional":{"$ref":"#/components/schemas/PublicAvailabilityProfessionalRefDto"},"slots":{"type":"array","items":{"$ref":"#/components/schemas/PublicNextSlotDto"}}},"required":["professional","slots"]},"PublicNextAvailabilityResponseDto":{"type":"object","properties":{"results":{"type":"array","items":{"$ref":"#/components/schemas/PublicNextAvailabilityItemDto"}}},"required":["results"]},"PublicAppointmentRefDto":{"type":"object","properties":{"id":{"type":"string"},"display_name":{"type":"string"}},"required":["id"]},"PublicAppointmentProfessionalDto":{"type":"object","properties":{"id":{"type":"string"},"name":{"type":"string"},"last_name":{"type":"string"},"specialty":{"type":"string"}},"required":["id"]},"PublicAppointmentCustomerDto":{"type":"object","properties":{"name":{"type":"string"},"last_name":{"type":"string"},"email":{"type":"string"},"phone":{"type":"string"}},"required":["name"]},"PublicAppointmentDatesDto":{"type":"object","properties":{"start":{"type":"string","format":"date-time"},"end":{"type":"string","format":"date-time"},"time_zone":{"type":"string","description":"IANA, ej. America/Santiago"}},"required":["start","end"]},"PublicAppointmentResponseDto":{"type":"object","properties":{"_id":{"type":"string","description":"Id de la cita"},"appointment_number":{"type":"number","description":"Correlativo legible de la cita"},"branch":{"$ref":"#/components/schemas/PublicAppointmentRefDto"},"service":{"$ref":"#/components/schemas/PublicAppointmentRefDto"},"professional":{"$ref":"#/components/schemas/PublicAppointmentProfessionalDto"},"customer":{"$ref":"#/components/schemas/PublicAppointmentCustomerDto"},"dates":{"$ref":"#/components/schemas/PublicAppointmentDatesDto"},"appointment_type":{"type":"string","description":"online | in-person"},"status":{"type":"string","description":"pending | confirmed | cancelled | …"},"payment_status":{"type":"string","description":"Estado del pago"},"notes":{"type":"string"},"price":{"type":"number"},"currency":{"type":"string","description":"Moneda ISO 4217"},"paid":{"type":"boolean"},"cancelled_at":{"type":"string","format":"date-time"},"cancellation_reason":{"type":"string"},"created_at":{"type":"string","format":"date-time"},"updated_at":{"type":"string","format":"date-time"}},"required":["_id","branch","dates","status"]},"PublicCustomerDto":{"type":"object","properties":{"name":{"type":"string"},"last_name":{"type":"string"},"email":{"type":"string"},"phone":{"type":"string"}},"required":["name"]},"PublicAppointmentCreateDto":{"type":"object","properties":{"branch_id":{"type":"string"},"service_id":{"type":"string"},"professional_id":{"type":"string"},"date":{"type":"string","description":"Fecha (YYYY-MM-DD)"},"start_time":{"type":"string","description":"Hora inicio (HH:mm)"},"end_time":{"type":"string","description":"Hora fin (HH:mm). Si se omite, scheduling la calcula desde la duración del servicio."},"customer":{"$ref":"#/components/schemas/PublicCustomerDto"},"notes":{"type":"string"},"price":{"type":"number"},"currency":{"type":"string"}},"required":["branch_id","service_id","date","start_time","customer"]},"CancelAppointmentDto":{"type":"object","properties":{"reason":{"type":"string","description":"Motivo de cancelación"}}},"CustomerBookingCreateDto":{"type":"object","properties":{}},"CustomerBookingModifyDto":{"type":"object","properties":{}},"CustomerBookingCancelDto":{"type":"object","properties":{}},"CustomerBookingPaymentLinkDto":{"type":"object","properties":{}},"TenantCreateDto":{"type":"object","properties":{"name":{"type":"string","description":"Nombre legible del tenant (cliente final del developer). Ej: \"ACME Corp\"."},"external_id":{"type":"string","description":"ID externo del tenant en el sistema del developer. Único por company. Si ya existe se devuelve el tenant existente (idempotencia)."},"metadata":{"type":"object","description":"Metadata libre."}},"required":["name"]},"PublicTenantResponseDto":{"type":"object","properties":{"id":{"type":"string","description":"ObjectId del tenant"},"name":{"type":"string"},"external_id":{"type":"object","nullable":true,"description":"Identificador propio que enviaste al crear el tenant"},"metadata":{"type":"object"},"whatsapp_configs_count":{"type":"number","description":"Canales de WhatsApp asociados"},"setup_links_count":{"type":"number","description":"Setup links vigentes"},"created_at":{"type":"string","format":"date-time"},"updated_at":{"type":"string","format":"date-time"}},"required":["id","name","external_id","metadata","created_at","updated_at"]},"PublicTenantListResponseDto":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/PublicTenantResponseDto"}},"next_cursor":{"type":"object","nullable":true,"description":"Cursor para la página siguiente. null cuando no hay más."}},"required":["data","next_cursor"]},"TenantUpdateDto":{"type":"object","properties":{"name":{"type":"string"},"external_id":{"type":"object","description":"Pasar null para limpiar el external_id existente."},"metadata":{"type":"object"}}},"PublicTenantWhatsappConfigDto":{"type":"object","properties":{"id":{"type":"string","description":"ObjectId del canal"},"name":{"type":"string"},"phone_number_id":{"type":"string","description":"phone_number_id emitido por Meta"},"phone_number":{"type":"string"},"is_active":{"type":"boolean"}},"required":["id"]},"PublicTenantWhatsappConfigListResponseDto":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/PublicTenantWhatsappConfigDto"}}},"required":["data"]},"SetupLinkThemeDto":{"type":"object","properties":{"primary":{"type":"string"},"primary_foreground":{"type":"string"},"background":{"type":"string"},"text":{"type":"string"},"muted":{"type":"string"},"muted_text":{"type":"string"},"card":{"type":"string"},"border":{"type":"string"},"destructive":{"type":"string"},"destructive_foreground":{"type":"string"},"secondary":{"type":"string"},"secondary_foreground":{"type":"string"}}},"SetupLinkCreateDto":{"type":"object","properties":{"language":{"type":"object","description":"Código de idioma BCP-47. null/omitido = se usa el idioma del browser del cliente final."},"success_redirect_url":{"type":"object"},"failure_redirect_url":{"type":"object"},"allowed_modes":{"type":"array","description":"Modos de conexión permitidos.","items":{"type":"string","enum":["embedded_signup","coexistence"]}},"provision_phone_number":{"type":"boolean","description":"Si true, intentar provisión automática de número (fuera de scope inicial; reservado).","default":false},"theme":{"$ref":"#/components/schemas/SetupLinkThemeDto"}}},"PublicSetupLinkResponseDto":{"type":"object","properties":{"id":{"type":"string"},"dev_tenant_id":{"type":"string"},"token":{"type":"string","description":"Token del link. Es la credencial: tratalo como secreto."},"url":{"type":"string","description":"URL lista para entregar al tenant"},"language":{"type":"object","nullable":true},"success_redirect_url":{"type":"object","nullable":true},"failure_redirect_url":{"type":"object","nullable":true},"allowed_modes":{"type":"array","items":{"type":"string"}},"provision_phone_number":{"type":"boolean"},"theme":{"type":"object","nullable":true},"last_used_at":{"type":"object","format":"date-time","nullable":true},"revoked_at":{"type":"object","format":"date-time","nullable":true},"created_at":{"type":"string","format":"date-time"},"updated_at":{"type":"string","format":"date-time"}},"required":["id","dev_tenant_id","token","url","language","success_redirect_url","failure_redirect_url","allowed_modes","provision_phone_number","theme","last_used_at","revoked_at","created_at","updated_at"]},"PublicSetupLinkListResponseDto":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/PublicSetupLinkResponseDto"}}},"required":["data"]},"SetupLinkUpdateDto":{"type":"object","properties":{"language":{"type":"object","description":"Código de idioma BCP-47. null/omitido = se usa el idioma del browser del cliente final."},"success_redirect_url":{"type":"object"},"failure_redirect_url":{"type":"object"},"allowed_modes":{"type":"array","description":"Modos de conexión permitidos.","items":{"type":"string","enum":["embedded_signup","coexistence"]}},"provision_phone_number":{"type":"boolean","description":"Si true, intentar provisión automática de número (fuera de scope inicial; reservado).","default":false},"theme":{"$ref":"#/components/schemas/SetupLinkThemeDto"}}},"PublicSetupLinkConfigResponseDto":{"type":"object","properties":{"tenant_name":{"type":"string","description":"Nombre del tenant dueño del link"},"language":{"type":"object","nullable":true},"allowed_modes":{"description":"embedded_signup | coexistence","type":"array","items":{"type":"string"}},"provision_phone_number":{"type":"boolean"},"theme":{"type":"object","nullable":true},"success_redirect_url":{"type":"object","nullable":true},"failure_redirect_url":{"type":"object","nullable":true},"meta_app_id":{"type":"string","description":"App id de Meta para el Embedded Signup"}},"required":["tenant_name","language","allowed_modes","provision_phone_number","theme","success_redirect_url","failure_redirect_url","meta_app_id"]},"StartSetupLinkRequestDto":{"type":"object","properties":{"mode":{"type":"string","enum":["embedded_signup","coexistence"]}},"required":["mode"]},"PublicStartSetupLinkResponseDto":{"type":"object","properties":{"mode":{"type":"string","description":"embedded_signup | coexistence"},"state":{"type":"string","description":"State HMAC que correlaciona el callback"},"meta_app_id":{"type":"string","description":"Sólo en embedded_signup / coexistence"},"config_id":{"type":"string","description":"Sólo en embedded_signup / coexistence"},"graph_api_version":{"type":"string","description":"Sólo en embedded_signup / coexistence"}},"required":["mode","state"]},"CompleteSetupLinkRequestDto":{"type":"object","properties":{"state":{"type":"string","description":"state HMAC firmado emitido por /start"},"code":{"type":"string","description":"authorization code retornado por FB.login"},"waba_id":{"type":"string","description":"WhatsApp Business Account ID provisto por el SDK"},"phone_number_id":{"type":"string","description":"Phone Number ID provisto por el SDK"},"mode":{"type":"string","enum":["embedded_signup","coexistence"]}},"required":["state","code","waba_id","phone_number_id","mode"]},"PublicCompleteSetupLinkResponseDto":{"type":"object","properties":{"redirect_url":{"type":"string","description":"Dónde mandar al usuario al terminar el flujo"}},"required":["redirect_url"]},"SelectProjectRequestDto":{"type":"object","properties":{"project":{"type":"string","description":"Slug o ObjectId del project que se quiere activar para la session CLI."}},"required":["project"]},"PublicCliProjectDto":{"type":"object","properties":{"id":{"type":"string","description":"ObjectId del project"},"slug":{"type":"string"},"name":{"type":"string"}},"required":["id"]},"PublicCliSelectProjectResponseDto":{"type":"object","properties":{"access_token":{"type":"string","description":"JWT de sesión CLI con el project ya aplicado"},"expires_at":{"type":"string","format":"date-time"},"current_project":{"$ref":"#/components/schemas/PublicCliProjectDto"}},"required":["access_token","expires_at","current_project"]},"PublicCliMeResponseDto":{"type":"object","properties":{"user_id":{"type":"string","description":"ObjectId del usuario dueño de la sesión"},"email":{"type":"string"},"current_project":{"nullable":true,"type":"object","allOf":[{"$ref":"#/components/schemas/PublicCliProjectDto"}]},"session_id":{"type":"object","nullable":true},"is_cli_session":{"type":"boolean","description":"true cuando el bearer es un JWT del CLI y no un PAT"}},"required":["user_id","email","current_project","session_id","is_cli_session"]}}}}