Tu Empleado de IA dentro de tu plataforma

Tu Empleado de IA de Customer Service puede atender a tus clientes dentro de tu propia app, sitio web o herramienta de soporte. Tu plataforma envía el mensaje del cliente y la respuesta vuelve en la misma respuesta HTTP, escrita con las mismas herramientas que el Empleado de IA usa en WhatsApp: cotizaciones, órdenes, reservas, catálogo, base de conocimiento y escalamiento a una persona.

La API de SpaceKru (v1.1) es una API REST/JSON disponible en todos los planes de pago de SpaceKru. Sincroniza leads en ambos sentidos (upsert por external_id), añade leads a campañas, crea y mueve deals y pide seguimientos a los Empleados de IA, gestiona productos, cotizaciones, órdenes, pagos y reservas, permite que tu plataforma converse con tu Empleado de IA de Customer Service y envía webhooks firmados para 16 eventos que dicen quién causó cada cambio. URL base: https://app.spacekru.com/api/public/v1. Autenticación: llave de API Bearer (sk_live_…). Documentación: https://www.spacekru.com/es/developers. OpenAPI 3.1: https://app.spacekru.com/api/public/v1/openapi.json.

Read in English

Requisitos

  • Una llave de API de Lectura y escritura con Conversaciones con IA (el dueño de la cuenta lo marca al crear la llave).
  • En SpaceKru, una campaña inbound que incluya el canal Web Chat, asignada a un Empleado de IA de Customer Service que tenga activado el canal Web Chat. Las conversaciones por API las atiende esa campaña, igual que el chat del sitio web.
  • Tokens de IA en el plan o en la billetera: cada respuesta los usa, como cualquier otra respuesta de tus Empleados de IA.

Compruébalo cuando quieras:

curl
curl "https://app.spacekru.com/api/public/v1/conversations/availability" \
  -H "Authorization: Bearer $SPACEKRU_API_KEY"
Node.js
const res = await fetch('https://app.spacekru.com/api/public/v1/conversations/availability', {
  headers: {
    Authorization: `Bearer ${process.env.SPACEKRU_API_KEY}`,
  },
});
const body = await res.json();
if (!res.ok) {
  // Branch on body.error.code; quote body.error.request_id to support.
  throw new Error(`${body.error.code}: ${body.error.message} (request ${body.error.request_id})`);
}
console.log(body);
Python
import os

import requests

r = requests.get(
    "https://app.spacekru.com/api/public/v1/conversations/availability",
    headers={
        "Authorization": f"Bearer {os.environ['SPACEKRU_API_KEY']}",
    },
    timeout=30,
)
body = r.json()
if not r.ok:
    # Branch on body["error"]["code"]; quote body["error"]["request_id"] to support.
    raise RuntimeError(f"{body['error']['code']}: {body['error']['message']} (request {body['error']['request_id']})")
print(body)
Respuesta 200
{
  "object": "conversation_availability",
  "available": true,
  "reason": null,
  "agent": {
    "id": "a1b2c3d4-e5f6-4a7b-8c9d-0e1f2a3b4c5e",
    "name": "Sofia",
    "language": "es"
  },
  "campaign": {
    "id": "4e5f6a7b-8c9d-4e0f-a1b2-c3d4e5f6a7b8",
    "name": "Customer service",
    "status": "running"
  }
}

Ciclo de vida

POST /conversations → POST /conversations/{id}/messages → … tantos turnos como haga falta … → POST /conversations/{id}/close

1. Abre una conversación

Para un lead existente (lead_id) o uno nuevo (lead, los mismos campos que al crear un lead; si coincide con un lead existente por correo o teléfono, se usa ese lead). Envía tu propio id como external_conversation_id (un id de ticket o de chat): abrirla de nuevo devuelve la misma conversación, así que reintentar es seguro.

curl
curl -X POST "https://app.spacekru.com/api/public/v1/conversations" \
  -H "Authorization: Bearer $SPACEKRU_API_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: your-unique-request-id" \
  -d '{
  "lead_id": "3f2b8c1e-9a4d-4e6f-b7a8-1c2d3e4f5a6b",
  "external_conversation_id": "ticket-5521",
  "locale": "es"
}'
Node.js
const res = await fetch('https://app.spacekru.com/api/public/v1/conversations', {
  method: 'POST',
  headers: {
    Authorization: `Bearer ${process.env.SPACEKRU_API_KEY}`,
    'Content-Type': 'application/json',
    'Idempotency-Key': 'your-unique-request-id',
  },
  body: JSON.stringify({
    "lead_id": "3f2b8c1e-9a4d-4e6f-b7a8-1c2d3e4f5a6b",
    "external_conversation_id": "ticket-5521",
    "locale": "es"
  }),
});
const body = await res.json();
if (!res.ok) {
  // Branch on body.error.code; quote body.error.request_id to support.
  throw new Error(`${body.error.code}: ${body.error.message} (request ${body.error.request_id})`);
}
console.log(body);
Python
import os

import requests

r = requests.post(
    "https://app.spacekru.com/api/public/v1/conversations",
    headers={
        "Authorization": f"Bearer {os.environ['SPACEKRU_API_KEY']}",
        "Idempotency-Key": "your-unique-request-id",
    },
    json={
        "lead_id": "3f2b8c1e-9a4d-4e6f-b7a8-1c2d3e4f5a6b",
        "external_conversation_id": "ticket-5521",
        "locale": "es",
    },
    timeout=30,
)
body = r.json()
if not r.ok:
    # Branch on body["error"]["code"]; quote body["error"]["request_id"] to support.
    raise RuntimeError(f"{body['error']['code']}: {body['error']['message']} (request {body['error']['request_id']})")
print(body)

2. Envía los mensajes del cliente

Cada llamada envía un mensaje (hasta 4000 caracteres) y espera al Empleado de IA. La mayoría de las respuestas tardan unos segundos; con herramientas (cotizar, agendar) puede tardar hasta un minuto aproximadamente. Configura el timeout HTTP en al menos 90 segundos.

curl
curl -X POST "https://app.spacekru.com/api/public/v1/conversations/18293a4b-5c6d-4e7f-8091-a2b3c4d5e6f7/messages" \
  -H "Authorization: Bearer $SPACEKRU_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
  "text": "Hi, do you have a table for 4 on Saturday at 8pm?"
}'
Node.js
const res = await fetch('https://app.spacekru.com/api/public/v1/conversations/18293a4b-5c6d-4e7f-8091-a2b3c4d5e6f7/messages', {
  method: 'POST',
  headers: {
    Authorization: `Bearer ${process.env.SPACEKRU_API_KEY}`,
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({
    "text": "Hi, do you have a table for 4 on Saturday at 8pm?"
  }),
});
const body = await res.json();
if (!res.ok) {
  // Branch on body.error.code; quote body.error.request_id to support.
  throw new Error(`${body.error.code}: ${body.error.message} (request ${body.error.request_id})`);
}
console.log(body);
Python
import os

import requests

r = requests.post(
    "https://app.spacekru.com/api/public/v1/conversations/18293a4b-5c6d-4e7f-8091-a2b3c4d5e6f7/messages",
    headers={
        "Authorization": f"Bearer {os.environ['SPACEKRU_API_KEY']}",
    },
    json={
        "text": "Hi, do you have a table for 4 on Saturday at 8pm?",
    },
    timeout=30,
)
body = r.json()
if not r.ok:
    # Branch on body["error"]["code"]; quote body["error"]["request_id"] to support.
    raise RuntimeError(f"{body['error']['code']}: {body['error']['message']} (request {body['error']['request_id']})")
print(body)
Respuesta 200
{
  "object": "conversation_turn",
  "conversation_id": "18293a4b-5c6d-4e7f-8091-a2b3c4d5e6f7",
  "messages": [
    {
      "object": "conversation_message",
      "id": "29304b5c-6d7e-4f80-91a2-b3c4d5e6f708",
      "conversation_id": "18293a4b-5c6d-4e7f-8091-a2b3c4d5e6f7",
      "role": "agent",
      "text": "Hi Maria! Yes, Table 4 on the terrace is free on Saturday at 8pm. Shall I book it for you?",
      "created_at": "2026-10-20T15:00:06.000Z"
    }
  ],
  "deferred": false,
  "deferred_reason": null
}

El Empleado de IA puede responder con más de un mensaje: muestra cada elemento de messages en orden.

3. Ciérrala

Las conversaciones no caducan. Cierra una cuando termine el caso (POST /conversations/{id}/close); una conversación cerrada rechaza mensajes nuevos con 422. Abre una nueva para volver a hablar.

Cuando no hay respuesta

El mensaje del cliente siempre queda guardado en el Inbox de SpaceKru. Cuando el Empleado de IA no responde en ese momento, deferred es true y deferred_reason dice por qué:

deferred_reasonSignificadoQué hacer
replies_disabledUna persona tomó el control de este cliente, o se desactivaron las respuestas de IA para él.Espera a la persona: su mensaje llega por webhook.
campaign_inactiveLa campaña inbound está en pausa. Se avisa a un supervisor.Reanuda la campaña en SpaceKru.
message_filteredEl mensaje se filtró (spam, baja, respuesta automática…).Nada.
no_inbound_campaign / agent_not_readyLa configuración cambió después de abrir la conversación.Revisa GET /conversations/availability.
no_replyEl Empleado de IA decidió no escribir nada esta vez.Nada.

Una persona puede tomar el control

Cada conversación por API aparece en el Inbox de SpaceKru como Web Chat. Cualquiera del equipo puede responder desde ahí. Cada mensaje escrito al cliente, por una persona o por el Empleado de IA (incluidas las respuestas que ya recibiste en la respuesta del turno), dispara el webhook conversation.message_created (data.role es human para una persona y agent para el Empleado de IA; deduplica por data.id). Suscríbete para no perder ninguna respuesta:

curl
curl -X POST "https://app.spacekru.com/api/public/v1/subscriptions" \
  -H "Authorization: Bearer $SPACEKRU_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
  "event_type": "conversation.message_created",
  "target_url": "https://your-app.example.com/hooks/spacekru"
}'
Node.js
const res = await fetch('https://app.spacekru.com/api/public/v1/subscriptions', {
  method: 'POST',
  headers: {
    Authorization: `Bearer ${process.env.SPACEKRU_API_KEY}`,
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({
    "event_type": "conversation.message_created",
    "target_url": "https://your-app.example.com/hooks/spacekru"
  }),
});
const body = await res.json();
if (!res.ok) {
  // Branch on body.error.code; quote body.error.request_id to support.
  throw new Error(`${body.error.code}: ${body.error.message} (request ${body.error.request_id})`);
}
console.log(body);
Python
import os

import requests

r = requests.post(
    "https://app.spacekru.com/api/public/v1/subscriptions",
    headers={
        "Authorization": f"Bearer {os.environ['SPACEKRU_API_KEY']}",
    },
    json={
        "event_type": "conversation.message_created",
        "target_url": "https://your-app.example.com/hooks/spacekru",
    },
    timeout=30,
)
body = r.json()
if not r.ok:
    # Branch on body["error"]["code"]; quote body["error"]["request_id"] to support.
    raise RuntimeError(f"{body['error']['code']}: {body['error']['message']} (request {body['error']['request_id']})")
print(body)

GET /conversations/{id}/messages devuelve todo el historial, del más antiguo al más reciente.

Tokens, límites y errores

SituaciónRespuesta
No quedan tokens de IA en el plan ni en la billetera402 AI_QUOTA_EXHAUSTED
La configuración está incompleta409 CONVERSATIONS_NOT_CONFIGURED (details[0].issue dice qué falta)
Más de 4 respuestas de IA en curso en un servidor503 SERVICE_BUSY con Retry-After
El modelo no respondió a tiempo503 SERVICE_BUSY: el mensaje del cliente ya quedó guardado; reintenta más tarde o deja que una persona responda
Se alcanzó el límite diario de mensajes de Web Chat de la cuenta429 RATE_LIMITED
Las conversaciones están apagadas503 CONVERSATIONS_UNAVAILABLE