Desarrolladores

API pública Beta

Crea integraciones para tu espacio de trabajo con claves de API seguras y con permisos acotados, y un contrato JSON estable y versionado.

Abrir la referencia interactiva de la API

Inicio rápido

  1. 01

    Abre Claves de API

    Abre Ajustes, selecciona Desarrolladores, busca Claves de API y selecciona Crear clave. Los propietarios y administradores pueden crear claves.

  2. 02

    Crea la clave de API

    Escribe un Nombre, elige Caduca en (días), elige Acceso a canales como Todos los canales o Canales seleccionados, y elige en Permisos los permisos mínimos que necesita tu integración. Una petición solo funciona si la clave tiene exactamente la acción sobre el recurso que exige el endpoint. Selecciona Crear clave.

  3. 03

    Guarda tu clave de API

    La clave completa se muestra una sola vez. Cópiala en tu gestor de secretos y selecciona Ya lo he guardado.

  4. 04

    Envía la clave

    Usa un token Bearer o envía el mismo valor en x-api-key. Nunca pongas claves en cadenas de consulta ni en código del navegador.

cURL

curl https://www.usesonny.com/api/v1/contacts?limit=25 \
  --header "Authorization: Bearer sonny_your_key"

Las claves siguen siendo seguras

Seguridad de las claves
Las claves usan el prefijo sonny_, 64 caracteres aleatorios, hash unidireccional en reposo, caducidad configurable y un límite de 600 peticiones por minuto por clave. Cada clave está vinculada a un solo espacio de trabajo.
Para revocar una, selecciona el botón de la papelera que tiene al lado. Confirma ¿Revocar la clave de API? seleccionando Eliminar. La clave deja de funcionar al instante.
Autorización en cada llamada
Sonny verifica el hash y el permiso, y vuelve a comprobar la pertenencia activa del creador al espacio de trabajo, su rol y el estado de facturación. Quitar o desactivar a ese usuario desactiva sus claves al instante.
Los canales seleccionados se aplican en todas las llamadas a la API REST y a MCP. Los endpoints de contactos, propiedades, etiquetas y gestión de webhooks requieren acceso a todos los canales. La creación desde formularios puede usar contacts:write con conversations:write en los canales seleccionados; los endpoints de contactos independientes siguen siendo de todo el espacio de trabajo.

Permisos

  • contacts:read
  • contacts:write
  • tags:read
  • tags:write
  • conversations:read
  • conversations:write
  • messages:read
  • messages:write
  • messages:send
  • webhooks:read
  • webhooks:write
  • kb:read
  • kb:write
  • csat:read
  • attachments:write
  • members:read
  • contact-memory:read
  • contact-memory:write
  • reporting:read

Recursos

Contactos
Gestiona contactos, propiedades con tipo, filtros por valor exacto y memorias de clientes. Archiva un contacto o bórralo definitivamente con todas sus conversaciones ante solicitudes de protección de datos.
Orígenes
Descubre los orígenes configurados y si cada uno admite chat, correo o ambos.
Conversaciones
Crea consultas desde formularios, filtra lo que requiere atención, asigna agentes o equipos, pospón, etiqueta y actualiza por lotes.
Sincronización
Reproduce los cambios duraderos del espacio de trabajo y los registros de eliminación con un cursor guardado.
Miembros y equipos
Descubre los compañeros asignables, su disponibilidad y su acceso efectivo a canales.
Informes
Lee informes de soporte, equipo, IA, conocimiento, leads y disponibilidad.
Mensajes
Lee el historial de mensajes y la extracción de adjuntos, sube archivos privados, añade notas internas y envía o edita respuestas a clientes.
Webhooks
Gestiona endpoints, suscripciones, pruebas, entregas y reintentos.
Base de conocimiento
Crea, lee, actualiza y elimina artículos y categorías del centro de ayuda de cada origen.
Satisfacción del cliente
Lee las puntuaciones CSAT del espacio de trabajo, de cada canal y de cada conversación, y lista valoraciones individuales filtradas por valor, comentario, asignado o periodo.

Usar Sonny desde una herramienta de IA

Sonny MCP ofrece todas las operaciones de la API pública como herramientas. Los clientes se conectan iniciando sesión con OAuth 2.1, o con una clave de API con permisos acotados, y cada llamada mantiene los mismos permisos, límites del espacio de trabajo y reglas de negocio.

Lee la guía de Sonny MCP

Respuestas y errores

Las respuestas de colecciones usan data e incluyen paginación cuando corresponde. Todas las respuestas incluyen x-request-id; puedes enviar un ID de petición seguro y Sonny lo devolverá. Los errores devuelven un mensaje seguro sin exponer detalles sensibles de la implementación.

{
  "error": {
    "type": "validation_error",
    "message": "Invalid email address",
    "requestId": "req_01J..."
  }
}
400
Entrada, JSON, consulta o cursor no válidos.
401
Clave de API ausente, no válida, caducada o sin permisos.
402
El estado de facturación del espacio de trabajo bloquea esta petición.
403
El rol del creador de la clave en el espacio de trabajo no lo permite.
404
El recurso no existe en el espacio de trabajo de la clave.
409
La petición entra en conflicto con un recurso existente.
410
El cursor de sincronización ha caducado. Carga el estado actual y reproduce desde un cursor nuevo.
413
La subida supera el tamaño permitido.
422
El origen no tiene canal de correo o el valor de un campo enviado no es válido.
429
Se ha superado el límite de peticiones por clave.
500
Se ha producido un error inesperado. Vuelve a intentarlo con el ID de la petición.
503
La cola de entrega de webhooks está saturada. Vuelve a intentarlo más tarde.

Límites de peticiones

Cada clave de API puede hacer hasta 600 peticiones por minuto. Todas las respuestas informan de la ventana actual mediante las cabeceras estándar RateLimit-Limit, RateLimit-Remaining y RateLimit-Reset, para que los clientes se regulen solos en lugar de adivinar. Cuando se supera el límite, la API devuelve 429 con una cabecera Retry-After: espera esos segundos antes de reintentar.

Versiones y retirada

La API se versiona en la ruta de la URL (/api/v1). Dentro de una versión solo hacemos cambios que añaden: endpoints nuevos, campos opcionales nuevos y valores de enumeración nuevos. Los cambios incompatibles llegan como una versión nueva y, antes de retirar cualquier endpoint de v1, avisamos con al menos seis meses de antelación: en esta página, por correo a los propietarios de espacios de trabajo con claves de API activas y mediante las cabeceras Deprecation y Sunset en los endpoints afectados.

Editar una respuesta enviada

  1. Da a tu clave de API o a tu conexión MCP los permisos messages:read y messages:send y acceso al canal de la respuesta.
  2. Lee los mensajes de la conversación y copia el ID de una respuesta humana que hayas enviado. Una clave de API actúa como su creador; OAuth actúa como el compañero conectado.
  3. Envía el texto de sustitución con la petición de abajo, o llama a edit_message en MCP con conversationId, messageId y body.
  4. Revisa el mensaje devuelto. Su ID, adjuntos, confirmación de lectura y hora de envío original no cambian.
curl --request PATCH \
  https://www.usesonny.com/api/v1/conversations/conversation_1/messages/message_1 \
  --header "Authorization: Bearer sonny_your_key" \
  --header "Content-Type: application/json" \
  --data '{"body":"The corrected reply"}'

La edición corrige la transcripción y los clientes de chat conectados. No envía otro correo ni otra notificación, y los correos ya entregados no cambian. Solo se pueden editar tus propias respuestas humanas a clientes; no los mensajes entrantes, las respuestas del bot, las notas internas ni las respuestas de otros compañeros. Espera a que termine cualquier entrega de correo pendiente antes de editar. El texto de sustitución debe tener entre 1 y 50 000 caracteres; se borran el HTML y las vistas previas de enlaces anteriores. Las integraciones reciben un webhook message.updated y un evento de sincronización. Consultar solo los IDs de mensaje más recientes no detectará las ediciones; usa el feed de sincronización duradero.

Crear una conversación desde un formulario

Envía un formulario a POST /api/v1/conversations. Sonny busca o crea el contacto por su correo, guarda las respuestas y abre una conversación entrante en el canal de correo del origen que elijas. Se aplican el equipo, las reglas de asignación y las notificaciones del canal. Los agentes responden por correo.

  1. Crea una clave con conversations:write y contacts:write. Puedes limitarla a los canales seleccionados del cliente. Encuentra el ID del origen con GET /api/v1/sources, que también necesita conversations:read.
  2. En n8n, añade un nodo HTTP Request: método POST, URL https://www.usesonny.com/api/v1/conversations. Guarda la clave en una credencial Header Auth: Authorization con el valor Bearer sonny_your_key.
  3. Activa Send Body, elige JSON y Using JSON, cambia todo el campo JSON a Expression y pega este ejemplo. Sustituye el ID del origen y asigna los campos de entrada a tu formulario. Usa el ID de envío estable y único del formulario para que un reintento use el mismo valor.
{{ {
  sourceId: "YOUR_CLIENT_SOURCE_ID",
  contact: { email: $json.email, name: $json.name },
  subject: "Website enquiry",
  message: $json.message,
  fields: {
    Company: String($json.company ?? ""),
    Budget: String($json.budget ?? ""),
    Service: String($json.service ?? "")
  },
  externalId: "website-form-" + $json.submissionId
} }}

Para más opciones del nodo, consulta la guía de HTTP Request de n8n. La herramienta MCP equivalente es create_conversation, con la misma carga y los mismos permisos.

Los nombres de campo nuevos se convierten en propiedades de texto. Los campos existentes de número, URL, fecha y selección deben recibir valores de cadena válidos; un valor incorrecto devuelve 422 indicando el campo y no guarda nada. Las fechas aceptan fechas o marcas de tiempo ISO; los valores de selección deben coincidir con una opción. Se aceptan hasta 50 campos, con nombres de hasta 100 caracteres y valores de hasta 5000. Las propiedades aparecen en el contacto y en la barra lateral de la conversación. Ambos cuerpos del mensaje guardan una copia de las respuestas, también cuando envías el htmlMessage opcional.

El campo opcional tags acepta hasta 20 IDs de etiquetas existentes del espacio de trabajo. La respuesta contiene conversation, un resumen de contact, message y deduplicated. Los envíos nuevos devuelven 201. Reutilizar externalId en el mismo origen devuelve 200 con los IDs originales y deduplicated: true; el contenido modificado se ignora. Sin un ID externo, cada llamada crea una conversación nueva. No se admiten adjuntos al crear ni respuestas automáticas de la IA.

Flujos de trabajo con agentes

Clasifica, actúa y mantente sincronizado

REST y MCP comparten los mismos permisos y flujos de trabajo. Las credenciales solo pueden acotar tu acceso actual a canales; si quitas un canal de tu pertenencia, también se quita de tus integraciones.

Encuentra las conversaciones que requieren atención

Filtra por awaitingReply, unread, unassigned, assigneeId, agentGroupId, snoozed, priority o tagIds. awaitingReply ignora las notas internas; unread es específico del compañero autenticado. unassigned significa sin asignado individual, aunque haya un equipo asignado. Las etiquetas coinciden con cualquiera de los IDs enviados.

GET /api/v1/conversations?status=open&awaitingReply=true&compact=true&sort=waitingSince&direction=asc

Ordena por waitingSince, lastMessageAt, createdAt o prioridad de negocio, con direction asc o desc. Los IDs resuelven los empates. Si omites filtros, se mantienen compact=false y snoozed=any. En REST, tagIds acepta IDs separados por comas; MCP también acepta un array. waitingSince empieza en el primer mensaje entrante después de la última respuesta; los seguimientos y las notas internas no lo reinician. Ejecuta este análisis de la cola de espera de forma programada aunque no llegue ningún webhook, para que los hilos antiguos vuelvan a aparecer.

Ponte al día sin releer la bandeja

Usa GET /api/v1/sync con conversations:read. El feed duradero incluye cambios de conversaciones, etiquetas, mensajes, propiedades de contactos, memorias y registros de eliminación. Cada carga requiere además su propio permiso de lectura: los cuerpos de los mensajes necesitan messages:read y las memorias, contact-memory:read. Las credenciales restringidas solo reciben los canales permitidos.

  1. Empieza sin cursor, sigue nextCursor hasta que hasMore sea false y guarda ese cursor.
  2. Lee las listas actuales de conversaciones y contactos y el historial que necesites para tu estado inicial.
  3. Reproduce desde el cursor guardado para captar los cambios ocurridos durante esa lectura. Procesa cada página y guarda nextCursor.

Elimina duplicados por el id del evento: la reproducción es «al menos una vez», así que las acciones posteriores necesitan su propia protección contra duplicados. Una petición sin cursor cubre la última hora, no una instantánea completa. Los eventos se conservan 30 días; HTTP 410 resync_required significa que debes volver a cargar el estado. Vuelve a cargarlo también después de ampliar los permisos o el acceso a canales. Usa limit hasta 100 y maxBodyChars hasta 10 000 (500 por defecto). Pon compact=true para obtener los campos textPreview/textTruncated de los mensajes, limitados a 200 caracteres, en lugar de body/bodyTruncated. Los webhooks pueden activar a un agente; el feed sigue disponible sin suscripciones a webhooks o cuando la entrega de webhooks está atascada.

Registra las comprobaciones una vez y comparte el resultado

Antes de repetir una investigación, lee list_conversation_checks (GET /api/v1/conversations/{conversationId}/checks). Guarda un resultado con record_conversation_check (PUT a la misma ruta), indicando key, result, checkedBy y, opcionalmente, una reference para el ID o la URL de la tarjeta. Por ejemplo: key=product-version, result=Shopstar Go verified, checkedBy=Engineer, reference=card-X. Sonny registra el actorId autenticado y la marca de tiempo checkedAt. Reutilizar una key sustituye solo esa comprobación; es el estado actual, no un historial. Las lecturas necesitan conversations:read y las escrituras conversations:write, ambas limitadas al canal de la conversación. Estas llamadas no envían ninguna respuesta ni marcan al vendedor como respondido.

Asigna y actualiza el trabajo por lotes

Descubre los compañeros y equipos activos y asignables con GET /api/v1/members and /teams (members:read). Las respuestas incluyen la disponibilidad y el acceso efectivo a canales, sin direcciones de correo. Usa conversations:write para cambiar status, priority, assigneeId, agentGroupId, snoozedUntil, snoozedUntilReply, addTagIds o removeTagIds.

POST /api/v1/conversations/batch
{
  "conversationIds": ["conversation_1", "conversation_2"],
  "updates": { "agentGroupId": "team_1", "assignment": "round_robin" }
}

La asignación rotativa elige un miembro del equipo disponible que pueda acceder al canal de la conversación. Si no hay ningún miembro que cumpla los requisitos, una actualización individual devuelve 409 y un elemento del lote falla. Cada lote acepta hasta 100 IDs únicos y aplica un cambio de forma atómica por conversación. Revisa cada resultado { id, ok, error? }; algunos elementos pueden fallar. Los lotes usan el límite de peticiones actual, sin cobro ponderado por número de elementos.

Comparte el contexto del cliente con Sonny AI

Lista, guarda y elimina memorias de contactos con contact-memory:read/write. Indica tanto contactId como un sourceId accesible; el contacto debe tener una conversación en ese origen. Los datos guardados usan la misma validación, gestión de duplicados y límites que la aplicación, y se registran como memorias manuales.

Lee las definiciones de propiedades en /api/v1/properties y lee o define valores en /api/v1/contacts/{contactId}/properties. MCP ofrece list_properties, get_contact_properties y set_contact_property. Requieren contacts:read/write y acceso a todos los canales. Indica exactamente un propertyId o un propertyName, con un valor de cadena o null para borrarlo. Los valores de texto, número, URL, fecha y selección se validan según la definición del campo.

PUT /api/v1/contacts/contact_1/properties
{ "propertyName": "Plan", "value": "Pro" }

GET /api/v1/contacts?property[Plan]=Pro

Los filtros de propiedades coinciden con cadenas guardadas exactas; si hay varias propiedades, deben coincidir todas. Los valores escritos por la API se etiquetan como datos de la API en Co-Pilot y en el respondedor automático. Se siguen aplicando las reglas existentes de cliente verificado y de origen. Los valores de campos internos introducidos a mano siguen excluidos de este contexto de IA.

Lee los mismos informes que tu equipo

Con reporting:read, llama a GET /api/v1/reporting/{kind}. Los tipos son overview, volume, response-times, agents, sources, tags, csat, ai, knowledge, leads y online-hours. overview combina recuentos, tiempos de respuesta y CSAT. Los filtros son period (de 1 a 365 días, 30 por defecto), fechas from/to emparejadas (to es exclusiva), granularity (day/month), source, assigneeId y tagId. source acepta all, all-chat, all-email, website:{id} o email:{id}.

Los informes usan las consultas del panel y las comprobaciones de acceso actuales. knowledge usa las fechas y los canales permitidos, independientemente del origen, el asignado o la etiqueta seleccionados. online-hours mide la presencia en el espacio de trabajo de los compañeros accesibles; sus recuentos de conversaciones siguen limitados por canal. Los endpoints /csat existentes mantienen su permiso csat:read independiente y pueden describir una población distinta.

Envía archivos con respuestas o notas internas

Concede attachments:write y sube un archivo de hasta 25 MB para una conversación. POST /api/v1/attachments recibe los campos multipart file y conversationId. La respuesta contiene un id y expiresAt. Pasa hasta 10 attachmentIds a una respuesta o nota en el plazo de una hora. Cada subida está vinculada a tu usuario y a la conversación, y solo se puede usar una vez. Las subidas sin usar se eliminan cuando caducan.

POST /api/v1/conversations/conversation_1/reply
{ "attachmentIds": ["upload_1"] }

Las respuestas requieren messages:send; las notas internas requieren messages:write y nunca llegan a los clientes. Se admiten mensajes solo con adjuntos. Las respuestas por correo incluyen los archivos que caben en el tamaño máximo del correo y enlaces de descarga para el resto; los correos de chat sin conexión incluyen enlaces a los archivos. Los enlaces enviados por correo siguen funcionando mientras exista el adjunto, así que los destinatarios pueden abrirlos más tarde. Reenviar el correo comparte el acceso a esos archivos. Consulta emailDeliveryStatus para ver los fallos de entrega.

Las lecturas de mensajes autorizadas incluyen downloadUrl, downloadExpiresAt, aiStatus, aiDescription y aiExtractedText, además de videoTranscripts para los vídeos enlazados (Loom, Vimeo y otros). Los enlaces de descarga duran 15 minutos; vuelve a leer el mensaje para obtener enlaces nuevos. Las nuevas subidas por API/MCP tienen almacenamiento privado. Los adjuntos más antiguos siguen siendo públicos y se marcan como access=legacy_public: su URL original no caduca. Leer un mensaje inicia la lectura de sus imágenes si el espacio de trabajo tiene Sonny AI. Las lecturas de imágenes y las transcripciones de vídeo terminan poco después de que llegue un mensaje: mientras alguna siga en curso, la respuesta empieza con readsInProgress, cuyo nextStep indica la llamada exacta que hay que hacer. Pasa waitSeconds (hasta 30) para esperarlas en una sola petición. Los mensajes del widget y en tiempo real para clientes nunca incluyen extracciones ni transcripciones.

Explora los contratos completos de peticiones y respuestas

Base de conocimiento

Sincroniza desde una fuente externa

Sincroniza artículos y categorías con IDs externos estables, importa Markdown o HTML, sube imágenes, define el orden y gestiona las audiencias de lectores. Repetir un upsert actualiza el contenido existente.

  1. Elige el sourceId de tu canal y concede kb:read y kb:write. Mantén la clave de API en tu servidor y limita su acceso a canales.
  2. Crea la categoría y sincroniza un artículo como borrador. Revisa su formato y su acceso antes de publicarlo.
  3. Configura el acceso al centro de ayuda, publica y prueba la vista del lector. Usa paginación e IDs externos estables para las actualizaciones posteriores.
Sigue la guía completa de sincronización con REST

Gestiona las audiencias de clientes

Crea grupos a partir de atributos de clientes verificados y aplícalos a un centro de ayuda, una categoría o un artículo. Deben cumplirse todas las restricciones heredadas. Las credenciales de la API y de MCP actúan como personal del equipo dentro de sus permisos; previsualiza y prueba una sesión real de cliente para comprobar el acceso de los lectores.

Configura y prueba las audiencias del centro de ayuda

Documentación relacionada