Para agentes

Documentación de la API y MCP de Circles

Esta página está escrita para agentes de IA que quieren saber qué es Circles y cómo usarlo: las herramientas, la forma de cada respuesta, cómo funciona el inicio de sesión, la API HTTP y cada límite. Las personas que configuran Circles tienen las guías en usecircles.app/es/docs.

Circles entrega a los agentes de una persona los chats de WhatsApp que esa persona abre, por un servidor MCP remoto en https://app.usecircles.app/api/mcp (OAuth 2.1 o un token bearer) y una API HTTP en https://app.usecircles.app/api/v1/agent (OpenAPI 3.1 en https://app.usecircles.app/api/openapi.json). Hay 9 herramientas, cada rechazo es una respuesta que nombra lo que sí está abierto, y todas las horas están en UTC. A octubre de 2026.

Actualizado el

Empieza aquí

Actúas por una persona, dentro de los chats que esa persona abrió a los agentes. Nada más de su WhatsApp existe para ti.

  • Conoce tu mundo. allowed_chats lista cada chat abierto para ti y si puedes enviar ahí. Un chat que no está en la lista no se puede leer ni buscar. La única forma de salir de la lista es un chat nuevo: cuando el valor por defecto del número es lectura y envío, send puede empezar un chat con alguien nuevo, por número de teléfono o por el nombre exacto de un contacto guardado (GET /recipients?to= por HTTP).
  • “¿Qué me perdí?” Llama primero a activity con un momento since (solo cantidades, barato), y después a catch_up para los chats que se movieron. Los audios llegan como texto en media.transcript cuando hay transcripción (hebreo e inglés).
  • Un rechazo es una respuesta. Llega con isError: false y nombra lo que SÍ está abierto o permitido. Pásaselo a la persona; no lo reintentes.
  • Enviar es hablar como la persona. Muéstrale a la persona el texto exacto y el chat exacto, y llama a send con confirmed: true solo cuando acepte. Un envío nunca se reintenta: si la entrega es incierta, lee el chat antes de decidir nada.
  • Las horas están en UTC. Circles no sabe dónde está la persona; convierte tú las horas.
  • ¿Todavía no estás conectado? La persona vincula WhatsApp y te conecta siguiendo las guías en usecircles.app/es/docs. Circles nunca te pide su contraseña ni un código de WhatsApp.

Direcciones

QuéDónde
Servidor MCP (HTTP, sin estado)https://app.usecircles.app/api/mcp
API HTTPhttps://app.usecircles.app/api/v1/agent
OpenAPI 3.1https://app.usecircles.app/api/openapi.json; una referencia legible en https://app.usecircles.app/api
Metadatos OAuthhttps://app.usecircles.app/.well-known/oauth-protected-resource, https://app.usecircles.app/.well-known/oauth-authorization-server
Tarjeta del servidor MCPhttps://usecircles.app/.well-known/mcp/server-card.json
Esta página en Markdownhttps://usecircles.app/es/api-mcp-docs.md; todas las páginas del sitio están en https://usecircles.app/llms.txt

Las 9 herramientas MCP

Las herramientas se listan según quién llama: send aparece solo con el scope chats:send y algún chat donde enviar, get_media solo con media:read. Una herramienta que falta responde igual que una que no existe.

allowed_chats: sin parámetros. Los chats abiertos a los agentes, cada uno con name, kind, access (read only o read and send) y archived cuando corresponde. Es todo el mundo: un chat que no está aquí no se puede leer, buscar ni recibir envíos. También trae connection (not_linked, subscription_ended) y subscription.ends_at cuando un plan cancelado está por terminar.

activity: since (ISO 8601, obligatorio). Qué chats abiertos se movieron: cantidad de mensajes, last_at / last_at_iso, last_from. Solo cantidades, sin texto. La primera llamada barata para “¿qué me perdí?”.

catch_up: since (obligatorio), chat, limit, per_chat, kind. Mensajes desde un momento, del más antiguo al más nuevo, remitentes por nombre. Con chat: ese chat, limit por defecto 50, máximo 200, se conservan los más nuevos. Sin él: cada chat abierto que se movió, el chat más reciente primero, per_chat por defecto 20, máximo 50, dentro de un total de 150; un chat con más dice more. kind es voice, audio o recording (cualquiera de los dos). Los adjuntos solo se anuncian. Trae uno con get_media.

search: query (obligatorio), chat, days (1 a 36.500; por defecto, todo el historial guardado), kind. Búsqueda de texto sin distinguir mayúsculas en un chat abierto o en todos, que incluye lo escrito y lo que dicen las transcripciones de audios. Cada resultado nombra su chat cuando se busca en todos.

people: since (obligatorio), limit (por defecto 60, máximo 150), min_messages (por defecto 3). Con quién habla la persona en los chats abiertos: cantidades en chats individuales, grupos compartidos, mensajes por grupo. Devuelve solo nombres, sin números y sin texto.

group_members: chat (obligatorio). Los miembros de un grupo abierto según la lista de WhatsApp, incluidos los que nunca escribieron. Nombre guardado, o si no el nombre con el que escriben, o su nombre de WhatsApp marcado con ~. Administradores marcados. Como máximo 300 nombres; los miembros sin nombre conocido se cuentan en unnamed. Nunca números de teléfono.

documents: since (obligatorio). Cada PDF, archivo de Word y hoja de cálculo enviados en los chats abiertos: nombre del archivo, fecha, los chats a los que se envió (una entrada por archivo), ref y state. Solo nombres y fechas.

get_media: ref (obligatorio). Un adjunto, en base64 en bytes_base64, con mime, filename y size_bytes. Hasta 50 MB por archivo. Para un archivo on_request pide al celular que lo vuelva a subir y espera unos 25 segundos. Una ref por llamada. El agente lee el archivo. Circles no hace OCR, no describe imágenes ni extrae el texto de los PDF.

send: chat, text, confirmed (todos obligatorios), file (mime, data_base64, filename), from. Un mensaje a un chat abierto para envío: texto de hasta 65.536 caracteres, o un archivo de hasta unos 3 MB con el texto como pie (hasta 4.096). Un JPEG, PNG o WebP sale como foto, un MP4 o 3GP como video, y cualquier otra cosa como documento con nombre. Cuando el valor por defecto del número es lectura y envío, chat puede ser un número de teléfono con código de país o el nombre exacto de un contacto guardado, para empezar un chat nuevo; from elige el número cuando podría ser más de uno. Con límite diario, nunca se reintenta. confirmed es la afirmación del agente de que la persona aceptó este texto exacto en este chat exacto; Circles no puede verificarla y no la toma como permiso.

Respuestas, rechazos y archivos

El envoltorio. Cada herramienta responde con un elemento de texto. En una respuesta, content[0].text es JSON (con formato). En un rechazo, es una oración simple. En los dos casos isError es false: lee el rechazo y pásalo. No lo reintentes.

Los rechazos nombran lo que SÍ está permitido. “No chat named X is open to agents. What IS open: A, B.” o “X is open for reading only.” Un chat oculto nunca se nombra, así que un rechazo no le dice a un agente si un chat existe. “No hay mensajes” y “no puedes ver ese chat” nunca se confunden.

Cobertura. Cuando una solicitud llega más atrás de lo que se guarda, la respuesta trae coverage, que dice dónde empieza el historial guardado y por qué, y termina con “Nothing was hidden from you.” Si no hay coverage, no falta nada en la ventana.

Las horas están en UTC: at en milisegundos desde 1970 y at_iso en ISO 8601 terminado en Z (igual last_at / last_at_iso). Circles no sabe dónde está la persona y no convierte nada.

Audios. media.kind es voice para un audio de WhatsApp y audio para un archivo de audio. Los dos traen transcript y transcript_state: pending (todavía se está transcribiendo), done, empty (no se dijo nada) o failed; y duration_seconds cuando WhatsApp lo da. La transcripción es automática, en hebreo e inglés; la de audios en español todavía no está verificada. Un audio de más de unos 25 días al vincular se transcribe cuando se trae.

Estados de los adjuntos. Cada archivo anunciado tiene un state:

  • available: get_media lo devuelve ahora.
  • downloading: está llegando solo, normalmente en menos de un minuto. Vuelve a pedirlo en un rato.
  • on_request: WhatsApp ya no lo tiene; get_media le pide al celular de la persona que lo vuelva a subir (el celular tiene que estar en línea) y espera unos 25 segundos.
  • fetching: el celular todavía no respondió. NO se perdió: vuelve a pedirlo con la misma ref en un minuto; una repetición se suma a la solicitud que ya está corriendo.
  • gone: el celular no pudo volver a subirlo. Dilo; no lo reintentes.
  • too_large: supera 50 MB, el límite por llamada.
  • failed: todavía no se pudo descargar. La persona no tiene que hacer nada.

También en los mensajes: reactions (emoji, quién, cuándo) cuando alguien reaccionó, desde el 2026-10-27. Las ediciones en WhatsApp actualizan el texto guardado; “eliminar para todos” quita el mensaje. Las ubicaciones, tarjetas de contacto y encuestas se guardan como mensajes vacíos para que un chat no tenga huecos. Las vistas previas de enlaces y el contexto de mensajes citados no se incluyen.

Un ejemplo abreviado, con personas inventadas (las respuestas de la API están en inglés):

// An answer: content[0].text is JSON, isError is false
{
  "chat": "Oak Street parents",
  "coverage": {
    "days": 30,
    "note": "This account keeps the last 30 days ... Nothing was hidden from you."
  },
  "messages": [
    {
      "id": "G7",
      "from": "Dana",
      "fromMe": false,
      "at": 1792995120000,
      "at_iso": "2026-10-26T06:12:00.000Z",
      "body": "",
      "media": {
        "kind": "voice",
        "duration_seconds": 41,
        "transcript_state": "done",
        "transcript": "The trip moved to Thursday, buses leave at 8:15."
      }
    },
    {
      "id": "G8",
      "from": "Yossi",
      "fromMe": false,
      "at": 1792998180000,
      "at_iso": "2026-10-26T07:03:00.000Z",
      "body": "Permission slip attached",
      "media": {
        "kind": "document",
        "filename": "trip-permission.pdf",
        "mime": "application/pdf",
        "size": "212 KB",
        "state": "on_request",
        "fetch_with": "get_media",
        "ref": "r1_..."
      }
    }
  ]
}

// A refusal: content[0].text is the sentence itself, isError is still false
No chat named "Book club" is open to agents. What IS open: Oak Street parents, Building committee. Only the person can open another, in Circles.

Autenticación: OAuth 2.1 y tokens

Valor
Metadatos del recurso protegidohttps://app.usecircles.app/.well-known/oauth-protected-resource
Metadatos del servidor de autorizaciónhttps://app.usecircles.app/.well-known/oauth-authorization-server (emisor https://app.usecircles.app)
Direcciones/oauth/authorize, /oauth/token, /oauth/register (registro dinámico de clientes), /oauth/revoke
FlujoCódigo de autorización con PKCE (solo S256). Sin flujo implícito, sin secretos de cliente (token_endpoint_auth_methods_supported: none).
401WWW-Authenticate: Bearer resource_metadata=... apuntando a los metadatos del recurso protegido
URI de redirecciónhttps en cualquier lugar, o http en localhost, 127.0.0.1 o [::1]. Los esquemas personalizados se rechazan.
Scopeschats:read (leer los chats abiertos), media:read (abrir sus archivos), chats:send (enviar donde la persona lo permitió)
AprobaciónEn la página de Circles. El cliente recibe solo lo que la persona deja marcado ahí, pida lo que pida. Para los clientes que se registran por su cuenta, lectura y archivos empiezan marcados y el envío desmarcado. Los clientes propios de Circles pueden empezar con el envío marcado. Revisa los permisos antes de aprobar.
DuraciónToken de acceso 1 hora. Token de renovación 30 días, rotado en cada uso, con detección de reutilización.
Tokens creadosSe crean en la página de agentes (Nuevo token). Prefijo circ_, se muestran una vez, solo se guarda un hash. Duración: sin límite (por defecto), 90 días o 1 año. Sin renovación.
Código de conexión de un solo usocirc_code_..., se canjea en POST /api/v1/connect/exchange con {"code": "..."} y sin Authorization. Un solo uso, 1 hora, no abre nada por sí mismo, solo hash, 10 intentos por minuto por dirección.
RevocarDesconectar en la página de agentes revoca al instante los permisos OAuth y los tokens creados

Un scope restringe; nunca amplía. Un token con todos los scopes sigue llegando solo a los chats que la persona abrió, porque los niveles de los chats se vuelven a leer en cada llamada.

API HTTP

Las mismas operaciones que MCP, como JSON por HTTP, para agentes y herramientas que llaman a una API. OpenAPI 3.1 (versión 2.0.0) en https://app.usecircles.app/api/openapi.json; una referencia de solo lectura en https://app.usecircles.app/api.

Cada solicitud lleva Authorization: Bearer <key>: una clave circ_ creada o el token OAuth de un cliente MCP. No se acepta nada más, ni cookies.

  • Lecturas: GET https://app.usecircles.app/api/v1/agent/allowed_chats, /activity, /people, /catch_up, /search, /documents, /group_members, con los mismos parámetros que las herramientas.
  • Detalles: GET /chats/{chat_ref} y GET /messages/{message_ref} devuelven lo permitido (capabilities, con motivos y notas) y las actions completas.
  • Enviar: POST /chats/{chat_ref}/messages (texto, o un archivo de hasta unos 3 MB con un pie opcional).
  • Responder: POST /messages/{message_ref}/replies, una respuesta citada nativa de WhatsApp. Una respuesta que no se puede citar se rechaza.
  • Reaccionar: POST /messages/{message_ref}/reactions, una reacción con emoji.
  • Chat nuevo: GET /recipients?to= con un número de teléfono (con código de país, codificado para URL) o el nombre exacto de un contacto guardado; responde como los detalles de un chat.
  • Comprobante de escritura: GET /writes/{submission_ref}.
  • Archivos: POST /get_media (puede pedir el archivo al celular), GET /media/{ref}/status, /content y /view (nunca se lo piden al celular).
  • Código de conexión: POST https://app.usecircles.app/api/v1/connect/exchange.

Actuar. Para enviar, responder o reaccionar, haz GET de los detalles del chat o del mensaje y ejecuta una de sus actions tal como viene: una solicitud completa (método, URL, encabezados, cuerpo) a la que el agente solo agrega su encabezado Authorization y el texto.

Escrituras idempotentes. Cada escritura lleva una referencia de envío emitida por el servidor y atada a su destino. Reutilizarla no puede volver a enviar ni ocupar otro lugar del límite diario, durante 24 horas. Una entrega incierta devuelve delivery_unknown y nunca se reintenta: lee el comprobante y el chat antes de hacer un envío nuevo y deliberado.

Paginación. Las respuestas en lista traen pagination.next_url y has_more en el nivel superior. Sigue next_url hasta que sea null; cada página vuelve a verificar la autorización. Las páginas de catch_up van de los mensajes más nuevos hacia atrás.

Errores. Un 401 significa que la clave ya no funciona. Un 403 scope_required significa que la persona no dio ese permiso. Un argumento inválido nombra el campo y su rango permitido.

No se admite: votar en encuestas, quitar una reacción, citar un mensaje que no es de texto.

# Read: which chats moved since 06:00 UTC
curl -H "Authorization: Bearer circ_..." \
  "https://app.usecircles.app/api/v1/agent/activity?since=2026-10-27T06:00:00Z"

# Act: GET a chat's details, then perform one of its actions as given
curl -H "Authorization: Bearer circ_..." "https://app.usecircles.app/api/v1/agent/chats/<chat_ref>"
# -> "actions": [{ "method": "POST", "url": ".../chats/<chat_ref>/messages",
#                  "headers": {...}, "body": { ... "submission_ref": "..." } }]

# An agent handed a one-time code (Instinct) swaps it for its key, no Authorization
curl -X POST -H "Content-Type: application/json" \
  -d '{"code":"circ_code_..."}' https://app.usecircles.app/api/v1/connect/exchange

Límites

QuéLímite
Texto por mensaje65.536 caracteres (el límite de WhatsApp); un pie, 4.096
Archivo para enviarUnos 3 MB
Archivo para traer50 MB por archivo; más grande es too_large
Envíos por díaPor defecto 5 por número, sumando todos los agentes; 5, 10, 20 o sin límite; contados por día UTC
catch_up, un chatPor defecto 50, máximo 200 mensajes
catch_up, todos los chatsPor defecto 20, máximo 50 por chat; 150 en total
peoplePor defecto 60, máximo 150 personas; min_messages por defecto 3
group_membersComo máximo 300 nombres
searchHasta 36.500 días atrás, o la ventana de la cuenta
get_mediaUna ref por llamada; espera unos 25 segundos a que el celular vuelva a subir el archivo
Descarga de archivos en segundo planoDentro de unos 25 días desde el mensaje; los más antiguos, a pedido
HistorialLos agentes ven el último mes en Free y los últimos 3 meses en Starter; en Pro, todo el historial, o los últimos 90, 60 o 30 días
Chats abiertos a los agentes2 en Free; hasta 5 en Starter; todos los que la persona elija en Pro
EnvíoSolo en Pro
Transcripción de audiosAutomática, en hebreo e inglés; en español todavía no está verificada
Tokens OAuthAcceso 1 hora, renovación 30 días
Código de conexión de un solo usoUn solo uso, 1 hora, 10 intentos por minuto por dirección
Idempotencia de escrituras24 horas por referencia de envío
Enlace de inicio de sesiónUn solo uso, 10 minutos
Números de WhatsAppUno por cuenta, en todos los planes

Registro de cambios

Cambios recientes que notaría un agente o un integrador.

  • 2026-10-27: Instinct se conecta con un código de un solo uso enviado desde WhatsApp, sin mostrar ni pegar ninguna clave.
  • 2026-10-27: Un mensaje puede ser tan largo como permite WhatsApp: 65.536 caracteres.
  • 2026-10-27: Las reacciones se guardan en su mensaje y aparecen en cada lectura.
  • 2026-10-27: Los chats individuales se abren para lectura por defecto en un número nuevo.
  • 2026-10-27: API HTTP 2.0.0: se quitaron los agentes de navegador; la API de agentes acepta solo una clave Bearer.
  • 2026-10-26: Una suscripción cancelada sigue funcionando hasta el final del período pagado, y allowed_chats le dice la fecha al agente.
  • 2026-10-23: Los agentes pueden escribirle a alguien con quien todavía no hay chat, por número de teléfono o nombre de contacto guardado.
  • 2026-10-19: Los agentes pueden enviar un archivo de cualquier tipo: un PDF, un documento, un video o una imagen.
  • 2026-10-19: Grabaciones: filtros kind=voice|audio|recording y duration_seconds; cada hora se indica en UTC.
  • 2026-10-19: Claude y Codex se conectan por dirección, con aprobación en la página de Circles.
  • 2026-10-18: Los audios se transcriben automáticamente y los agentes leen la transcripción en el mensaje.
  • 2026-10-18: Todo el historial es el valor por defecto, para números nuevos y existentes.
  • 2026-10-16: API HTTP con respuestas y reacciones nativas; se aplican las ediciones y eliminaciones hechas en WhatsApp.

Preguntas y respuestas

¿Cuál es la URL del servidor MCP de Circles?

https://app.usecircles.app/api/mcp. Es un servidor MCP remoto por HTTP que acepta OAuth 2.1 (con descubrimiento y registro dinámico) o un token bearer que creas en Circles.

¿Circles admite streaming o SSE?

Circles responde cada solicitud MCP con una sola respuesta JSON por HTTP POST, sin estado. No hay un flujo de eventos que mantener abierto, así que cualquier cliente que hable MCP por HTTP puede usarlo.

¿Por qué mi agente recibió un rechazo en lugar de un error?

Circles devuelve los rechazos como respuestas (isError: false) para que los agentes los lean y no los reintenten. Cada uno nombra lo que SÍ está abierto o permitido.

¿Por qué un archivo está en “fetching”?

Circles le pidió al celular de la persona que vuelva a subir un archivo que WhatsApp ya no tiene. No se perdió: vuelve a pedirlo con la misma ref en un minuto, con el celular en línea.

¿Puedo responder o reaccionar a un mensaje?

Sí, por la API HTTP de Circles: respuestas citadas nativas y reacciones con emoji. Las herramientas MCP solo envían mensajes y archivos simples.