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_chatslista 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,sendpuede 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
activitycon un momentosince(solo cantidades, barato), y después acatch_uppara los chats que se movieron. Los audios llegan como texto enmedia.transcriptcuando hay transcripción (hebreo e inglés). - Un rechazo es una respuesta. Llega con
isError: falsey 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
sendconconfirmed: truesolo 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 HTTP | https://app.usecircles.app/api/v1/agent |
| OpenAPI 3.1 | https://app.usecircles.app/api/openapi.json; una referencia legible en https://app.usecircles.app/api |
| Metadatos OAuth | https://app.usecircles.app/.well-known/oauth-protected-resource, https://app.usecircles.app/.well-known/oauth-authorization-server |
| Tarjeta del servidor MCP | https://usecircles.app/.well-known/mcp/server-card.json |
| Esta página en Markdown | https://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_medialo 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_mediale 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 protegido | https://app.usecircles.app/.well-known/oauth-protected-resource |
| Metadatos del servidor de autorización | https://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 |
| Flujo | Código de autorización con PKCE (solo S256). Sin flujo implícito, sin secretos de cliente (token_endpoint_auth_methods_supported: none). |
| 401 | WWW-Authenticate: Bearer resource_metadata=... apuntando a los metadatos del recurso protegido |
| URI de redirección | https en cualquier lugar, o http en localhost, 127.0.0.1 o [::1]. Los esquemas personalizados se rechazan. |
| Scopes | chats:read (leer los chats abiertos), media:read (abrir sus archivos), chats:send (enviar donde la persona lo permitió) |
| Aprobación | En 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ón | Token de acceso 1 hora. Token de renovación 30 días, rotado en cada uso, con detección de reutilización. |
| Tokens creados | Se 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 uso | circ_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. |
| Revocar | Desconectar 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}yGET /messages/{message_ref}devuelven lo permitido (capabilities, con motivos y notas) y lasactionscompletas. - 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,/contenty/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/exchangeLímites
| Qué | Límite |
|---|---|
| Texto por mensaje | 65.536 caracteres (el límite de WhatsApp); un pie, 4.096 |
| Archivo para enviar | Unos 3 MB |
| Archivo para traer | 50 MB por archivo; más grande es too_large |
| Envíos por día | Por defecto 5 por número, sumando todos los agentes; 5, 10, 20 o sin límite; contados por día UTC |
catch_up, un chat | Por defecto 50, máximo 200 mensajes |
catch_up, todos los chats | Por defecto 20, máximo 50 por chat; 150 en total |
people | Por defecto 60, máximo 150 personas; min_messages por defecto 3 |
group_members | Como máximo 300 nombres |
search | Hasta 36.500 días atrás, o la ventana de la cuenta |
get_media | Una ref por llamada; espera unos 25 segundos a que el celular vuelva a subir el archivo |
| Descarga de archivos en segundo plano | Dentro de unos 25 días desde el mensaje; los más antiguos, a pedido |
| Historial | Los 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 agentes | 2 en Free; hasta 5 en Starter; todos los que la persona elija en Pro |
| Envío | Solo en Pro |
| Transcripción de audios | Automática, en hebreo e inglés; en español todavía no está verificada |
| Tokens OAuth | Acceso 1 hora, renovación 30 días |
| Código de conexión de un solo uso | Un solo uso, 1 hora, 10 intentos por minuto por dirección |
| Idempotencia de escrituras | 24 horas por referencia de envío |
| Enlace de inicio de sesión | Un solo uso, 10 minutos |
| Números de WhatsApp | Uno 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_chatsle 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|recordingyduration_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.