chat.codename.cl

Documentación

Cómo implementar un backend personalizado, crear un space e insertar la burbuja en un sitio nuevo. Nosotros alojamos el servidor. Tú construyes el inbox de tu equipo sobre la API pública, o pegas la burbuja y contestas desde el dashboard.

Backend personalizado

El dashboard de referencia usa solo la API pública. Si tu producto necesita su propia bandeja, identidad o datos de pedido, habla con los mismos endpoints. El secreto JWT vive en tu servidor: el navegador del visitante nunca lo ve.

Emitir un token de agente

Firma JWT con HS256 y el secreto compartido del entorno. Audiencia agent, alcance de un workspace. El claim sub tiene que ser el id de un agente que ya existe en ese workspace (el que devuelve el login o GET /v1/agents). Si no existe, las rutas de inbox responden 403.

import { SignJWT } from "jose";

const secret = new TextEncoder().encode(process.env.CHAT_JWT_SECRET);

export async function mintAgentToken(agent) {
  return new SignJWT({
    workspaceId: agent.workspaceId,
    role: agent.role,
  })
    .setProtectedHeader({ alg: "HS256" })
    .setSubject(agent.id)
    .setAudience("agent")
    .setIssuedAt()
    .setExpirationTime("12h")
    .sign(secret);
}

Cada request lleva Authorization: Bearer TOKEN. El token de visitante lo emite este servidor al abrir la conversación (POST /v1/conversations); no lo firmes tú desde el browser.

Si prefieres no firmar tokens, POST /v1/auth/login con el email y la contraseña del agente devuelve uno listo:

curl -X POST https://backend-help.codename.cl/v1/auth/login \
  -H "content-type: application/json" \
  -d '{"email":"[email protected]","password":"..."}'

Inbox, mensajes y metafields

Lista solo los chats de los spaces donde el agente es miembro. El envío es al menos una vez: manda un idempotencyKey por mensaje y, al reconectar, pide GET /v1/conversations/:id/messages?since=.

curl https://backend-help.codename.cl/v1/conversations \
  -H "authorization: Bearer TOKEN"

curl -X POST https://backend-help.codename.cl/v1/conversations/CONVERSATION_ID/messages \
  -H "authorization: Bearer TOKEN" \
  -H "content-type: application/json" \
  -d '{"body":"Hola","idempotencyKey":"msg-1"}'

curl -X PUT https://backend-help.codename.cl/v1/conversations/CONVERSATION_ID/metafields/shopify/order_id \
  -H "authorization: Bearer TOKEN" \
  -H "content-type: application/json" \
  -d '{"value":"1042"}'

Los metafields son JSON con namespace y clave (shopify/order_id). El filtro del listado es coincidencia exacta, hasta 3 condiciones unidas con AND: ?metafield=shopify/order_id:1042.

WebSocket: wss://backend-help.codename.cl/v1/stream?token=TOKEN. Eventos: message.created, presence.changed, participant.assigned, metafield.set, conversation.opened, conversation.closed.

Presencia: PUT /v1/presence con {"available":true} mientras el agente está en línea. Sin heartbeat durante 45 segundos se considera ausente.

Mensajes cuando nadie está en línea

Si el workspace tiene una URL de webhook, cada mensaje que llega sin agentes en línea se entrega con POST y Content-Type: application/json:

{
  "type": "conversation.offline_message",
  "conversationId": "cnv_…",
  "email": "[email protected]",
  "body": "¿Siguen abiertos?",
  "messageId": "msg_…"
}

El tipo es conversation.offline_message. Responde 200. Cualquier respuesta 2xx marca el mensaje como atendido y lo saca de la cola. Si no, reintentamos con espera de 1, 2, 4, 8, 15, 30, 60, 120 y 240 minutos, y dejamos de intentar a las 24 horas. La conversación sigue en la cola de seguimiento. Un agente también puede cerrarla a mano con POST /v1/conversations/:id/follow-up.

El envío del correo es tuyo: nosotros solo avisamos. El catálogo completo está en GET /v1.

Crear un space

Un space es la bandeja a la que habla una burbuja. Cada agente solo ve los spaces de los que es miembro. El creador queda como miembro.

Desde el dashboard: entra, abre la pestaña Espacios, escribe el nombre y pulsa Crear. La clave que aparece bajo el nombre es el id del space.

Desde tu backend, con un token de agente, POST /v1/spaces:

curl -X POST https://backend-help.codename.cl/v1/spaces \
  -H "authorization: Bearer TOKEN" \
  -H "content-type: application/json" \
  -d '{"name":"Soporte"}'

La respuesta trae space.id y space.key con el mismo valor. Ese valor es el data-space de la burbuja. space.workspaceId es el data-workspace.

Para sumar a alguien, esa persona ya tiene que ser agente del workspace:

curl -X POST https://backend-help.codename.cl/v1/spaces/SPACE_ID/members \
  -H "authorization: Bearer TOKEN" \
  -H "content-type: application/json" \
  -d '{"email":"[email protected]"}'

PATCH /v1/spaces/:id renombra. DELETE /v1/spaces/:id lo borra. DELETE /v1/spaces/:id/members con {"email":"…"} quita a un miembro.

Insertar la burbuja en un sitio nuevo

Pega este script antes de </body>. Hacen falta los dos atributos: sin data-workspace o sin data-space la burbuja no arranca.

<script src="https://backend-help.codename.cl/widget.js"
        data-workspace="WORKSPACE_ID"
        data-space="SPACE_ID"></script>

Sustituye WORKSPACE_ID y SPACE_ID por los valores del space que acabas de crear. El visitante deja su correo y escribe; si hay alguien del space en línea, el chat es en vivo. Si no, el mensaje queda para seguimiento y, si configuraste webhook, tu backend recibe el aviso.

Opcional: data-api="https://backend-help.codename.cl" solo si el script no se sirve desde este mismo origen. Puedes probar el resultado en /demo.