Skip to navigation

La API

Lo mismo que hace la app, desde tu código, en https://signalcore.ai/v1.

View as Markdown

La API pública está en https://signalcore.ai/v1: JSON de entrada y salida, y un WebSocket por conversación para lo que pasa en directo. La app usa la misma API en /api, con su sesión; tu código usa siempre /v1. Cada endpoint está en la referencia.

Cada llamada lleva Authorization: Bearer con una clave o un token.

Desde Python o TypeScript, los SDK hacen lo mismo con cada llamada tipada: Python y TypeScript.

Claves

ClaveParaPuede
Secreta sk_…Tu servidor. Nunca en una página.Lo que digan sus permisos (abajo).
Publicable pk_…Una página, como el widget.Hablar con un agente, solo desde las webs que indiques.

Los permisos de una clave secreta:

PermisoDeja
readLeer todo (cada GET).
writeCambiar la organización: equipos, agentes, su código, archivos, tablas, claves, automatizaciones, canales, apps, contactos, quién responde una conversación.
talkHablar: empezar conversaciones, escribir en ellas, llamar, subir archivos, crear tokens de persona.
adminCrear las organizaciones de tus clientes y los webhooks.

Crear una clave

Las claves las crea el dueño de la cuenta, con su sesión. Mientras llega su pantalla en la app, créala desde la consola del navegador con signalcore.ai/app abierta y la sesión iniciada:

Consola del navegador, en signalcore.ai/app
const answer = await fetch("/api/keys", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({ kind: "secret", name: "Mi servidor", scopes: ["read", "write", "talk"] }),
});
console.log((await answer.json()).key); // sk_…: solo se muestra esta vez

Una clave publicable nombra su agente y sus webs: { kind: "publishable", name: "Web", agent_id: "agt_…", origins: ["https://tuweb.com"] }. GET /api/keys las lista y DELETE /api/keys/{id} revoca una, y con ella los tokens que creó.

Hablar con un agente

Busca el id del agente en sus equipos, empieza una conversación y escríbele. Con wait: true la respuesta llega cuando el agente termina (hasta 60 segundos).

export SIGNALCORE_KEY=sk_...
# Los equipos, con sus agentes
curl https://signalcore.ai/v1/squads -H "Authorization: Bearer $SIGNALCORE_KEY"
# Una conversación nueva
curl -X POST https://signalcore.ai/v1/agents/agt_.../conversations \
-H "Authorization: Bearer $SIGNALCORE_KEY"
# Escribir y esperar la respuesta
curl -X POST https://signalcore.ai/v1/conversations/cnv_.../messages \
-H "Authorization: Bearer $SIGNALCORE_KEY" \
-H "Content-Type: application/json" \
-d '{"text": "¿Abrís los sábados?", "wait": true}'
Respuesta
{
"conversation_id": "cnv_...",
"message": { "id": "msg_...", "role": "user", "text": "¿Abrís los sábados?", "...": "..." },
"status": "done",
"replies": [
{ "id": "msg_...", "role": "assistant", "text": "Sí, de 10:00 a 14:00. ¿Te reservo una cita?", "...": "..." }
],
"waiting": [],
"error": null
}

status es done, waiting (espera algo: una respuesta a una pregunta, un sí; está en waiting), failed (con error) o running: aún no ha terminado, lee la conversación después con GET /v1/conversations/{id}.

El builder también es un agente: con una clave con talk puedes hablarle igual.

En directo

Cada conversación tiene un WebSocket con todo lo que pasa: la respuesta mientras se escribe, lo que hace el agente, lo que enseña.

wss://signalcore.ai/v1/conversations/{id}/live?token=<clave o token>

Desde un servidor también vale la cabecera Authorization. Cada mensaje es JSON con un type. Envías {"type": "say", "text": "..."} y recibes, entre otros, message (un mensaje guardado), text (un trozo de la respuesta), step (algo que hace el agente), done (terminó) y error.

Organizaciones de tus clientes

Si eres una agencia o un software que da agentes a sus clientes, crea una organización por cliente (permiso admin). Cada una nace con su equipo General y su builder, y no comparte nada con las demás.

curl -X POST https://signalcore.ai/v1/orgs \
-H "Authorization: Bearer $SIGNALCORE_KEY" \
-H "Content-Type: application/json" \
-d '{"name": "Clínica Sol"}'

Para actuar en ella, añade su id en cada llamada: SignalCore-Org: org_….

Tokens de persona

Para que tus usuarios hablen con un agente desde tu producto, tu servidor crea un token para cada uno (permiso talk). Dura una hora y solo deja hablar con los agentes que nombres y ver sus propias conversaciones.

curl -X POST https://signalcore.ai/v1/tokens \
-H "Authorization: Bearer $SIGNALCORE_KEY" \
-H "Content-Type: application/json" \
-d '{"agents": ["agt_..."], "external_id": "user_42", "name": "Lucía Pérez"}'
# {"token": "eyJ...", "expires_at": "..."}

Con una clave publicable, la página manda también SignalCore-Visitor: <id>: un id del visitante que la página guarda (16 a 128 caracteres de A-Za-z0-9_-). Los componentes de chat web lo hacen por ti.

Webhooks

Para enterarte de lo que pasa sin preguntar, registra una dirección tuya (permiso admin):

curl -X POST https://signalcore.ai/v1/webhooks \
-H "Authorization: Bearer $SIGNALCORE_KEY" \
-H "Content-Type: application/json" \
-d '{"url": "https://tuapp.com/signalcore", "events": ["message.created", "run.failed"]}'
# {"secret": "whsec_...", ...}: solo se muestra esta vez

Eventos: message.created, conversation.holder_changed, inbox.item_created, run.finished, run.failed, call.ended, channel.status_changed, approval.requested.

Cada evento llega como POST con {id, type, created_at, org_id, data} y la cabecera SignalCore-Signature: t=<segundos>,v1=<firma>. Compruébala sobre el cuerpo tal como llega:

import hashlib
import hmac
import time
def verified(body: bytes, signature: str, secret: str) -> bool:
parts = dict(part.split("=", 1) for part in signature.split(","))
if abs(time.time() - int(parts["t"])) > 300:
return False
expected = hmac.new(secret.encode(), f"{parts['t']}.".encode() + body, hashlib.sha256)
return hmac.compare_digest(expected.hexdigest(), parts["v1"])

Responde con un 2xx en 10 segundos. Si no, se reintenta (a los 15 s, 30, 60 y 120) y, tras el quinto intento, se da por perdido. El id es el mismo en cada intento.

Escrituras sin repetir

Un POST, PUT, PATCH o DELETE puede llevar Idempotency-Key: <hasta 255 caracteres>. Si lo mandas otra vez con la misma clave en las siguientes 24 horas, recibes la primera respuesta (con Idempotent-Replayed: true) y no se hace dos veces.

Límites

600 llamadas por minuto por clave (o por persona de una clave). Pasado el límite, 429 con Retry-After.

Errores

Los errores son {code, detail}: code para tu código, detail en palabras.

{ "code": "unauthorized", "detail": "This key is not valid, or was revoked" }
EstadocodeQuiere decir
401unauthorizedFalta la clave, o no es válida.
403forbiddenLa clave no tiene el permiso.
404not_foundNo existe, o no es tuyo.
409conflictChoca con algo que ya existe.
422invalid, o el de la negativaLa petición no vale: busy (el agente aún responde), pending (espera una respuesta antes), files.
429rate_limitedDemasiadas llamadas: espera lo que diga Retry-After.

Si el cuerpo no tiene la forma esperada, el 422 es {"detail": [{"loc": [...], "msg": "..."}]}.