[{"data":1,"prerenderedAt":779},["ShallowReactive",2],{"docs-nav-docs_es":3,"docs-search-docs_es":80,"doc-docs_es-\u002Fdocs\u002Fwebchat":497,"surround-docs_es-\u002Fdocs\u002Fwebchat":775},[4],{"title":5,"path":6,"stem":7,"children":8,"page":42},"Docs","\u002Fdocs","docs",[9,13,17,21,43,47,68,72,76],{"title":10,"path":11,"stem":12},"Introducción","\u002Fdocs\u002Fintroduction","docs\u002F1.introduction",{"title":14,"path":15,"stem":16},"Inicio rápido","\u002Fdocs\u002Fquickstart","docs\u002F2.quickstart",{"title":18,"path":19,"stem":20},"Cómo funciona","\u002Fdocs\u002Fhow-it-works","docs\u002F3.how-it-works",{"title":22,"path":23,"stem":24,"children":25,"page":42},"Conceptos","\u002Fdocs\u002Fconcepts","docs\u002F4.concepts",[26,30,34,38],{"title":27,"path":28,"stem":29},"Workspaces y recursos","\u002Fdocs\u002Fconcepts\u002Fworkspaces-and-resources","docs\u002F4.concepts\u002F1.workspaces-and-resources",{"title":31,"path":32,"stem":33},"Servicios y disponibilidad","\u002Fdocs\u002Fconcepts\u002Fservices-and-availability","docs\u002F4.concepts\u002F2.services-and-availability",{"title":35,"path":36,"stem":37},"Reservas y pre-reservas","\u002Fdocs\u002Fconcepts\u002Fbookings-and-holds","docs\u002F4.concepts\u002F3.bookings-and-holds",{"title":39,"path":40,"stem":41},"Automatizaciones","\u002Fdocs\u002Fconcepts\u002Fautomations","docs\u002F4.concepts\u002F4.automations",false,{"title":44,"path":45,"stem":46},"WhatsApp e IA","\u002Fdocs\u002Fwhatsapp-and-ai","docs\u002F5.whatsapp-and-ai",{"title":48,"path":49,"stem":50,"children":51,"page":42},"API","\u002Fdocs\u002Fapi","docs\u002F6.api",[52,56,60,64],{"title":53,"path":54,"stem":55},"Autenticación","\u002Fdocs\u002Fapi\u002Fauthentication","docs\u002F6.api\u002F1.authentication",{"title":57,"path":58,"stem":59},"Convenciones","\u002Fdocs\u002Fapi\u002Fconventions","docs\u002F6.api\u002F2.conventions",{"title":61,"path":62,"stem":63},"Endpoints","\u002Fdocs\u002Fapi\u002Fendpoints","docs\u002F6.api\u002F3.endpoints",{"title":65,"path":66,"stem":67},"Webhooks","\u002Fdocs\u002Fapi\u002Fwebhooks","docs\u002F6.api\u002F4.webhooks",{"title":69,"path":70,"stem":71},"MCP y agentes de IA","\u002Fdocs\u002Fmcp","docs\u002F7.mcp",{"title":73,"path":74,"stem":75},"Recetas por negocio","\u002Fdocs\u002Frecipes","docs\u002F8.recipes",{"title":77,"path":78,"stem":79},"WebChat en tu sitio","\u002Fdocs\u002Fwebchat","docs\u002F9.webchat",[81,85,91,96,101,106,109,114,119,124,129,134,139,144,149,152,157,162,167,172,175,180,185,190,195,198,203,208,213,218,223,226,231,236,241,246,251,254,259,264,269,274,279,284,287,292,297,302,307,312,317,320,325,330,335,338,343,348,353,358,363,366,371,376,381,386,391,396,399,404,409,414,419,424,427,432,437,442,447,450,455,460,465,470,475,478,483,488,493],{"id":11,"title":10,"titles":82,"content":83,"level":84},[],"Qué es Wagend, para quién es y los bloques que vas a usar. Wagend es un motor de reservas con WhatsApp + IA como canal principal. Tus clientes reservan conversando; el sistema ofrece solo horarios que existen de verdad, los pre-reserva, los confirma y envía recordatorios. El negocio gestiona todo desde un panel, y los desarrolladores integran por API REST y webhooks. Wagend está en desarrollo. Esta documentación describe el contrato objetivo (borrador de la API v1). Los endpoints todavía pueden cambiar antes del piloto.",1,{"id":86,"title":87,"titles":88,"content":89,"level":90},"\u002Fdocs\u002Fintroduction#para-quién-es","Para quién es",[10],"Cualquier negocio que vende el tiempo de alguien o de algo: NegocioQué se reservaBarberíaUn barbero por 30–45 minutosEstéticaUn profesional y una máquina y una cabina, al mismo tiempoClínicaUn médico y un consultorioRestauranteCubiertos en el salón según el tamaño del grupoEntregasCapacidad en una ventana de 2 horas para una zonaClases, canchas, salasUn lugar en una clase o una cancha por hora",2,{"id":92,"title":93,"titles":94,"content":95,"level":90},"\u002Fdocs\u002Fintroduction#bloques-principales","Bloques principales",[10],"Organización → tu cuenta. Tiene uno o más workspaces (un negocio o sede).Recurso → lo que se consume: un barbero, una mesa, una máquina de láser, una sala, una zona de entrega.Servicio → lo que reserva el cliente. Declara sus requisitos: qué recursos necesita, y cuántos, al mismo tiempo.Horario → cuándo está disponible cada recurso.Reserva → pasa por una pre-reserva (10 minutos) antes de quedar confirmada.Automatización → recordatorios, confirmaciones y avisos disparados por eventos de la reserva. Leé Workspaces y recursos para el modelo completo.",{"id":97,"title":98,"titles":99,"content":100,"level":90},"\u002Fdocs\u002Fintroduction#canales","Canales",[10],"Todos los canales usan el mismo motor: un horario reservado por WhatsApp desaparece al instante del panel y de la API. WhatsApp con asistente de IA (texto y audio).Página pública de reserva, widget embebible y MCP para agentes de IA: Próximamente.Panel para el equipo (agenda del día, inbox, calendario, configuración).API REST y webhooks para desarrolladores.",{"id":102,"title":103,"titles":104,"content":105,"level":90},"\u002Fdocs\u002Fintroduction#próximos-pasos","Próximos pasos",[10],"Inicio rápido: hacé tu primera reserva por API en 5 minutos.Cómo funciona: la arquitectura y la vida de un mensaje.MCP: la conexión prevista para agentes de IA (próximamente).",{"id":15,"title":14,"titles":107,"content":108,"level":84},[],"Creá tu primera reserva por API en cinco minutos con una clave de un negocio de prueba. Esta guía crea una reserva real, así que usá una clave de producción (wg_live_...) de un negocio que armaste para probar. Las claves wg_test_ son de solo lectura hoy: un sandbox para escrituras es próximamente. Para probar el bot sin WhatsApp, usá el simulador del panel. URL base: https:\u002F\u002Fapi.wagend.app\u002Fv1. Cada request necesita Authorization: Bearer \u003Cclave>.",{"id":110,"title":111,"titles":112,"content":113,"level":90},"\u002Fdocs\u002Fquickstart#_1-generá-una-clave","1. Generá una clave",[14],"En el panel, andá a Configuración → Desarrolladores, creá una clave de Producción y marcá los scopes slots:read, bookings:write y config:read. La clave se muestra una sola vez. export WAGEND_KEY=\"wg_live_xxxxxxxx_xxxxxxxxxxxxxxxxxxxx\"",{"id":115,"title":116,"titles":117,"content":118,"level":90},"\u002Fdocs\u002Fquickstart#_2-verificá-quién-sos","2. Verificá quién sos",[14],"curl https:\u002F\u002Fapi.wagend.app\u002Fv1\u002Fme -H \"Authorization: Bearer $WAGEND_KEY\" {\n  \"workspace\": { \"id\": \"ws_9f2c\", \"name\": \"Barbería Centro\", \"timezone\": \"America\u002FSao_Paulo\", \"locale\": \"es\", \"currency\": \"BRL\" },\n  \"scopes\": [\"slots:read\", \"bookings:write\", \"config:read\"],\n  \"mode\": \"live\"\n} El workspace siempre sale de la clave. Nunca enviás un id de workspace.",{"id":120,"title":121,"titles":122,"content":123,"level":90},"\u002Fdocs\u002Fquickstart#_3-listá-los-servicios","3. Listá los servicios",[14],"curl https:\u002F\u002Fapi.wagend.app\u002Fv1\u002Fservices -H \"Authorization: Bearer $WAGEND_KEY\" {\n  \"data\": [\n    { \"id\": \"svc_corte\", \"name\": \"Corte\", \"duration_min\": 30, \"price_cents\": 5000, \"currency\": \"BRL\",\n      \"requirements\": [{ \"resource_group_id\": \"grp_barbers\", \"units\": 1 }] }\n  ]\n}",{"id":125,"title":126,"titles":127,"content":128,"level":90},"\u002Fdocs\u002Fquickstart#_4-buscá-horarios-disponibles","4. Buscá horarios disponibles",[14],"curl \"https:\u002F\u002Fapi.wagend.app\u002Fv1\u002Fslots?service_id=svc_corte&from=2026-10-15T08:00:00-03:00&to=2026-10-15T13:00:00-03:00\" \\\n  -H \"Authorization: Bearer $WAGEND_KEY\" {\n  \"data\": [\n    { \"start\": \"2026-10-15T09:00:00-03:00\", \"end\": \"2026-10-15T09:30:00-03:00\", \"resource_ids\": [\"res_juan\"] },\n    { \"start\": \"2026-10-15T09:45:00-03:00\", \"end\": \"2026-10-15T10:15:00-03:00\", \"resource_ids\": [\"res_juan\"] }\n  ],\n  \"unavailable_reason\": null\n}",{"id":130,"title":131,"titles":132,"content":133,"level":90},"\u002Fdocs\u002Fquickstart#_5-pre-reservá-el-horario","5. Pre-reservá el horario",[14],"La pre-reserva (hold) guarda el horario por 10 minutos mientras juntás los datos del cliente. Enviá siempre un Idempotency-Key para que los reintentos sean seguros. curl -X POST https:\u002F\u002Fapi.wagend.app\u002Fv1\u002Fholds \\\n  -H \"Authorization: Bearer $WAGEND_KEY\" \\\n  -H \"Idempotency-Key: $(uuidgen)\" \\\n  -H \"Content-Type: application\u002Fjson\" \\\n  -d '{ \"service_id\": \"svc_corte\", \"start\": \"2026-10-15T09:45:00-03:00\", \"resource_ids\": [\"res_juan\"] }' { \"id\": \"bkg_7Qx1\", \"status\": \"held\", \"expires_at\": \"2026-10-14T15:30:00-03:00\", \"start\": \"2026-10-15T09:45:00-03:00\" }",{"id":135,"title":136,"titles":137,"content":138,"level":90},"\u002Fdocs\u002Fquickstart#_6-confirmá","6. Confirmá",[14],"curl -X POST https:\u002F\u002Fapi.wagend.app\u002Fv1\u002Fholds\u002Fbkg_7Qx1\u002Fconfirm \\\n  -H \"Authorization: Bearer $WAGEND_KEY\" \\\n  -H \"Idempotency-Key: $(uuidgen)\" \\\n  -H \"Content-Type: application\u002Fjson\" \\\n  -d '{ \"customer\": { \"name\": \"Carlos\", \"phone\": \"+5491155550000\", \"locale\": \"es\" } }' { \"id\": \"bkg_7Qx1\", \"status\": \"confirmed\", \"start\": \"2026-10-15T09:45:00-03:00\", \"source\": \"api\" } Si el servicio pide seña, el estado queda en pending_payment. El cobro de la seña por Pix es próximamente.",{"id":140,"title":141,"titles":142,"content":143,"level":90},"\u002Fdocs\u002Fquickstart#el-mismo-flujo-en-javascript","El mismo flujo en JavaScript",[14],"const api = (path: string, init: RequestInit = {}) =>\n  fetch(`https:\u002F\u002Fapi.wagend.app\u002Fv1${path}`, {\n    ...init,\n    headers: { Authorization: `Bearer ${process.env.WAGEND_KEY}`, 'Content-Type': 'application\u002Fjson', ...init.headers },\n  }).then((r) => r.json())\n\nconst { data: slots } = await api(`\u002Fslots?service_id=svc_corte&from=${from}&to=${to}`)\nconst hold = await api('\u002Fholds', {\n  method: 'POST',\n  headers: { 'Idempotency-Key': crypto.randomUUID() },\n  body: JSON.stringify({ service_id: 'svc_corte', start: slots[0].start }),\n})\nconst booking = await api(`\u002Fholds\u002F${hold.id}\u002Fconfirm`, {\n  method: 'POST',\n  headers: { 'Idempotency-Key': crypto.randomUUID() },\n  body: JSON.stringify({ customer: { name: 'Carlos', phone: '+5491155550000' } }),\n})",{"id":145,"title":146,"titles":147,"content":148,"level":90},"\u002Fdocs\u002Fquickstart#siguientes-pasos","Siguientes pasos",[14],"Reaccioná a las reservas con webhooks.Mirá todos los endpoints en la referencia. html pre.shiki code .szBVR, html code.shiki .szBVR{--shiki-default:#D73A49;--shiki-dark:#F97583}html pre.shiki code .sVt8B, html code.shiki .sVt8B{--shiki-default:#24292E;--shiki-dark:#E1E4E8}html pre.shiki code .sZZnC, html code.shiki .sZZnC{--shiki-default:#032F62;--shiki-dark:#9ECBFF}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html pre.shiki code .sScJk, html code.shiki .sScJk{--shiki-default:#6F42C1;--shiki-dark:#B392F0}html pre.shiki code .sj4cs, html code.shiki .sj4cs{--shiki-default:#005CC5;--shiki-dark:#79B8FF}html pre.shiki code .s4XuR, html code.shiki .s4XuR{--shiki-default:#E36209;--shiki-dark:#FFAB70}",{"id":19,"title":18,"titles":150,"content":151,"level":84},[],"Arquitectura, principios y la vida de un mensaje de WhatsApp dentro de Wagend.",{"id":153,"title":154,"titles":155,"content":156,"level":90},"\u002Fdocs\u002Fhow-it-works#principios","Principios",[18],"Núcleo determinístico, IA como intérprete. La IA entiende al cliente y llama herramientas. El motor calcula disponibilidad, pre-reserva, y confirma. La IA nunca inventa un horario ni un precio.La base de datos garantiza las reglas. El sobreturno es imposible porque PostgreSQL rechaza asignaciones superpuestas, no porque la app \"chequea antes\".API primero. Panel y bot de WhatsApp usan los mismos servicios. Si algo no se puede hacer por API, falta en la API.La credencial define el negocio. Una clave o sesión siempre pertenece a un workspace.",{"id":158,"title":159,"titles":160,"content":161,"level":90},"\u002Fdocs\u002Fhow-it-works#arquitectura","Arquitectura",[18],"Canales:    WhatsApp · Panel · REST\n                 │\nGateway:    credencial → workspace · scopes · límites · webhooks firmados\n                 │\nNúcleo:     conversaciones + IA │ motor de agenda │ automatizaciones │ conocimiento\n                 │\nDatos:      PostgreSQL (seguridad por fila, constraints de exclusión, jobs) · Redis\nExternos:   modelos de IA (OpenRouter) · transcripción de audio · proveedor de WhatsApp",{"id":163,"title":164,"titles":165,"content":166,"level":90},"\u002Fdocs\u002Fhow-it-works#la-vida-de-un-mensaje","La vida de un mensaje",[18],"Llega. El proveedor de WhatsApp llama a nuestro webhook. Verificamos la firma HMAC, descartamos duplicados por id de mensaje y lo guardamos. Respondemos en menos de 200 ms.Se entiende. Los audios se transcriben. Identificamos cliente y conversación. Si una persona tomó el control, el bot no responde.La IA pide. El modelo recibe el contexto del negocio, la fecha y hora locales, un estado estructurado de la conversación y los últimos mensajes. Solo puede llamar herramientas como find_slots, hold_slot o confirm_hold.El motor decide. Cada llamada se valida contra un schema estricto y las reglas del negocio, y después se ejecuta. Los errores vuelven como datos estructurados (por ejemplo slot_taken con alternativas) para que la IA vuelva a preguntar.Respuesta exacta. Fechas, horas, servicios, precios y direcciones salen de plantillas completadas con el resultado real.Eventos. booking.confirmed y compañía disparan automatizaciones (recordatorios) y tus webhooks.",{"id":168,"title":169,"titles":170,"content":171,"level":90},"\u002Fdocs\u002Fhow-it-works#a-dónde-seguir","A dónde seguir",[18],"Reservas y pre-reservas explica las garantías.WhatsApp e IA explica qué puede y qué no puede hacer la IA.",{"id":28,"title":27,"titles":173,"content":174,"level":84},[],"Organizaciones, workspaces, roles, recursos, modos de capacidad y grupos de recursos.",{"id":176,"title":177,"titles":178,"content":179,"level":90},"\u002Fdocs\u002Fconcepts\u002Fworkspaces-and-resources#organización-y-workspaces","Organización y workspaces",[27],"Una organización es la cuenta que paga. Contiene uno o más workspaces. Un workspace es un negocio o sede con sus propios: zona horaria, idioma y moneda,número(s) de WhatsApp,bot, servicios, recursos y equipo. Una cadena de tres barberías es una organización con tres workspaces.",{"id":181,"title":182,"titles":183,"content":184,"level":90},"\u002Fdocs\u002Fconcepts\u002Fworkspaces-and-resources#roles","Roles",[27],"RolPuedeownerTodo, en todos los workspaces de la organizaciónmanagerTodo dentro de un workspacestaffVer y gestionar solo sus propios recursos (por ejemplo, el barbero ve solo su agenda)viewerSolo lectura El equipo también puede actuar por WhatsApp después de vincular su número con un código de un solo uso. Las acciones de administrador por WhatsApp siempre piden confirmación SÍ\u002FNO.",{"id":186,"title":187,"titles":188,"content":189,"level":90},"\u002Fdocs\u002Fconcepts\u002Fworkspaces-and-resources#recursos","Recursos",[27],"Un recurso es cualquier cosa que una reserva consume. kindEjemplosstaffBarbero, médico, esteticista, instructorspaceSala, consultorio, cabina, salónequipmentMáquina de láser, sillón, canchatableMesa de restaurante (modo mesas)vehicleCamioneta, equipo de repartozoneZona de entrega por código postal Cada recurso tiene un modo de capacidad: exclusive — atiende una reserva a la vez (un barbero, una sala, una máquina).pooled — tiene capacidad en unidades (40 cubiertos por turno, 12 lugares en una clase, 10 entregas por ventana).",{"id":191,"title":192,"titles":193,"content":194,"level":90},"\u002Fdocs\u002Fconcepts\u002Fworkspaces-and-resources#grupos-de-recursos","Grupos de recursos",[27],"Un grupo de recursos es un conjunto intercambiable (\"cualquier barbero\", \"máquinas de láser\"). Los servicios piden grupos, no recursos individuales, para que el motor elija uno. La estrategia de asignación decide cuál: assignmentComportamientocustomer_choiceElige el cliente (por ejemplo \"con Juan\"); si le da igual, usa otra estrategiaround_robinRota entre los miembrosleast_busyElige al miembro con menos reservas en el díafixedSiempre el mismo miembro (una sola máquina, una sola sala) {\n  \"name\": \"Barberos\",\n  \"assignment\": \"customer_choice\",\n  \"member_ids\": [\"res_juan\", \"res_pedro\", \"res_leo\"]\n} html pre.shiki code .sVt8B, html code.shiki .sVt8B{--shiki-default:#24292E;--shiki-dark:#E1E4E8}html pre.shiki code .sj4cs, html code.shiki .sj4cs{--shiki-default:#005CC5;--shiki-dark:#79B8FF}html pre.shiki code .sZZnC, html code.shiki .sZZnC{--shiki-default:#032F62;--shiki-dark:#9ECBFF}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}",{"id":32,"title":31,"titles":196,"content":197,"level":84},[],"Servicios, requisitos con varios recursos, horarios y cómo se calculan los slots.",{"id":199,"title":200,"titles":201,"content":202,"level":90},"\u002Fdocs\u002Fconcepts\u002Fservices-and-availability#servicios","Servicios",[31],"Un servicio es lo que reserva el cliente. CampoSignificadoduration_minDuración del serviciostep_minGrilla de inicio (cada 15, 30 minutos…)buffer_before_min \u002F buffer_after_minTiempo de preparación o limpieza bloqueado alrededor de la reservaprice_cents, currencyPrecio que informa el bot (siempre desde la base de datos)deposit_centsSeña necesaria para confirmar (cobro por Pix: próximamente)lead_time_minAnticipación mínima (por ejemplo 60 minutos)max_advance_daysCon cuánta anticipación máxima se puede reservarwindow_modeEl slot es una ventana fija (entregas: 14:00–16:00)fulfillment_modescheduled (default, con horario) o queue (despacho por cola, sin horario fijo)intake_formJSON Schema de datos extra a pedir (obra social, dirección…)requirementsQué recursos necesita el servicio al mismo tiempo",{"id":204,"title":205,"titles":206,"content":207,"level":90},"\u002Fdocs\u002Fconcepts\u002Fservices-and-availability#ventana-o-despacho-dos-modos-de-cumplimiento","Ventana o despacho: dos modos de cumplimiento",[31],"Cada servicio define cómo se cumple lo reservado (fulfillment_mode): scheduled (el default): la reserva ocupa un rango de tiempo conocido — un horario fijo o, con window_mode, una ventana (entregas de 14:00 a 16:00, con cupo por zona).queue (despacho, para agua, gas o delivery on-demand): la reserva no tiene horario fijo — entra en la cola de pendientes de un repartidor. El motor la asigna al repartidor con menos tareas activas y cada repartidor tiene un cupo de tareas activas a la vez, garantizado en la base de datos. La cola usa los mismos estados que una reserva: pendiente → aceptada → iniciada → finalizada (o fallida). Así, un mismo negocio de entregas puede ofrecer ventanas programadas, despacho inmediato o ambos.",{"id":209,"title":210,"titles":211,"content":212,"level":90},"\u002Fdocs\u002Fconcepts\u002Fservices-and-availability#requisitos","Requisitos",[31],"Un requisito dice: de este grupo, necesito tantas unidades. Un servicio puede tener varios; un slot existe solo si todos están libres. {\n  \"name\": \"Depilación láser\",\n  \"duration_min\": 45,\n  \"buffer_after_min\": 10,\n  \"requirements\": [\n    { \"resource_group_id\": \"grp_professionals\", \"units\": 1 },\n    { \"resource_group_id\": \"grp_lasers\", \"units\": 1 },\n    { \"resource_group_id\": \"grp_rooms\", \"units\": 1 }\n  ]\n} Con dos profesionales y un solo láser, Wagend nunca ofrece dos sesiones de láser superpuestas. Opciones avanzadas: units: \"party_size\" — consume tantas unidades como personas (restaurantes, clases).offset_min \u002F duration_min en un requisito — usa un recurso solo en parte del servicio (por ejemplo el lavacabezas en los últimos 15 minutos de un color).",{"id":214,"title":215,"titles":216,"content":217,"level":90},"\u002Fdocs\u002Fconcepts\u002Fservices-and-availability#horarios","Horarios",[31],"Cada recurso tiene un horario: reglas semanales en la zona horaria del recurso más excepciones para fechas puntuales (cerrado u horario especial). {\n  \"tz\": \"America\u002FArgentina\u002FBuenos_Aires\",\n  \"weekly\": { \"tue\": [[\"09:00\", \"19:00\"]], \"sat\": [[\"08:00\", \"12:00\"], [\"13:00\", \"16:00\"]] },\n  \"overrides\": [{ \"date\": \"2026-12-24\", \"ranges\": [[\"09:00\", \"13:00\"]] }, { \"date\": \"2026-12-25\", \"closed\": true }]\n}",{"id":219,"title":220,"titles":221,"content":222,"level":90},"\u002Fdocs\u002Fconcepts\u002Fservices-and-availability#cómo-se-calculan-los-slots","Cómo se calculan los slots",[31],"Expandir los horarios para el rango pedido, en la zona horaria de cada recurso.Restar reservas y pre-reservas activas (más los buffers) y bloqueos manuales.Cortar en slots candidatos según la duración y la grilla del servicio.Aplicar anticipación mínima y máxima, reglas de corte y tamaño del grupo.Cruzar todos los requisitos, probando los miembros de cada grupo según la estrategia de asignación.Devolver una lista corta y ordenada. Cuando no hay nada disponible, la respuesta trae unavailable_reason (closed, no_staff, no_equipment, no_space, lead_time, max_advance, cutoff, full) para que el bot explique por qué. html pre.shiki code .sVt8B, html code.shiki .sVt8B{--shiki-default:#24292E;--shiki-dark:#E1E4E8}html pre.shiki code .sj4cs, html code.shiki .sj4cs{--shiki-default:#005CC5;--shiki-dark:#79B8FF}html pre.shiki code .sZZnC, html code.shiki .sZZnC{--shiki-default:#032F62;--shiki-dark:#9ECBFF}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}",{"id":36,"title":35,"titles":224,"content":225,"level":84},[],"Estados de la reserva, la pre-reserva de 10 minutos, señas y la garantía de cero sobreturnos.",{"id":227,"title":228,"titles":229,"content":230,"level":90},"\u002Fdocs\u002Fconcepts\u002Fbookings-and-holds#por-qué-una-pre-reserva","Por qué una pre-reserva",[35],"Una conversación por WhatsApp puede tardar minutos: el cliente elige horario, después le pedís el nombre, quizás una seña. Mientras tanto otros clientes y la API compiten por el mismo horario. La pre-reserva (hold) guarda el horario por 10 minutos (15 cuando hay seña) y vence sola.",{"id":232,"title":233,"titles":234,"content":235,"level":90},"\u002Fdocs\u002Fconcepts\u002Fbookings-and-holds#estados","Estados",[35],"EstadoSignificadoOcupa el horarioheldPre-reserva temporalSípending_paymentEsperando la señaSíconfirmedReservadoSíchecked_inEl cliente llegóSícompletedAtendidoNocancelledCancelado (o reemplazado por una reprogramación)Nono_showAusencia marcada por una personaNoexpiredPre-reserva no confirmada a tiempoNo held ──confirm──► confirmed ──check-in──► checked_in ──► completed\n │  └─(seña)──► pending_payment ──pagada──► confirmed\n └─vence──► expired          confirmed ──cancela──► cancelled",{"id":237,"title":238,"titles":239,"content":240,"level":90},"\u002Fdocs\u002Fconcepts\u002Fbookings-and-holds#garantías","Garantías",[35],"Cada recurso que ocupa una reserva se guarda como una asignación con un rango de tiempo.Para recursos exclusive, PostgreSQL rechaza asignaciones superpuestas con una constraint de exclusión.Para recursos pooled, los contadores de capacidad nunca superan el límite (chequeo atómico).Una reserva con varios recursos se escribe en una sola transacción: si cualquier recurso choca, no se reserva nada.POST \u002Fholds y POST \u002Fholds\u002F{id}\u002Fconfirm exigen Idempotency-Key: reintentar un request nunca crea una segunda reserva. Si el horario se ocupó mientras el cliente decidía, recibís 409 con code: \"slot_taken\" y una lista de alternatives.",{"id":242,"title":243,"titles":244,"content":245,"level":90},"\u002Fdocs\u002Fconcepts\u002Fbookings-and-holds#reprogramar-y-cancelar","Reprogramar y cancelar",[35],"Reprogramar crea una reserva nueva y cancela la anterior (vinculadas por rescheduled_to). Los recordatorios se mueven solos.Cancelar libera el horario y cancela los recordatorios pendientes.Ausencia nunca es automática: el sistema la sugiere, una persona la confirma.",{"id":247,"title":248,"titles":249,"content":250,"level":90},"\u002Fdocs\u002Fconcepts\u002Fbookings-and-holds#señas","Señas",[35],"Si el servicio tiene deposit_cents, confirmar la pre-reserva deja la reserva en pending_payment y el horario sigue bloqueado. El cobro de la seña por Pix es próximamente: hasta entonces la reserva no pasa sola a confirmed y no se emite payment.paid.",{"id":40,"title":39,"titles":252,"content":253,"level":84},[],"Recordatorios, confirmaciones y avisos como reglas \"cuando pase esto, hacé aquello\". Las automatizaciones son reglas con un disparador, condiciones opcionales y una acción. Cada negocio crea, activa y ajusta las suyas.",{"id":255,"title":256,"titles":257,"content":258,"level":90},"\u002Fdocs\u002Fconcepts\u002Fautomations#disparadores","Disparadores",[39],"DisparadorEjemplobooking.confirmedEnviar el resumen de la reservabooking.starts_in(Δ)Por ejemplo 24 h antes: enviar un recordatoriobooking.ended(+Δ)Después de que termina la reserva: enviar un mensajebooking.cancelled, booking.rescheduledAvisar al clientebooking.stage_changedCuando la reserva pasa a otra etapa",{"id":260,"title":261,"titles":262,"content":263,"level":90},"\u002Fdocs\u002Fconcepts\u002Fautomations#condiciones","Condiciones",[39],"Servicio, recurso, cantidad de personas mayor a N, canal.",{"id":265,"title":266,"titles":267,"content":268,"level":90},"\u002Fdocs\u002Fconcepts\u002Fautomations#acciones","Acciones",[39],"Enviar un mensaje o plantilla al cliente, avisar al equipo, pedir confirmación SÍ\u002FNO, cambiar el estado de la reserva.",{"id":270,"title":271,"titles":272,"content":273,"level":90},"\u002Fdocs\u002Fconcepts\u002Fautomations#reglas-iniciales","Reglas iniciales",[39],"Los modelos de negocio no activan reglas por sí solos: cada negocio crea, activa y ajusta las suyas.",{"id":275,"title":276,"titles":277,"content":278,"level":90},"\u002Fdocs\u002Fconcepts\u002Fautomations#próximamente","Próximamente",[39],"Todavía no existen: los disparadores hold.expired, payment.paid y daily_at(hh:mm) (agenda del día al equipo); las condiciones por etiqueta del cliente y por cantidad de ausencias; y las acciones de crear una tarea interna y llamar a un webhook.",{"id":280,"title":281,"titles":282,"content":283,"level":90},"\u002Fdocs\u002Fconcepts\u002Fautomations#garantías-de-ejecución","Garantías de ejecución",[39],"Los jobs se crean en la misma transacción que el evento de la reserva, así que nunca se pierden.Antes de ejecutarse, el job vuelve a revisar la reserva. Si se reprogramó o canceló, el job viejo se descarta.Cada job corre una vez (clave de idempotencia) y reintenta con espera creciente; después de 5 fallos aparece en el panel.Horario de silencio: no se envía nada a clientes entre las 21:00 y las 08:00 de su zona horaria.Las respuestas SÍ\u002FNO se interpretan sin IA (sim, sí, ok, 👍, não…): instantáneo y gratis.",{"id":45,"title":44,"titles":285,"content":286,"level":84},[],"Conectar un número, qué puede y qué no puede hacer el asistente, acciones del equipo y derivación a una persona.",{"id":288,"title":289,"titles":290,"content":291,"level":90},"\u002Fdocs\u002Fwhatsapp-and-ai#conectar-un-número","Conectar un número",[44],"En el panel, andá a Canales → WhatsApp → Conectar y escaneá el QR con el celular del negocio, como en WhatsApp Web. Un workspace puede conectar varios números (uno por sede, por ejemplo). Usá un número dedicado al negocio. Hoy la conexión por QR es la única forma de conectar.",{"id":293,"title":294,"titles":295,"content":296,"level":90},"\u002Fdocs\u002Fwhatsapp-and-ai#clientes-y-equipo","Clientes y equipo",[44],"El rol se decide en el código, nunca por lo que alguien dice en el chat: Un número vinculado a alguien del equipo (verificado con un código de un solo uso) recibe herramientas de equipo.Todos los demás reciben herramientas de cliente. Herramientas de clienteHerramientas de equipo (extra)list_services, find_slots, hold_slot, confirm_hold, my_bookings, cancel_my_booking, reschedule_my_booking, get_business_info, search_knowledge, handoff_to_humanlist_today, block_time, mark_no_show, update_catalog_item — siempre con confirmación SÍ\u002FNO",{"id":298,"title":299,"titles":300,"content":301,"level":90},"\u002Fdocs\u002Fwhatsapp-and-ai#qué-puede-y-qué-no-puede-hacer-la-ia","Qué puede y qué no puede hacer la IA",[44],"PuedeNo puedeEntender texto, audio, errores de tipeo y cambios de ideaInventar horarios, precios o direccionesBuscar horarios y ofrecer 2–3 opcionesConfirmar una reserva sin el motorPre-reservar y pedir los datos que faltanUsar herramientas de administrador con un clienteResponder dudas con la base de conocimiento del negocioSeguir instrucciones escondidas en mensajes o archivosPasar la conversación a una personaVer datos de otro negocio Los ids de workspace, los ids de cliente y los precios los inyecta el sistema; el modelo nunca los aporta.",{"id":303,"title":304,"titles":305,"content":306,"level":90},"\u002Fdocs\u002Fwhatsapp-and-ai#derivación-a-una-persona","Derivación a una persona",[44],"El equipo ve todas las conversaciones en vivo en el Inbox. Tomar el control pausa el bot en esa conversación; vuelve solo después de 15 minutos sin actividad del operador. El asistente también deriva cuando el cliente lo pide (\"quiero hablar con una persona\").",{"id":308,"title":309,"titles":310,"content":311,"level":90},"\u002Fdocs\u002Fwhatsapp-and-ai#audios-e-idiomas","Audios e idiomas",[44],"Los audios se transcriben antes de que la IA los lea, y la transcripción se ve en el inbox. El asistente responde en el idioma del cliente (portugués, español o inglés).",{"id":313,"title":314,"titles":315,"content":316,"level":90},"\u002Fdocs\u002Fwhatsapp-and-ai#modelos","Modelos",[44],"La capa de IA corre por OpenRouter con una clave y un límite de gasto propios por workspace. Por defecto usa un modelo rápido y barato; un modelo más potente se usa solo en los turnos que fallan la validación. Los proveedores se fijan entre los que no retienen datos.",{"id":54,"title":53,"titles":318,"content":319,"level":84},[],"Claves de API, scopes, modos de prueba y producción.",{"id":321,"title":322,"titles":323,"content":324,"level":90},"\u002Fdocs\u002Fapi\u002Fauthentication#claves-de-api","Claves de API",[53],"Enviá tu clave como bearer token: GET \u002Fv1\u002Fme HTTP\u002F1.1\nHost: api.wagend.app\nAuthorization: Bearer wg_live_3fa9c2_Lr8t... PrefijoModowg_live_Datos de producción y mensajes realeswg_test_Solo lectura: permite listar y leer, no crear ni modificar nada. Un sandbox para escrituras es próximamente Las claves pertenecen a un workspace. El workspace siempre se toma de la clave: no hay id de workspace en paths ni en bodies. Las claves se guardan hasheadas; la clave completa se muestra una sola vez, al crearla.",{"id":326,"title":327,"titles":328,"content":329,"level":90},"\u002Fdocs\u002Fapi\u002Fauthentication#scopes","Scopes",[53],"ScopePermiteslots:readGET \u002Fslotsbookings:readListar y leer reservasbookings:writePre-reservas, confirmar, cancelar, reprogramar, check-in, ausenciacustomers:readLeer clientesmessages:readLeer conversaciones y mensajesmessages:writeEnviar mensajes, derivarconfig:read \u002F config:writeServicios, recursos, grupos, horarios, automatizaciones, conocimientowebhooks:manageEndpoints de webhooks Un request sin el scope necesario devuelve 403 con code: \"insufficient_scope\".",{"id":331,"title":332,"titles":333,"content":334,"level":90},"\u002Fdocs\u002Fapi\u002Fauthentication#rotación","Rotación",[53],"Creá una clave nueva, desplegala y después revocá la vieja en Configuración → Desarrolladores. Las claves revocadas devuelven 401 al instante. html pre.shiki code .szBVR, html code.shiki .szBVR{--shiki-default:#D73A49;--shiki-dark:#F97583}html pre.shiki code .sVt8B, html code.shiki .sVt8B{--shiki-default:#24292E;--shiki-dark:#E1E4E8}html pre.shiki code .sj4cs, html code.shiki .sj4cs{--shiki-default:#005CC5;--shiki-dark:#79B8FF}html pre.shiki code .s9eBZ, html code.shiki .s9eBZ{--shiki-default:#22863A;--shiki-dark:#85E89D}html pre.shiki code .sZZnC, html code.shiki .sZZnC{--shiki-default:#032F62;--shiki-dark:#9ECBFF}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}",{"id":58,"title":57,"titles":336,"content":337,"level":84},[],"Formatos, idempotencia, paginación, errores y límites de uso.",{"id":339,"title":340,"titles":341,"content":342,"level":90},"\u002Fdocs\u002Fapi\u002Fconventions#lo-básico","Lo básico",[57],"URL base https:\u002F\u002Fapi.wagend.app\u002Fv1. Los cambios incompatibles salen como una nueva versión.JSON de entrada y de salida (Content-Type: application\u002Fjson).Fechas en ISO 8601 con offset (2026-10-15T09:45:00-03:00). Se guardan en UTC.Montos en centavos enteros más currency (BRL, ARS, PYG, USD).Los IDs son strings opacos con prefijo (bkg_, svc_, res_, grp_, cus_).",{"id":344,"title":345,"titles":346,"content":347,"level":90},"\u002Fdocs\u002Fapi\u002Fconventions#idempotencia","Idempotencia",[57],"POST \u002Fholds, POST \u002Fholds\u002F{id}\u002Fconfirm, POST \u002Fbookings y POST \u002Fbookings\u002F{id}\u002Freschedule exigen el header Idempotency-Key (por ejemplo un UUID). Repetir un request con la misma clave dentro de 24 horas devuelve la respuesta original. Reusar la clave con otro body devuelve 422.",{"id":349,"title":350,"titles":351,"content":352,"level":90},"\u002Fdocs\u002Fapi\u002Fconventions#paginación","Paginación",[57],"Los endpoints de listado usan cursores: curl \"https:\u002F\u002Fapi.wagend.app\u002Fv1\u002Fbookings?limit=50\" -H \"Authorization: Bearer $WAGEND_KEY\"\n# → { \"data\": [...], \"next_cursor\": \"eyJpZCI6...\" }\ncurl \"https:\u002F\u002Fapi.wagend.app\u002Fv1\u002Fbookings?limit=50&cursor=eyJpZCI6...\" -H \"Authorization: Bearer $WAGEND_KEY\"",{"id":354,"title":355,"titles":356,"content":357,"level":90},"\u002Fdocs\u002Fapi\u002Fconventions#errores","Errores",[57],"Los errores siguen la RFC 9457 (application\u002Fproblem+json): {\n  \"type\": \"https:\u002F\u002Fwagend.app\u002Fdocs\u002Fapi\u002Fconventions#errors\",\n  \"title\": \"Slot no longer available\",\n  \"status\": 409,\n  \"code\": \"slot_taken\",\n  \"alternatives\": [{ \"start\": \"2026-10-15T10:15:00-03:00\", \"end\": \"2026-10-15T10:45:00-03:00\" }]\n} codeEstadoCuándoinvalid_request400 \u002F 422Falló la validaciónunauthorized401Clave ausente, inválida o revocadainsufficient_scope403La clave no tiene el scopenot_found404Id desconocido (o de otro workspace)slot_taken409Otra persona tomó el horarioinvalid_transition409Por ejemplo confirmar una reserva canceladahold_expired410La pre-reserva venció antes de confirmaridempotency_mismatch422Misma clave, distinto bodyrate_limited429Demasiados requests",{"id":359,"title":360,"titles":361,"content":362,"level":90},"\u002Fdocs\u002Fapi\u002Fconventions#límites-de-uso","Límites de uso",[57],"Los límites aplican por clave y por workspace. Cada respuesta trae RateLimit-Limit, RateLimit-Remaining y RateLimit-Reset. Ante un 429, esperá Retry-After segundos. html pre.shiki code .sScJk, html code.shiki .sScJk{--shiki-default:#6F42C1;--shiki-dark:#B392F0}html pre.shiki code .sZZnC, html code.shiki .sZZnC{--shiki-default:#032F62;--shiki-dark:#9ECBFF}html pre.shiki code .sj4cs, html code.shiki .sj4cs{--shiki-default:#005CC5;--shiki-dark:#79B8FF}html pre.shiki code .sVt8B, html code.shiki .sVt8B{--shiki-default:#24292E;--shiki-dark:#E1E4E8}html pre.shiki code .sJ8bj, html code.shiki .sJ8bj{--shiki-default:#6A737D;--shiki-dark:#6A737D}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}",{"id":62,"title":61,"titles":364,"content":365,"level":84},[],"Todos los endpoints de la v1 de un vistazo, con los formatos más comunes de request y respuesta. El contrato legible por máquina está en el repositorio, en packages\u002Fopenapi\u002Fopenapi.yaml (OpenAPI 3.1).",{"id":367,"title":368,"titles":369,"content":370,"level":90},"\u002Fdocs\u002Fapi\u002Fendpoints#agenda","Agenda",[61],"MétodoPathScopeDescripciónGET\u002Fslotsslots:readHorarios disponibles para un servicioPOST\u002Fholdsbookings:writeCrear pre-reserva de 10 minutosPOST\u002Fholds\u002F{id}\u002Fconfirmbookings:writeConfirmar (o pending_payment si pide seña)DELETE\u002Fholds\u002F{id}bookings:writeLiberar pre-reservaGET\u002Fbookingsbookings:readListar (filtros: from, to, status, resource_id, customer_id)POST\u002Fbookingsbookings:writePre-reserva + confirmación en una llamadaGET \u002F PATCH\u002Fbookings\u002F{id}bookings:read \u002F writeLeer, actualizar notas o datos de intakePOST\u002Fbookings\u002F{id}\u002Fcancelbookings:writeCancelarPOST\u002Fbookings\u002F{id}\u002Freschedulebookings:writeMover a un nuevo inicioPOST\u002Fbookings\u002F{id}\u002Fcheck-inbookings:writeMarcar llegadaPOST\u002Fbookings\u002F{id}\u002Fno-showbookings:writeMarcar ausencia",{"id":372,"title":373,"titles":374,"content":375,"level":90},"\u002Fdocs\u002Fapi\u002Fendpoints#catálogo","Catálogo",[61],"MétodoPathScopeGET \u002F POST\u002Fservicesconfig:read \u002F config:writeGET \u002F POST\u002Fresourcesconfig:read \u002F config:writeGET\u002Fresource-groupsconfig:readPOST\u002Fschedules\u002F{id}\u002Foverridesconfig:write",{"id":377,"title":378,"titles":379,"content":380,"level":90},"\u002Fdocs\u002Fapi\u002Fendpoints#clientes-y-conversaciones","Clientes y conversaciones",[61],"MétodoPathScopeGET\u002Fcustomerscustomers:readGET\u002Fconversationsmessages:readGET \u002F POST\u002Fconversations\u002F{id}\u002Fmessagesmessages:read \u002F messages:write",{"id":382,"title":383,"titles":384,"content":385,"level":90},"\u002Fdocs\u002Fapi\u002Fendpoints#plataforma","Plataforma",[61],"MétodoPathScopeGET\u002FmecualquieraGET \u002F POST\u002Fwebhook-endpointswebhooks:manage",{"id":387,"title":388,"titles":389,"content":390,"level":90},"\u002Fdocs\u002Fapi\u002Fendpoints#ejemplo-slots","Ejemplo: slots",[61],"GET \u002Fv1\u002Fslots?service_id=svc_laser&from=2026-10-20T09:00:00-03:00&to=2026-10-20T20:00:00-03:00&around=2026-10-20T18:00:00-03:00 {\n  \"data\": [\n    { \"start\": \"2026-10-20T17:45:00-03:00\", \"end\": \"2026-10-20T18:30:00-03:00\", \"resource_ids\": [\"res_ana\", \"res_laser1\", \"res_room2\"] },\n    { \"start\": \"2026-10-20T18:45:00-03:00\", \"end\": \"2026-10-20T19:30:00-03:00\", \"resource_ids\": [\"res_carla\", \"res_laser1\", \"res_room1\"] }\n  ],\n  \"unavailable_reason\": null\n}",{"id":392,"title":393,"titles":394,"content":395,"level":90},"\u002Fdocs\u002Fapi\u002Fendpoints#ejemplo-objeto-de-reserva","Ejemplo: objeto de reserva",[61],"{\n  \"id\": \"bkg_7Qx1\",\n  \"status\": \"confirmed\",\n  \"service_id\": \"svc_laser\",\n  \"start\": \"2026-10-20T17:45:00-03:00\",\n  \"end\": \"2026-10-20T18:30:00-03:00\",\n  \"party_size\": 1,\n  \"customer\": { \"id\": \"cus_31\", \"name\": \"Marina\", \"phone\": \"+5521988887777\", \"locale\": \"pt\" },\n  \"allocations\": [\n    { \"resource_id\": \"res_ana\", \"start\": \"2026-10-20T17:45:00-03:00\", \"end\": \"2026-10-20T18:40:00-03:00\", \"units\": 1 },\n    { \"resource_id\": \"res_laser1\", \"start\": \"2026-10-20T17:45:00-03:00\", \"end\": \"2026-10-20T18:40:00-03:00\", \"units\": 1 },\n    { \"resource_id\": \"res_room2\", \"start\": \"2026-10-20T17:45:00-03:00\", \"end\": \"2026-10-20T18:40:00-03:00\", \"units\": 1 }\n  ],\n  \"source\": \"whatsapp\",\n  \"created_at\": \"2026-10-19T11:02:13-03:00\"\n} Las asignaciones incluyen el buffer (acá, 10 minutos después del servicio). html pre.shiki code .szBVR, html code.shiki .szBVR{--shiki-default:#D73A49;--shiki-dark:#F97583}html pre.shiki code .sVt8B, html code.shiki .sVt8B{--shiki-default:#24292E;--shiki-dark:#E1E4E8}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html pre.shiki code .sj4cs, html code.shiki .sj4cs{--shiki-default:#005CC5;--shiki-dark:#79B8FF}html pre.shiki code .sZZnC, html code.shiki .sZZnC{--shiki-default:#032F62;--shiki-dark:#9ECBFF}",{"id":66,"title":65,"titles":397,"content":398,"level":84},[],"Eventos firmados de reservas y conversaciones, con reintentos automáticos.",{"id":400,"title":401,"titles":402,"content":403,"level":90},"\u002Fdocs\u002Fapi\u002Fwebhooks#eventos","Eventos",[65],"EventoCuándobooking.createdSe creó una pre-reserva o reservabooking.confirmedSe confirmó una reservabooking.cancelledCancelada o vencidabooking.rescheduledSe movió de horario (el payload trae el id viejo y el nuevo)booking.no_showMarcada como ausenciabooking.completedAtención completadapayment.paidReservado: todavía no se emite (seña por Pix: próximamente)message.receivedLlegó un mensaje de un clienteconversation.handoffUna conversación se derivó a una persona Creá endpoints con POST \u002Fv1\u002Fwebhook-endpoints. El secreto de firma se muestra una sola vez.",{"id":405,"title":406,"titles":407,"content":408,"level":90},"\u002Fdocs\u002Fapi\u002Fwebhooks#payload","Payload",[65],"{\n  \"id\": \"evt_3f6c1d9e0b7a4c2f8e5d1a9b7c3e6f20\",\n  \"type\": \"booking.confirmed\",\n  \"created_at\": \"2026-10-14T15:21:07-03:00\",\n  \"workspace_id\": \"b3a6c8e2-5f1d-4c7a-9e0b-2d8f4a1c6e53\",\n  \"data\": { \"booking\": { \"id\": \"6d1f0c4a-7b2e-4a58-9c3d-0e5f8a2b1c47\", \"status\": \"confirmed\", \"start_at\": \"2026-10-15T12:45:00+00:00\" } }\n} La entrega es al menos una vez: usá el id para ignorar duplicados.",{"id":410,"title":411,"titles":412,"content":413,"level":90},"\u002Fdocs\u002Fapi\u002Fwebhooks#verificar-la-firma","Verificar la firma",[65],"Cada request trae el header: Wagend-Signature: t=1791040867,v1=5c2b9f...e81 v1 es HMAC-SHA256(secreto, t + \".\" + body_crudo) en hexadecimal. Rechazá requests de más de 5 minutos. import crypto from 'node:crypto'\n\nexport function verifyWagend(rawBody: string, header: string, secret: string) {\n  const parts = Object.fromEntries(header.split(',').map((p) => p.split('=') as [string, string]))\n  const age = Math.abs(Date.now() \u002F 1000 - Number(parts.t))\n  if (!parts.t || !parts.v1 || age > 300) return false\n  const expected = crypto.createHmac('sha256', secret).update(`${parts.t}.${rawBody}`).digest('hex')\n  return crypto.timingSafeEqual(Buffer.from(expected), Buffer.from(parts.v1))\n} import hashlib, hmac, time\n\ndef verify_wagend(raw_body: bytes, header: str, secret: str) -> bool:\n    parts = dict(p.split(\"=\", 1) for p in header.split(\",\"))\n    if abs(time.time() - int(parts.get(\"t\", \"0\"))) > 300:\n        return False\n    signed = f\"{parts['t']}.\".encode() + raw_body\n    expected = hmac.new(secret.encode(), signed, hashlib.sha256).hexdigest()\n    return hmac.compare_digest(expected, parts.get(\"v1\", \"\"))",{"id":415,"title":416,"titles":417,"content":418,"level":90},"\u002Fdocs\u002Fapi\u002Fwebhooks#reintentos","Reintentos",[65],"Respondé con cualquier 2xx en menos de 10 segundos. Si no, reintentamos a los 1 min, 5 min, 30 min, 2 h y 12 h. Cada intento se ve en el log de entregas, donde también podés reenviar a mano.",{"id":420,"title":421,"titles":422,"content":423,"level":90},"\u002Fdocs\u002Fapi\u002Fwebhooks#seguridad-y-límites","Seguridad y límites",[65],"La URL debe ser https y resolver a una dirección pública: rechazamos localhost, redes privadas, link-local y direcciones de metadatos de nube (al registrar y en cada entrega). No seguimos redirecciones (un 3xx cuenta como fallo).Headers extra: Wagend-Event (tipo) y Wagend-Delivery (id de la entrega). Cada intento se firma con un timestamp nuevo.Hasta 10 endpoints por workspace. Tras 10 fallos consecutivos el endpoint se desactiva (reactivalo con PATCH \u002Fv1\u002Fwebhook-endpoints\u002F{id} y {\"active\": true}).POST \u002Fv1\u002Fwebhook-endpoints\u002F{id}\u002Fping envía un evento de prueba webhook.ping; POST \u002Fv1\u002Fwebhook-endpoints\u002F{id}\u002Frotate-secret genera un secreto nuevo (se muestra una sola vez; el anterior deja de valer al instante).Con API key usá el scope webhooks:manage. El log está en GET \u002Fv1\u002Fwebhook-endpoints\u002F{id}\u002Fdeliveries y el reenvío en POST …\u002Fdeliveries\u002F{delivery_id}\u002Fresend. html pre.shiki code .sVt8B, html code.shiki .sVt8B{--shiki-default:#24292E;--shiki-dark:#E1E4E8}html pre.shiki code .sj4cs, html code.shiki .sj4cs{--shiki-default:#005CC5;--shiki-dark:#79B8FF}html pre.shiki code .sZZnC, html code.shiki .sZZnC{--shiki-default:#032F62;--shiki-dark:#9ECBFF}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html pre.shiki code .szBVR, html code.shiki .szBVR{--shiki-default:#D73A49;--shiki-dark:#F97583}html pre.shiki code .sScJk, html code.shiki .sScJk{--shiki-default:#6F42C1;--shiki-dark:#B392F0}html pre.shiki code .s4XuR, html code.shiki .s4XuR{--shiki-default:#E36209;--shiki-dark:#FFAB70}",{"id":70,"title":69,"titles":425,"content":426,"level":84},[],"Dejá que Claude, ChatGPT o tu propio agente busque horarios, reserve y opere un negocio por Model Context Protocol. Próximamente: el servidor MCP todavía no está disponible. Esta página describe lo previsto. Wagend expone un servidor MCP para que los agentes de IA usen el mismo motor que el bot de WhatsApp: mismas pre-reservas, misma validación, mismo registro de auditoría.",{"id":428,"title":429,"titles":430,"content":431,"level":90},"\u002Fdocs\u002Fmcp#conectar","Conectar",[69],"URL: https:\u002F\u002Fmcp.wagend.app (Streamable HTTP)Autenticación: una clave de API en el header Authorization. OAuth llega más adelante. Ejemplo de configuración del cliente: {\n  \"mcpServers\": {\n    \"wagend\": {\n      \"type\": \"http\",\n      \"url\": \"https:\u002F\u002Fmcp.wagend.app\",\n      \"headers\": { \"Authorization\": \"Bearer wg_live_...\" }\n    }\n  }\n}",{"id":433,"title":434,"titles":435,"content":436,"level":90},"\u002Fdocs\u002Fmcp#conjuntos-de-herramientas","Conjuntos de herramientas",[69],"Las herramientas que ve el agente dependen de los scopes de la clave. Reservas (slots:read, bookings:write) — para asistentes que reservan en nombre de un cliente: HerramientaHacelist_servicesServicios con duración y preciofind_slotsHorarios disponibles para un servicio y un rango de fechashold_slotPre-reserva de 10 minutosconfirm_bookingConfirma una pre-reserva con los datos del clientecancel_booking, reschedule_booking, get_bookingGestiona una reserva existente Administración (config:write) — para que el dueño opere el negocio desde su asistente de IA: HerramientaHacelist_resources, list_todayEquipo, salas, máquinas y agenda del díablock_timeBloquea un recurso (vacaciones, mantenimiento)create_service, update_scheduleCambia el catálogo y los horariosget_statsReservas, ocupación y ausencias",{"id":438,"title":439,"titles":440,"content":441,"level":90},"\u002Fdocs\u002Fmcp#ejemplos-de-pedidos","Ejemplos de pedidos",[69],"\"Reservame un corte con Juan mañana a la mañana, a nombre de Carlos.\"\"Bloqueá la máquina de láser el lunes que viene por mantenimiento y decime qué reservas quedan afectadas.\"\"¿Cuántas ausencias tuvimos este mes?\"",{"id":443,"title":444,"titles":445,"content":446,"level":90},"\u002Fdocs\u002Fmcp#docs-para-llms","Docs para LLMs",[69],"\u002Fllms.txt lista todas las páginas de la documentación.\u002Fllms-full.txt contiene la documentación completa en inglés, en Markdown. html pre.shiki code .sVt8B, html code.shiki .sVt8B{--shiki-default:#24292E;--shiki-dark:#E1E4E8}html pre.shiki code .sj4cs, html code.shiki .sj4cs{--shiki-default:#005CC5;--shiki-dark:#79B8FF}html pre.shiki code .sZZnC, html code.shiki .sZZnC{--shiki-default:#032F62;--shiki-dark:#9ECBFF}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}",{"id":74,"title":73,"titles":448,"content":449,"level":84},[],"Cómo modelar una barbería, un centro de estética, un consultorio, un restaurante y entregas. Cada receta corresponde a un modelo listo que elegís en el onboarding.",{"id":451,"title":452,"titles":453,"content":454,"level":90},"\u002Fdocs\u002Frecipes#barbería","Barbería",[73],"Cada barbero es un recurso staff exclusive con su propio horario. Un grupo, customer_choice con round_robin como alternativa. {\n  \"name\": \"Corte\",\n  \"duration_min\": 30,\n  \"step_min\": 15,\n  \"buffer_after_min\": 5,\n  \"price_cents\": 5000,\n  \"requirements\": [{ \"resource_group_id\": \"grp_barbers\", \"units\": 1 }]\n}",{"id":456,"title":457,"titles":458,"content":459,"level":90},"\u002Fdocs\u002Frecipes#estética","Estética",[73],"Profesionales, máquinas y cabinas son recursos separados. El servicio pide los tres al mismo tiempo, así que el más escaso (casi siempre la máquina) limita la agenda. {\n  \"name\": \"Depilación láser\",\n  \"duration_min\": 45,\n  \"buffer_after_min\": 10,\n  \"price_cents\": 18000,\n  \"deposit_cents\": 5000,\n  \"requirements\": [\n    { \"resource_group_id\": \"grp_professionals\", \"units\": 1 },\n    { \"resource_group_id\": \"grp_lasers\", \"units\": 1 },\n    { \"resource_group_id\": \"grp_rooms\", \"units\": 1 }\n  ]\n}",{"id":461,"title":462,"titles":463,"content":464,"level":90},"\u002Fdocs\u002Frecipes#clínica","Clínica",[73],"Médico más consultorio, por sede (un workspace por sede). Los datos de salud son sensibles: el asistente nunca pregunta síntomas y el formulario pide solo lo necesario para reservar. {\n  \"name\": \"Consulta\",\n  \"duration_min\": 30,\n  \"buffer_after_min\": 10,\n  \"intake_form\": { \"type\": \"object\", \"properties\": { \"obra_social\": { \"type\": \"string\" } } },\n  \"requirements\": [\n    { \"resource_group_id\": \"grp_doctors\", \"units\": 1 },\n    { \"resource_group_id\": \"grp_offices\", \"units\": 1 }\n  ]\n}",{"id":466,"title":467,"titles":468,"content":469,"level":90},"\u002Fdocs\u002Frecipes#restaurante","Restaurante",[73],"El salón es un recurso pooled con 40 unidades (cubiertos) por turno. La duración crece con el tamaño del grupo, y los grupos grandes pagan seña. {\n  \"name\": \"Mesa\",\n  \"step_min\": 30,\n  \"duration_by_units\": [\n    { \"max_units\": 2, \"duration_min\": 90 },\n    { \"max_units\": 4, \"duration_min\": 120 },\n    { \"max_units\": 20, \"duration_min\": 150 }\n  ],\n  \"requirements\": [{ \"resource_group_id\": \"grp_dining_room\", \"units\": \"party_size\" }]\n} El modo mesas (mesas puntuales con tamaño mínimo y máximo, y combinaciones) está en el roadmap.",{"id":471,"title":472,"titles":473,"content":474,"level":90},"\u002Fdocs\u002Frecipes#entregas","Entregas",[73],"Cada zona es un recurso pooled con capacidad por ventana de 2 horas. La zona se elige por código postal, y una regla de corte cierra las ventanas del mismo día al mediodía. {\n  \"name\": \"Entrega\",\n  \"window_mode\": true,\n  \"duration_min\": 120,\n  \"cutoff_rule\": { \"same_day_until\": \"12:00\" },\n  \"intake_form\": { \"type\": \"object\", \"required\": [\"address\", \"postal_code\"] },\n  \"requirements\": [{ \"resource_group_id\": \"grp_zones\", \"units\": 1, \"select_by\": \"postal_code\" }]\n} html pre.shiki code .sVt8B, html code.shiki .sVt8B{--shiki-default:#24292E;--shiki-dark:#E1E4E8}html pre.shiki code .sj4cs, html code.shiki .sj4cs{--shiki-default:#005CC5;--shiki-dark:#79B8FF}html pre.shiki code .sZZnC, html code.shiki .sZZnC{--shiki-default:#032F62;--shiki-dark:#9ECBFF}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}",{"id":78,"title":77,"titles":476,"content":477,"level":84},[],"Pon el asistente de Wagend en tu sitio con una sola línea de script, sin número de WhatsApp. El WebChat es un widget de chat que tu negocio pega en su propio sitio. Conversa con el mismo bot de WhatsApp (mismos horarios, precios y reservas), pero sin número ni aprobaciones de terceros: ideal para probar y como vitrina en tu web.",{"id":479,"title":480,"titles":481,"content":482,"level":90},"\u002Fdocs\u002Fwebchat#instalar","Instalar",[77],"En el panel, como owner, publica el WebChat e indica los dominios permitidos (por ejemplo https:\u002F\u002Fwww.mitienda.com). Recibes una clave publicable wg_web_….Pega el snippet antes de \u003C\u002Fbody>: \u003Cscript src=\"https:\u002F\u002Fwagend.app\u002Fwidget.js\" data-key=\"wg_web_…\" defer>\u003C\u002Fscript> Atributos opcionales: data-locale (pt, es o en; por defecto usa el idioma del navegador) y data-api (origen de la API, solo para entornos de prueba). Color, posición y título vienen de la configuración del workspace. Hay una página de demostración en \u002Fdemo\u002Fwebchat donde pegas la clave y ves el widget funcionando.",{"id":484,"title":485,"titles":486,"content":487,"level":90},"\u002Fdocs\u002Fwebchat#qué-ve-el-visitante","Qué ve el visitante",[77],"Un botón flotante que abre el chat; textos en portugués, español o inglés.Nombre y teléfono son opcionales y no se verifican: no identifican al visitante ni se unen a clientes existentes.La conversación vive en la memoria de la página: al recargar empieza una nueva. No se guarda nada en el navegador.",{"id":489,"title":490,"titles":491,"content":492,"level":90},"\u002Fdocs\u002Fwebchat#seguridad","Seguridad",[77],"La clave publicable solo abre conversaciones anónimas: no da acceso al panel, a la API privada ni a datos de clientes. Se puede revocar en cualquier momento (y rota al publicar de nuevo).El workspace sale siempre de la clave; el widget nunca envía un workspace_id.Solo los dominios permitidos pueden usar el chat (CORS por workspace). Sin cookies.El chequeo de Origin no es autenticación. Solo protege contra otros sitios web en un navegador; cualquier cliente que no sea un navegador (un script, curl) puede enviar el Origin que quiera. Por eso la clave publicable no es un secreto y la protección real son los límites de uso, no el origen.Topes de costo: mensajes por conversación y por hora, mensajes diarios por workspace, conversaciones nuevas por hora y conexiones en vivo simultáneas. Al agotarse, la API responde 429 con Retry-After y el asistente no se invoca. Las conversaciones inactivas vencen solas y se purgan, incluido el nombre declarado del visitante.Límites de uso por IP, por conversación y por workspace; mensajes de hasta 1000 caracteres.El texto del visitante es un dato no confiable para el asistente, y el widget muestra todo texto como texto plano (nunca HTML).El chat es solo reactivo: no envía recordatorios ni mensajes proactivos.",{"id":494,"title":48,"titles":495,"content":496,"level":90},"\u002Fdocs\u002Fwebchat#api",[77],"Gestión (owner, cookie de panel): GET|PUT|DELETE \u002Fv1\u002Fwebchat-site. Públicos: GET \u002Fv1\u002Fpublic\u002Fwebchat\u002Fconfig, POST \u002Fv1\u002Fpublic\u002Fwebchat\u002Fsessions, GET|POST \u002Fv1\u002Fpublic\u002Fwebchat\u002Fsessions\u002F{id}\u002Fmessages y GET \u002Fv1\u002Fpublic\u002Fwebchat\u002Fsessions\u002F{id}\u002Fevents (SSE). El contrato está en packages\u002Fopenapi\u002Fopenapi.yaml. Desactivado por defecto (PUBLIC_WEBCHAT_ENABLED=false) hasta la revisión de seguridad y la activación explícita. html pre.shiki code .sVt8B, html code.shiki .sVt8B{--shiki-default:#24292E;--shiki-dark:#E1E4E8}html pre.shiki code .s9eBZ, html code.shiki .s9eBZ{--shiki-default:#22863A;--shiki-dark:#85E89D}html pre.shiki code .sScJk, html code.shiki .sScJk{--shiki-default:#6F42C1;--shiki-dark:#B392F0}html pre.shiki code .sZZnC, html code.shiki .sZZnC{--shiki-default:#032F62;--shiki-dark:#9ECBFF}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}",{"id":498,"title":77,"badge":499,"body":500,"description":768,"extension":769,"meta":770,"navigation":771,"path":78,"rawbody":772,"seo":773,"stem":79,"__hash__":774},"docs_es\u002Fdocs\u002F9.webchat.md","Borrador",{"type":501,"value":502,"toc":761},"minimark",[503,512,516,551,602,625,636,639,659,662,721,724,747,757],[504,505,506,507,511],"p",{},"El WebChat es un widget de chat que tu negocio pega en su propio sitio. Conversa con el ",[508,509,510],"strong",{},"mismo bot"," de WhatsApp (mismos horarios, precios y reservas), pero sin número ni aprobaciones de terceros: ideal para probar y como vitrina en tu web.",[513,514,480],"h2",{"id":515},"instalar",[517,518,519,544],"ol",{},[520,521,522,523,526,527,530,531,535,536,539,540,543],"li",{},"En el panel, como ",[508,524,525],{},"owner",", publica el WebChat e indica los ",[508,528,529],{},"dominios permitidos"," (por ejemplo ",[532,533,534],"code",{},"https:\u002F\u002Fwww.mitienda.com","). Recibes una ",[508,537,538],{},"clave publicable"," ",[532,541,542],{},"wg_web_…",".",[520,545,546,547,550],{},"Pega el snippet antes de ",[532,548,549],{},"\u003C\u002Fbody>",":",[552,553,558],"pre",{"className":554,"code":555,"language":556,"meta":557,"style":557},"language-html shiki shiki-themes github-light github-dark","\u003Cscript src=\"https:\u002F\u002Fwagend.app\u002Fwidget.js\" data-key=\"wg_web_…\" defer>\u003C\u002Fscript>\n","html","",[532,559,560],{"__ignoreMap":557},[561,562,564,568,572,576,579,583,586,588,591,594,597,599],"span",{"class":563,"line":84},"line",[561,565,567],{"class":566},"sVt8B","\u003C",[561,569,571],{"class":570},"s9eBZ","script",[561,573,575],{"class":574},"sScJk"," src",[561,577,578],{"class":566},"=",[561,580,582],{"class":581},"sZZnC","\"https:\u002F\u002Fwagend.app\u002Fwidget.js\"",[561,584,585],{"class":574}," data-key",[561,587,578],{"class":566},[561,589,590],{"class":581},"\"wg_web_…\"",[561,592,593],{"class":574}," defer",[561,595,596],{"class":566},">\u003C\u002F",[561,598,571],{"class":570},[561,600,601],{"class":566},">\n",[504,603,604,605,608,609,612,613,616,617,620,621,624],{},"Atributos opcionales: ",[532,606,607],{},"data-locale"," (",[532,610,611],{},"pt",", ",[532,614,615],{},"es"," o ",[532,618,619],{},"en","; por defecto usa el idioma del navegador) y ",[532,622,623],{},"data-api"," (origen de la API, solo para entornos de prueba). Color, posición y título vienen de la configuración del workspace.",[626,627,629],"callout",{"type":628},"tip",[504,630,631,632,635],{},"Hay una página de demostración en ",[532,633,634],{},"\u002Fdemo\u002Fwebchat"," donde pegas la clave y ves el widget funcionando.",[513,637,485],{"id":638},"qué-ve-el-visitante",[640,641,642,645,656],"ul",{},[520,643,644],{},"Un botón flotante que abre el chat; textos en portugués, español o inglés.",[520,646,647,648,651,652,655],{},"Nombre y teléfono son ",[508,649,650],{},"opcionales"," y ",[508,653,654],{},"no se verifican",": no identifican al visitante ni se unen a clientes existentes.",[520,657,658],{},"La conversación vive en la memoria de la página: al recargar empieza una nueva. No se guarda nada en el navegador.",[513,660,490],{"id":661},"seguridad",[640,663,664,671,677,680,697,708,711,718],{},[520,665,666,667,670],{},"La clave publicable solo abre conversaciones anónimas: ",[508,668,669],{},"no"," da acceso al panel, a la API privada ni a datos de clientes. Se puede revocar en cualquier momento (y rota al publicar de nuevo).",[520,672,673,674,543],{},"El workspace sale siempre de la clave; el widget nunca envía un ",[532,675,676],{},"workspace_id",[520,678,679],{},"Solo los dominios permitidos pueden usar el chat (CORS por workspace). Sin cookies.",[520,681,682,689,690,693,694,696],{},[508,683,684,685,688],{},"El chequeo de ",[532,686,687],{},"Origin"," no es autenticación."," Solo protege contra otros sitios web en un navegador; cualquier cliente que no sea un navegador (un script, ",[532,691,692],{},"curl",") puede enviar el ",[532,695,687],{}," que quiera. Por eso la clave publicable no es un secreto y la protección real son los límites de uso, no el origen.",[520,698,699,700,703,704,707],{},"Topes de costo: mensajes por conversación y por hora, mensajes diarios por workspace, conversaciones nuevas por hora y conexiones en vivo simultáneas. Al agotarse, la API responde ",[532,701,702],{},"429"," con ",[532,705,706],{},"Retry-After"," y el asistente no se invoca. Las conversaciones inactivas vencen solas y se purgan, incluido el nombre declarado del visitante.",[520,709,710],{},"Límites de uso por IP, por conversación y por workspace; mensajes de hasta 1000 caracteres.",[520,712,713,714,717],{},"El texto del visitante es un ",[508,715,716],{},"dato no confiable"," para el asistente, y el widget muestra todo texto como texto plano (nunca HTML).",[520,719,720],{},"El chat es solo reactivo: no envía recordatorios ni mensajes proactivos.",[513,722,48],{"id":723},"api",[504,725,726,727,730,731,612,734,612,737,651,740,743,744,543],{},"Gestión (owner, cookie de panel): ",[532,728,729],{},"GET|PUT|DELETE \u002Fv1\u002Fwebchat-site",". Públicos: ",[532,732,733],{},"GET \u002Fv1\u002Fpublic\u002Fwebchat\u002Fconfig",[532,735,736],{},"POST \u002Fv1\u002Fpublic\u002Fwebchat\u002Fsessions",[532,738,739],{},"GET|POST \u002Fv1\u002Fpublic\u002Fwebchat\u002Fsessions\u002F{id}\u002Fmessages",[532,741,742],{},"GET \u002Fv1\u002Fpublic\u002Fwebchat\u002Fsessions\u002F{id}\u002Fevents"," (SSE). El contrato está en ",[532,745,746],{},"packages\u002Fopenapi\u002Fopenapi.yaml",[626,748,750],{"type":749},"warning",[504,751,752,753,756],{},"Desactivado por defecto (",[532,754,755],{},"PUBLIC_WEBCHAT_ENABLED=false",") hasta la revisión de seguridad y la activación explícita.",[758,759,760],"style",{},"html pre.shiki code .sVt8B, html code.shiki .sVt8B{--shiki-default:#24292E;--shiki-dark:#E1E4E8}html pre.shiki code .s9eBZ, html code.shiki .s9eBZ{--shiki-default:#22863A;--shiki-dark:#85E89D}html pre.shiki code .sScJk, html code.shiki .sScJk{--shiki-default:#6F42C1;--shiki-dark:#B392F0}html pre.shiki code .sZZnC, html code.shiki .sZZnC{--shiki-default:#032F62;--shiki-dark:#9ECBFF}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}",{"title":557,"searchDepth":90,"depth":762,"links":763},3,[764,765,766,767],{"id":515,"depth":90,"text":480},{"id":638,"depth":90,"text":485},{"id":661,"depth":90,"text":490},{"id":723,"depth":90,"text":48},"Pon el asistente de Wagend en tu sitio con una sola línea de script, sin número de WhatsApp.","md",{},true,"---\ntitle: WebChat en tu sitio\ndescription: Pon el asistente de Wagend en tu sitio con una sola línea de script, sin número de WhatsApp.\nbadge: Borrador\n---\n\nEl WebChat es un widget de chat que tu negocio pega en su propio sitio. Conversa con el **mismo bot** de WhatsApp (mismos horarios, precios y reservas), pero sin número ni aprobaciones de terceros: ideal para probar y como vitrina en tu web.\n\n## Instalar\n\n1. En el panel, como **owner**, publica el WebChat e indica los **dominios permitidos** (por ejemplo `https:\u002F\u002Fwww.mitienda.com`). Recibes una **clave publicable** `wg_web_…`.\n2. Pega el snippet antes de `\u003C\u002Fbody>`:\n\n```html\n\u003Cscript src=\"https:\u002F\u002Fwagend.app\u002Fwidget.js\" data-key=\"wg_web_…\" defer>\u003C\u002Fscript>\n```\n\nAtributos opcionales: `data-locale` (`pt`, `es` o `en`; por defecto usa el idioma del navegador) y `data-api` (origen de la API, solo para entornos de prueba). Color, posición y título vienen de la configuración del workspace.\n\n::callout{type=\"tip\"}\nHay una página de demostración en `\u002Fdemo\u002Fwebchat` donde pegas la clave y ves el widget funcionando.\n::\n\n## Qué ve el visitante\n\n- Un botón flotante que abre el chat; textos en portugués, español o inglés.\n- Nombre y teléfono son **opcionales** y **no se verifican**: no identifican al visitante ni se unen a clientes existentes.\n- La conversación vive en la memoria de la página: al recargar empieza una nueva. No se guarda nada en el navegador.\n\n## Seguridad\n\n- La clave publicable solo abre conversaciones anónimas: **no** da acceso al panel, a la API privada ni a datos de clientes. Se puede revocar en cualquier momento (y rota al publicar de nuevo).\n- El workspace sale siempre de la clave; el widget nunca envía un `workspace_id`.\n- Solo los dominios permitidos pueden usar el chat (CORS por workspace). Sin cookies.\n- **El chequeo de `Origin` no es autenticación.** Solo protege contra otros sitios web en un navegador; cualquier cliente que no sea un navegador (un script, `curl`) puede enviar el `Origin` que quiera. Por eso la clave publicable no es un secreto y la protección real son los límites de uso, no el origen.\n- Topes de costo: mensajes por conversación y por hora, mensajes diarios por workspace, conversaciones nuevas por hora y conexiones en vivo simultáneas. Al agotarse, la API responde `429` con `Retry-After` y el asistente no se invoca. Las conversaciones inactivas vencen solas y se purgan, incluido el nombre declarado del visitante.\n- Límites de uso por IP, por conversación y por workspace; mensajes de hasta 1000 caracteres.\n- El texto del visitante es un **dato no confiable** para el asistente, y el widget muestra todo texto como texto plano (nunca HTML).\n- El chat es solo reactivo: no envía recordatorios ni mensajes proactivos.\n\n## API\n\nGestión (owner, cookie de panel): `GET|PUT|DELETE \u002Fv1\u002Fwebchat-site`. Públicos: `GET \u002Fv1\u002Fpublic\u002Fwebchat\u002Fconfig`, `POST \u002Fv1\u002Fpublic\u002Fwebchat\u002Fsessions`, `GET|POST \u002Fv1\u002Fpublic\u002Fwebchat\u002Fsessions\u002F{id}\u002Fmessages` y `GET \u002Fv1\u002Fpublic\u002Fwebchat\u002Fsessions\u002F{id}\u002Fevents` (SSE). El contrato está en `packages\u002Fopenapi\u002Fopenapi.yaml`.\n\n::callout{type=\"warning\"}\nDesactivado por defecto (`PUBLIC_WEBCHAT_ENABLED=false`) hasta la revisión de seguridad y la activación explícita.\n::\n",{"title":77,"description":768},"1flc71L-i-hWxdTgVkIeJGDu6cG8b0MvfA82XEkAekM",[776,778],{"title":73,"path":74,"stem":75,"description":777,"children":-1},"Cómo modelar una barbería, un centro de estética, un consultorio, un restaurante y entregas.",null,1790998345295]