Skip to main content
Todo lo que necesitas para integrarte, de principio a fin. Los endpoints en detalle, con un playground para probarlos, están en la pestaña Referencia.

Autenticación

Cómo obtener y usar la API key de tu organización. Toda solicitud lleva la API key de tu organización como bearer token:

Obtener una key

Las API keys las emite el equipo de Revem para tu organización. Escríbenos a soporte@revem.ai indicando para qué sistema es; te entregamos la key por un canal seguro.
La key completa se muestra una sola vez. Revem guarda sólo un hash del secreto y no puede recuperarla: si se pierde, emitimos una nueva y revocamos la anterior.

Forma de la key

Una key tiene la forma rvm_<prefijo>.<secreto>. El prefijo identifica la key en nuestros registros y puedes mencionarlo en un correo de soporte sin riesgo; el secreto nunca debe salir de tu servidor.

Buenas prácticas

  • Guárdala como secreto en tu backend (variables de entorno, gestor de secretos). Nunca en el código fuente, en un repositorio ni en el navegador.
  • Una key por sistema. Si tienes más de un servicio que hablan con Revem, pide una key para cada uno: revocar una no interrumpe al otro.
  • Rotación. Pide la nueva key, cámbiala en tu sistema y avísanos para revocar la anterior. La key vieja sigue funcionando hasta que se revoca, así que no hay corte.
  • Nunca desde el navegador. Las rutas de webchat en particular confían en la identidad del visitante que tu backend afirma; expuestas al cliente, cualquiera podría escribir como cualquiera dentro de tu organización. Ver Webchat.

Respuestas de autenticación

401
403

Errores y límites

Códigos de estado, forma de los errores y límite de solicitudes.

Códigos de estado

Forma de los errores

Los errores incluyen una clave error y pueden incluir ok: false y message; por ejemplo, algunos errores de autenticación omiten ok. Qué contiene error depende del módulo:
error es la etiqueta del código HTTP y message explica el problema. El 422 por atributos desconocidos agrega unknownAttributes con los nombres que no existen.
Los errores de validación (400) describen el campo con la notación de la API: body/phone_number, querystring/limit, params/id.

Límite de solicitudes

Cada API key puede hacer 600 solicitudes por minuto, sumando todos los endpoints. Al superarlo, la API responde 429 y no procesa la solicitud.
Las respuestas incluyen headers para que tu cliente se regule sin llegar al límite:
Para una sincronización masiva, respeta retry-after y reintenta con espera exponencial. Si necesitas un límite mayor de forma sostenida, escríbenos.

Idempotencia y reintentos

  • Puedes reintentar una lectura GET. Al reintentar una escritura, conserva el mismo destino y los mismos valores; una escritura puede actualizar updated_at aunque repita datos.
  • POST /contacts/public/v1 y POST /organizations/public/v1 son upserts por teléfono y tax_id, respectivamente: con la identidad sin cambios, repetirlos reutiliza el mismo registro.
  • Si un PATCH por tax_id cambia el identificador, repetir la URL antigua puede responder 404 o alcanzar otro registro si ese identificador fue reutilizado. Guarda el ID de Revem y consulta GET /organizations/public/v1/{id} antes de reintentar un cambio de identidad ambiguo.
  • POST /webchat/public/v1/messages no es idempotente: cada llamada registra un mensaje nuevo. Reintenta sólo si no recibiste respuesta, y evita duplicar un mensaje que sí llegó.

Contactos

Cómo mantener tu base de clientes al día en Revem desde tu CRM, tu tienda o tu ERP. Los endpoints de contactos viven bajo /contacts/public/v1. Un contacto tiene cuatro campos fijos —phone_number, first_name, last_name, email— y cualquier cantidad de atributos personalizados, que van al mismo nivel identificados por su nombre en Revem.

El teléfono identifica, el id persiste

Hay dos formas de escribir un contacto y conviene entender cuándo usar cada una:
1

Crear o actualizar por teléfono

POST /contacts/public/v1 recibe el teléfono y decide: si ya hay un contacto con ese número lo actualiza, si no lo crea. Es la llamada para una carga inicial y para sistemas que no guardan ids de Revem.
La respuesta trae el id del contacto y si fue creado (created: true) o actualizado.
2

Guardar el id y actualizar por id

Guarda ese id junto al cliente en tu sistema. Desde ahí, actualiza con PATCH /contacts/public/v1/{id}: acepta los mismos campos y aquí el teléfono es un campo más, así que un cliente que cambia de número sigue siendo el mismo contacto.
Con el upsert, ese mismo cambio habría creado un segundo contacto con la mitad del historial.

Reglas que conviene saber

Varios sistemas escriben sobre el mismo contacto (tu integración, el equipo desde la app, el agente). Por eso una solicitud parcial es una actualización parcial: sólo cambian las claves que envías. Enviar {"first_name": "Camila"} corrige el nombre y deja el apellido como estaba.Por la misma razón esta API no vacía campos: un email o un apellido en blanco se trata como ausente. Limpiar un dato es una acción deliberada desde la app.
Cualquier clave del cuerpo que no sea uno de los cuatro campos fijos se interpreta como un atributo personalizado y se busca por nombre entre los definidos para contactos en tu organización, sin distinguir mayúsculas.
  • Un nombre que no existe responde 422 con la lista en unknownAttributes. La API nunca crea definiciones por su cuenta: un error de tipeo sería un campo permanente.
  • Un valor que no calza con el tipo declarado (texto en un atributo numérico, por ejemplo) también responde 422.
  • Los valores pueden venir como texto aunque el atributo sea numérico o booleano; Revem los convierte según la definición.
  • Hasta 100 atributos por solicitud.
Los nombres id, created_at y updated_at están reservados para la lectura: enviarlos en un cuerpo responde 422.
Si el email que envías ya pertenece a otro contacto, la solicitud sí se aplica —nombre, apellido y atributos se guardan— y el email queda sin escribir, con un aviso en warnings. Revisa ese arreglo en tu integración: una respuesta 200 con avisos es información, no ruido.
Si el teléfono pertenece a un contacto que el equipo envió a la papelera, el upsert responde 409 en vez de resucitarlo en silencio. Restaurarlo o eliminarlo definitivamente se hace desde Contactos en la app. PATCH /{id} sobre ese contacto responde 404, igual que GET /{id}: la API key no ve la papelera.
Recomendamos E.164 (+56912345678). Revem normaliza las grafías habituales al guardar y al buscar, así que el número con que creaste un contacto también lo encuentra en ?phone=. Un número que no se puede normalizar se guarda tal cual.

Leer contactos

GET /contacts/public/v1/{id} devuelve un contacto en la misma forma plana que acepta la escritura, con sus atributos personalizados por nombre. Un campo sin valor se omite; la excepción es phone_number, que siempre viene y puede ser null para un contacto que llegó por un canal sin teléfono.
GET /contacts/public/v1 lista los contactos del más reciente al más antiguo según su fecha de creación, paginados con limit (hasta 200) y offset, y acepta filtros por phone, email y updated_since. La respuesta trae has_more en lugar de un total.

Sincronización incremental

Para traer a tu sistema lo que cambió en Revem, recorre la lista con updated_since:
updated_since filtra pero no ordena: las páginas van por fecha de creación, así que un contacto editado mientras recorres las páginas puede quedar fuera de la que le correspondía. Solapa la ventana unos minutos con la corrida anterior en vez de empezar exactamente donde terminó la última; el upsert en tu lado hace que repetir un contacto sea inocuo.

Lo que la API no hace

  • No elimina contactos. Enviar un contacto a la papelera es una acción deliberada desde la app.
  • No une contactos duplicados. Dos contactos partidos por un cambio de número antes de usar PATCH /{id} se unen desde Contactos.
  • No expone el nombre compuesto. Publica first_name y last_name tal como están guardados; compón el nombre completo en tu lado si lo necesitas.

Organizaciones

Usa POST /organizations/public/v1 con tax_id y los campos que quieras sincronizar:
El identificador se normaliza quitando signos y convirtiendo a mayúsculas; conserva ceros iniciales. Dentro del tenant, dos sistemas que envían el mismo identificador actualizan la misma organización. Los campos nativos opcionales omitidos o vacíos mantienen el valor existente; tax_id es obligatorio en POST y, si se envía en PATCH, no puede quedar vacío. No se valida el dígito verificador de un RUT chileno. Los campos nativos no aceptan null. Los atributos personalizados se envían por nombre al mismo nivel, sin distinguir mayúsculas, y deben estar definidos para organizaciones; hasta 100 por solicitud. Los desconocidos, ambiguos o inválidos responden 422. id, created_at y updated_at son de sólo lectura. Las solicitudes de escritura admiten hasta 128 KiB. POST responde 200 con { ok, id, created, warnings }; created indica si se creó el registro. PATCH responde { ok, id, warnings }. warnings es un arreglo, actualmente vacío. Guarda id como identidad estable. Las lecturas devuelven campos snake_case y atributos por nombre; tax_id puede ser null en organizaciones preexistentes que no tienen identificador. Consulta o actualiza mediante GET/PATCH /organizations/public/v1/{id} o GET/PATCH /organizations/public/v1/by-tax-id/{tax_id}. PATCH no crea registros; el tax_id del cuerpo, si se envía, reemplaza el identificador actual. Codifica caracteres especiales en la URL. Un identificador que pertenece a otra organización responde 409 sin aplicar cambios parciales.
GET /organizations/public/v1 permite filtrar por tax_id o updated_since, y paginar con limit (50 por defecto, máximo 200) y offset (0 por defecto, máximo 1000000). La respuesta contiene organizations y has_more; este último indica si queda otra página. El orden es por creación, no por última modificación: solapa las ventanas de sincronización y deduplica por id. Reenviar campos con el mismo valor puede actualizar updated_at; un PATCH vacío o con sólo campos opcionales en blanco lo conserva. Las organizaciones de la papelera no aparecen en lecturas y el upsert las rechaza con 409. Las del simulador no existen para esta API: si sólo una de ellas tiene ese tax_id, el upsert crea la real.

Productos

Cómo sincronizar tu catálogo con Revem desde tu ERP o tu tienda.

El SKU identifica, el id persiste

Usa POST /products/public/v1 con sku, name y price. Si ya existe un producto con ese SKU dentro de tu organización se actualiza; si no, se crea.
La respuesta es { ok, id, created, warnings }; created indica si se creó el registro. Guarda el id: es la identidad estable y es lo que te permite cambiarle el SKU después con PATCH /products/public/v1/{id}. El upsert resuelve por SKU, así que mandarle uno nuevo crearía un segundo producto con la mitad de la historia — eso es exactamente lo que la ruta por id evita. Si tu sistema no guarda nuestros ids, usa PATCH /products/public/v1/by-sku/{sku}. No crea productos: un SKU que no existe responde 404, no lo da de alta. Codifica los caracteres especiales en la URL.

Campos

sku, name y price son obligatorios en POST. Todo lo demás es opcional, y una clave ausente deja el valor guardado como está: una solicitud parcial es una actualización parcial. Un PATCH que no termina cambiando ningún campo responde 200 sin tocar nada, así que un sync idempotente puede reenviar el mismo cuerpo sin interpretarlo como que el producto desapareció. Una cadena vacía no borra una descripción guardada. id, externally_managed, created_at y updated_at son de sólo lectura y enviarlos responde 422. Las solicitudes de escritura admiten hasta 128 KiB.

Atributos personalizados

Van al mismo nivel que los campos de la tabla, identificados por su nombre en Revem y sin distinguir mayúsculas. A diferencia de un campo libre, tienen que estar definidos para productos antes de enviarlos: créalos en Productos.
  • Un nombre sin definición responde 422 con la lista en unknownAttributes. No se crea la definición sola: un typo se volvería un campo permanente en todos tus pickers.
  • Un obligatorio que falta responde 422 con la lista en missingAttributes, no en unknownAttributes: esos nombres sí existen, así que no hay que crearlos — hay que enviarlos.
  • Un nombre que coincide con más de una definición responde 422 en vez de elegir una.
  • Un valor que no calza con el tipo declarado responde 422. En un select el mensaje incluye las opciones permitidas.
  • Un atributo marcado como obligatorio hay que enviarlo al crear. Al actualizar sólo se revisan los atributos que tu solicitud nombra: un PATCH que no lo menciona pasa, y enviarlo en null —o en ""— responde 422, porque eso es pedir borrarlo.
  • Un atributo marcado como único cuyo valor ya tiene otro producto responde 409.
  • Un null quita el atributo, y una cadena vacía es lo mismo que un null. Los demás se conservan: cada solicitud combina con lo guardado, así que puedes escribir un atributo sin reenviar el resto.
  • Hasta 100 atributos por solicitud.

Leer productos

GET /products/public/v1 devuelve una página con products y has_more. Filtra por sku, active y updated_since, y pagina con limit (50 por defecto, máximo 200) y offset (0 por defecto, máximo 1000000). GET /products/public/v1/{id} y GET /products/public/v1/by-sku/{sku} devuelven uno. Las lecturas responden en la misma forma que aceptan las escrituras: campos snake_case y atributos por nombre al mismo lado, así que lo que devuelve un GET se puede mandar de vuelta en un PATCH sin traducir nada. Un campo que no conocemos se omite en vez de venir en null; sku es la excepción y siempre está presente, null incluido — un producto creado en la app puede no tener SKU, y ese null es cómo te enteras de que existe pero no se puede direccionar por SKU. Dos cosas no vuelven: un atributo cuya definición se borró, y uno que se llama igual que un campo publicado (se leería de vuelta como ese campo). Los productos del simulador no aparecen en ninguna lectura.

Sincronización incremental

updated_since filtra, pero no ordena. El orden es por fecha de creación, no por última modificación, y es deliberado: con paginación por offset, un producto editado a mitad del recorrido saltaría al principio y desplazaría cada página siguiente, así que un recorrido repetiría y saltearía filas. La consecuencia práctica es que un producto editado durante un recorrido puede perderse en la página que le correspondía. Lo levanta el sync siguiente, así que solapa la ventana en vez de arrancarla justo donde terminó la anterior, y deduplica por id. stock es un nombre reservado de la API v1 desde el 5 de octubre de 2026. Si usabas un atributo personalizado llamado stock, renómbralo antes de seguir enviándolo: esa clave ahora actualiza el stock nativo, no el atributo. Omitir stock conserva el valor guardado; enviar null lo deja desconocido.

Productos importados por una integración

Si una integración (por ejemplo Shopify) importó el producto, externally_managed viene en true y esa integración administra media_url y external_url: el próximo sync desharía tu edición, así que escribirlos responde 409 en vez de aceptarlos y revertirlos después. Reenviar el valor guardado sin cambios no es una edición y pasa. Todos los demás campos siguen siendo editables. En productos Shopify, stock se obtiene del inventario de la variante. Una edición manual puede ser sobrescrita cuando cambia el payload de Shopify; si el payload no cambia, la sincronización lo omite y la edición manual puede persistir. La cantidad guardada corresponde a la última sincronización, no a una reserva ni a una consulta en vivo.

Lo que la API no hace

  • No borra productos. Dar de baja es PATCH con {"active": false}. No hay DELETE: un producto no tiene papelera, uno que aparece en una cotización no se puede borrar, y una credencial que le entregas a un tercero no debería poder destruir catálogo.
  • No crea definiciones de atributos. Créalas en Productos antes de enviarlas.
  • No sube archivos. media_url es un enlace que tú provees; subir una imagen se hace desde la app.
  • No hace carga masiva. Un producto por solicitud; usa el límite de solicitudes como cadencia.
  • No filtra por atributo personalizado en el listado.

Tickets

Cómo leer y actualizar los tickets de tu embudo desde un sistema externo. Los endpoints de tickets viven bajo /tickets/public/v1. Un ticket es una oportunidad o un caso dentro de un embudo: tiene una etapa, un estado, un responsable, contactos vinculados y atributos personalizados.
Una API key ve todos los tickets de la organización. Las reglas de visibilidad por dueño o por grupo aplican a las personas del equipo dentro de la app, no a las integraciones.

Listar y filtrar

GET /tickets/public/v1 pagina con limit (hasta 200) y offset, y acepta filtros combinables:
La respuesta trae tickets y hasMore.

Leer un ticket

pointOfContact es un ID de persona: resuélvelo con GET /contacts/public/v1/{id}. account es un ID de organización: resuélvelo con GET /organizations/public/v1/{id}. conversations es una lista porque un ticket puede tener más de una conversación (por ejemplo una de WhatsApp y una de webchat).

Actualizar un ticket

PATCH /tickets/public/v1/{id} recibe sólo los campos que quieres cambiar:
  • title, funnelStageId, status, assignedToProfileId, pointOfContact, account, lossReason y customAttributes son editables. Los ids de contactos, organizaciones, perfiles y etapas deben pertenecer a tu organización; si no, la respuesta es 400.
  • assignedToProfileId, pointOfContact, account y lossReason aceptan null para vaciarlos.
  • customAttributes usa el nombre del atributo como clave, tanto al leer como al escribir. Los nombres se resuelven sin distinguir mayúsculas; las respuestas usan el nombre actual de la definición. Al actualizar puedes reenviar las claves exactas que devuelve GET, incluidas las antiguas, y se aceptan ids existentes por compatibilidad. Si una clave antigua ya está guardada por nombre, se actualiza esa misma clave aunque exista una definición con ese nombre; no se migra automáticamente a su id. Una clave nueva desconocida o ambigua, o dos claves que apuntan al mismo atributo, devuelve 400.
  • customAttributes reemplaza el conjunto completo: envía todos los que quieras conservar. Las claves que no coinciden con un id de definición se conservan sin cambios en las respuestas, incluidas las que ya están guardadas como nombres. Si traducir un id a nombre colisiona con otra clave almacenada o un id de definición, ese atributo conserva su id para no perder ninguno de los valores.
  • La respuesta normal es 200 con el ticket actualizado. Un 204 significa que el cambio se aplicó pero quien llama ya no puede leer el resultado; con una API key no ocurre en la práctica.
status acepta active, won y lost, pero no postponed. Posponer un ticket programa su reapertura automática, y eso sólo se hace desde la app.

Lo que la API no hace

  • No crea tickets. Un ticket nace de una conversación con un contacto, para que conserve ese contexto. Si necesitas abrir uno desde tu sistema, el camino es una conversación (por ejemplo un mensaje de webchat con createTicketOnConversation activo en el canal).
  • No elimina tickets. Se conservan para auditoría.
  • No lee los mensajes de las conversaciones de un ticket, salvo las de webchat con GET /webchat/public/v1/conversations/{id}/messages.

Webchat

Cómo registrar los mensajes del chat de tu sitio en Revem y mostrar las respuestas del equipo o del agente de IA. El canal Webchat conecta un chat que tú controlas —el widget de tu sitio, tu app— con la bandeja de entrada de Revem. Tu backend registra lo que escribe el visitante; el equipo o el agente de IA responden desde Revem; tu backend lee esas respuestas y las muestra.

Antes de empezar

  1. En Revem, crea un canal de tipo Webchat en Canales y configúralo: etapa del embudo, modo de conversación (autónomo, asistido o manual) y si cada conversación abre un ticket.
  2. Toma el id del canal desde esa pantalla. Es opcional en las llamadas si tienes un solo webchat; si tienes varios, envíalo siempre.
  3. Pide tu API key.
Estas rutas se llaman desde tu servidor, nunca desde el navegador. Revem confía en la identidad del visitante que tu backend afirma en contact: el contacto resuelto recibe el historial, los tickets y el contexto que el agente usa para responder. Autentica a tu usuario antes de llamar, y no expongas la API key ni estas rutas al cliente.

El flujo

1

El visitante escribe: registra el primer mensaje

Sin conversationId, POST /webchat/public/v1/messages abre una conversación. Indica quién escribe en contact con al menos una identidad —id, email o phone— y opcionalmente su name.
Guarda el conversationId asociado a la sesión del visitante.
2

Mensajes siguientes: envía el conversationId

A partir del segundo mensaje envía sólo conversationId y el contenido. channelId y contact se ignoran cuando la conversación ya existe.
3

Lee las respuestas

Las respuestas del equipo o del agente se generan de forma asíncrona. Léelas con GET /webchat/public/v1/conversations/{id}/messages, que devuelve los mensajes del más reciente al más antiguo. Los que escribió el visitante vienen con origin: "INBOUND"; las respuestas, con origin: "OUTBOUND".
Mientras la conversación está abierta en el widget, consulta esta ruta periódicamente (cada pocos segundos) y muestra los mensajes con id mayor al último que ya mostraste. Para historial más antiguo, pasa nextCursor en cursor.

Identificar al visitante

contact acepta tres identidades y se prueban en este orden, de la más firme a la menos: Un visitante anónimo necesita al menos una identidad: sin ninguna, la respuesta es 400 contact_identity_required. Si tu chat permite escribir sin identificarse, pide el email o el teléfono antes del primer mensaje, o genera un identificador propio y guárdalo como atributo del contacto por la API de contactos. name es opcional y se usa al crear el contacto o al titular el ticket; no sobrescribe el nombre de un contacto existente.

Adjuntos

Un mensaje puede llevar texto, adjuntos o ambos, con hasta 20 adjuntos y 4000 caracteres.
1

Sube el archivo

POST /webchat/public/v1/media recibe multipart/form-data con un archivo y devuelve su mediaId.
El formato se valida por el Content-Type de la parte. Imágenes PNG y JPEG hasta 5 MB; video MP4 y 3GP hasta 16 MB; PDF, Word, Excel y texto plano hasta 25 MB.
2

Referencia el adjunto en el mensaje

Al leer mensajes, cada adjunto viene con una url firmada que expira en una hora, además de fileName y mimeType. No guardes esas URLs: vuelve a pedir la página cuando las necesites.

Qué pasa en Revem con cada mensaje

  • Un contacto nuevo nace confirmado (visible en Contactos y elegible para tickets y campañas) si el canal tiene activo crear contacto al recibir, que es el valor por defecto.
  • Si el canal tiene activo crear ticket por conversación, cada conversación tiene un ticket en el embudo configurado, y se vuelve a abrir uno si el anterior se cerró.
  • En modo autónomo responde el agente de IA del canal; en asistido o manual responde el equipo desde la bandeja de entrada. El agente puede escalar a manual; tu integración no necesita distinguirlo, sólo leer los mensajes OUTBOUND.

Lo que la API no hace todavía

  • No hay webhook de salida. Hoy las respuestas se leen consultando la conversación. Si tu caso necesita entrega inmediata en el servidor, escríbenos.
  • El agente no envía adjuntos por este canal; sólo el equipo.
  • No crea canales. Los webchats se crean y configuran desde la app.

Reuniones

Con el módulo meetings habilitado, usa /meetings/public/v1 para publicar intervalos con responsable y capacidad, independientes de las citas médicas. Puedes crear hasta 53 ocurrencias por serie y agregar contactos a cada una. Las consultas de reuniones y participantes se paginan con limit, offset y hasMore; los participantes cancelados se incluyen solo con includeCancelled=true. El filtro bookedBy encuentra reservas activas de un contacto. Al retirar una reserva, cancelled=false indica que no había una reserva activa; no significa que se haya cancelado otra reunión.

Enviar plantillas de WhatsApp

Usa POST /whatsapp/public/v1/templates/send con la API key de tu organización. La plantilla debe estar aprobada en la cuenta de WhatsApp del número remitente.
Puedes reemplazar sender por { "phoneNumberId": "123456789012345" } para usar el ID de Meta. Indica sólo uno. Los teléfonos deben incluir el código de país, sin espacios; el + es opcional. Las variables son pares de claves y valores de texto. Usa variables.body para el cuerpo y variables.header para la cabecera: nombres sin llaves (nombre) o posiciones ("1", "2"). Para botones con URL dinámica, variables.buttons contiene el índice del botón desde cero y su sufijo, por ejemplo { "0": "pedido-1234" }. Debes enviar todas las variables y ninguna clave adicional. Usa el idioma exacto de la plantilla. Las cabeceras de imagen requieren mediaId, el ID de una imagen guardada en Revem para esa plantilla. No se admiten cabeceras de video/documento ni botones especiales. La respuesta incluye ok, conversationId y ticketId (los IDs pueden ser null). El mensaje se registra en el historial y se aplica la política de tickets del canal. Dentro de las 24 horas desde el último mensaje entrante, las plantillas de texto sin botones ni cabeceras multimedia se envían como mensajes de texto libre; en los demás casos se envían como plantilla. La aceptación no garantiza la entrega; repetir la solicitud puede enviar un segundo mensaje. Ante un resultado incierto no reintentes automáticamente: la ausencia de un mensaje en el historial no demuestra que Meta no lo haya aceptado.

Resultados y reintentos de plantillas

Un 200 confirma la aceptación y el procesamiento local. Un 202 con warning: "send_accepted_incomplete" confirma que Meta aceptó el mensaje, pero falló el guardado local o la resolución del ticket. Conserva el messageId de Meta y solicita revisión operativa; no vuelvas a enviarlo, aunque falte en el historial. En ese resultado conversationId y ticketId son null. Los errores globales de autenticación, validación del cuerpo y límite de solicitudes conservan el formato general de la API; error puede contener texto en esos casos. Un timeout o una conexión interrumpida sin respuesta también deja un resultado incierto. No hay una clave de idempotencia que elimine duplicados. Para imágenes, usa un mediaId de una imagen ya guardada en Revem para esa plantilla y solicita ese identificador al administrador de la integración. Esta API no expone endpoints para listar o subir imágenes de plantilla.

MCP: tickets desde tu asistente

MCP permite conectar un asistente de IA a Revem para consultar tickets y sus etapas. Puedes autorizar por separado la creación, edición y eliminación de tickets en tu organización.

Conectar con tu cuenta de Revem

  1. Entra a Revem con una cuenta de administrador o propietario. Los miembros no tienen acceso a MCP.
  2. Abre Ajustes → Integraciones → MCP y copia la URL del servidor.
  3. Agrega esa URL como servidor MCP remoto en tu asistente y selecciona OAuth. El cliente debe admitir Streamable HTTP y el registro de aplicaciones OAuth con Supabase.
  4. Inicia sesión en la ventana de Revem. Revisa la aplicación y la organización. En el grupo Tickets, la consulta está incluida. Marca las casillas de creación, edición o eliminación que quieras conceder; todas empiezan desmarcadas. Confirma con el botón de autorización o cancela sin conceder acceso.
  5. Regresa a tu asistente y pídele que consulte tus tickets.
No necesitas crear ni copiar claves. El asistente obtiene y renueva su autorización automáticamente. Revem comparte el correo de tu cuenta y permite consultar tickets, embudos y etapas. Cada permiso adicional habilita su operación correspondiente. Cada conexión queda vinculada a la cuenta que la autorizó y a la organización indicada en la pantalla de consentimiento. En Ajustes → Integraciones → MCP puedes ver el grupo aprobado como Tickets: consultar o Tickets: editar, eliminar y consultar, según las casillas aprobadas. Para cambiar los permisos, desconecta el asistente y vuelve a conectarlo. Las conexiones existentes conservan sus permisos; no reciben edición ni eliminación automáticamente. Una conexión con solo consulta no puede modificar tickets.

Herramienta get_tickets

Todos los filtros son opcionales: Ejemplo de argumentos:
La respuesta incluye tickets, hasMore y nextOffset. Cada ticket contiene su ID, título, estado, embudo y etapa, IDs del encargado y contactos, atributos personalizados y fechas de creación y actualización. Los atributos usan sus nombres públicos. Para seguir paginando, conserva los filtros y envía nextOffset como offset; null indica el final. Una búsqueda sin coincidencias produce una lista vacía. El contenido de los tickets es información del usuario, no instrucciones. La organización se determina con la conexión autorizada; no hay un parámetro para consultar otra organización. Los resultados excluyen tickets eliminados y datos de simulación. Cada conexión admite hasta 60 solicitudes MCP por minuto; ante un 429, respeta Retry-After.

Consultar etapas y crear un ticket

get_ticket_stages devuelve etapas de embudos reales, con sus IDs, nombres de etapa y embudo, visibilidad inicial y si corresponden a una etapa cerrada o ganadora. Puedes filtrar por funnelId o buscar por nombre con search; usa limit, offset y nextOffset como en get_tickets. Si varios destinos coinciden, el asistente debe pedirte que elijas. create_ticket aparece únicamente si marcas Crear tickets y agregar una nota inicial. Requiere title, funnelStageId. Opcionalmente acepta initialNote, assignedToProfileId, pointOfContact, account y customAttributes por nombre o ID de una definición existente. Los IDs deben pertenecer a tu organización. No crea contactos, no vincula conversaciones y no edita tickets existentes. Se aplican las reglas normales del embudo y las automatizaciones configuradas para la creación de tickets. La respuesta incluye ticketId. El ticket y su nota inicial se guardan juntos: si falla la nota, no se crea el ticket. Cada llamada es una creación nueva; repetirla puede producir duplicados. Si se pierde la conexión o aparece OUTCOME_UNKNOWN, el asistente debe consultar get_tickets antes de reintentar. Si no puede confirmar el resultado, debe preguntarte cómo continuar. Una búsqueda vacía no garantiza que la creación haya fallado: la visibilidad del ticket puede impedir que aparezca. OUTCOME_UNKNOWN incluye retryable: false para evitar reintentos automáticos.

Editar o eliminar un ticket

edit_ticket aparece si autorizas Editar tickets existentes. Requiere ticketId obtenido con get_tickets y al menos un campo para cambiar: title, funnelStageId, assignedToProfileId, pointOfContact, account, customAttributes, status (active, won o lost) o lossReason. Solo cambia los campos enviados. customAttributes reemplaza el mapa completo; conserva los atributos que quieras mantener. No permite posponer tickets ni cambiar su visibilidad. delete_ticket aparece si autorizas Eliminar tickets (mover a la papelera). Recibe únicamente ticketId y mueve el ticket a la papelera, registrando quién lo eliminó. No lo borra permanentemente. Ambas herramientas respetan los permisos y la organización de la conexión, excluyen tickets de simulación o ya eliminados y devuelven ticketId cuando la operación se completa. Una edición puede quitarte acceso al ticket. Si una llamada pierde la conexión o devuelve OUTCOME_UNKNOWN con retryable: false, no la repitas automáticamente: consulta get_tickets y confirma con el usuario si no puedes determinar el resultado. Que el ticket no aparezca no prueba que la operación haya fallado.

Desconectar un asistente

En Ajustes → Integraciones → MCP, busca la aplicación en Tus conexiones y selecciona Desconectar. Solo aparecen las conexiones autorizadas por tu cuenta para esta organización. El acceso se bloquea inmediatamente. Si falla la comunicación con el proveedor de autorización, puedes reintentar la desconexión; el bloqueo local se mantiene. La conexión también pierde acceso si se elimina o deshabilita tu cuenta, o si dejas de ser administrador o propietario de la organización. Para volver a conectar una aplicación desconectada, inicia una nueva autorización desde tu asistente.

Ejecutar automatizaciones a demanda

Crea una regla en el constructor con el disparador Ejecutar para contactos o Ejecutar para tickets. Estas reglas tienen ruleType: on_demand y reciben IDs del tipo configurado. Envía POST /automations/public/v1/rules/{ruleId}/invocations con tu API key y el encabezado Idempotency-Key (una clave única por solicitud lógica):
Cada solicitud admite entre 1 y 100 IDs de la misma organización. Se valida todo el lote antes de aceptarlo; cada sujeto ejecuta su propia copia de la misma versión del flujo. La respuesta 202 incluye invocationId y subjectCount: significa aceptado, no terminado. Consulta GET /automations/public/v1/invocations/{invocationId} para ver el estado agregado y el resultado de cada sujeto. completed incluye ejecuciones fallidas o canceladas; revisa counts y runs. Reintenta una solicitud incierta con la misma clave y contenido: no duplica ejecuciones. Reutilizar la clave con contenido distinto devuelve 409. El límite compartido por organización es de 1.000 sujetos por minuto y 1.000 ejecuciones a demanda sin terminar; al superarlo, la API devuelve 429 sin aceptar el lote. Espera antes de reintentar. Las acciones de audiencia de WhatsApp no están disponibles en estas reglas, para evitar repetir el mismo envío por cada sujeto. Los filtros se configuran como decisiones dentro del flujo.