¿Eres un agente de IA? Lee la referencia en texto: index.md · llms-full.txt · llms.txt · OpenAPI 3.1 (JSON)
Atmos API — Referencia v1
Documentación completa en texto de la API pública del CRM Atmos. Esta es la versión legible por máquinas de https://docs.atmos.com.mx/docs (la UI interactiva requiere JavaScript).
API pública de Atmos
REST sobre /api/v1/*. Autenticación M2M con un token de API (at-api-…) emitido por
un administrador del portal.
Autenticación
Cada petición lleva el token en la cabecera:
Authorization: Bearer at-api-XXXX.sk_YYYY
(También se acepta X-Api-Key: at-api-XXXX.sk_YYYY.) El token tiene su propio scope
(acciones CRUD por objeto + alcance de datos + acceso por campo), independiente del usuario
que lo creó. Solo un administrador crea, edita o revoca tokens.
Quickstart
Listar contactos:
curl https://app.atmos.com.mx/api/v1/contacts \
-H "Authorization: Bearer at-api-XXXX.sk_YYYY"
Crear un contacto:
curl -X POST https://app.atmos.com.mx/api/v1/contacts \
-H "Authorization: Bearer at-api-XXXX.sk_YYYY" \
-H "Content-Type: application/json" \
-d '{"firstName":"Ada","email":"ada@example.com"}'
Los identificadores en URLs y payloads son friendlyId (C0001, N0002, …), nunca UUID.
Paginación
Las listas y las búsquedas devuelven una página y un cursor:
{
"results": [ { "friendlyId": "C0001", "email": "ada@example.com" } ],
"paging": { "next": { "after": "eyJjcmVhdGVkQXQiOiI…", "link": "https://app.atmos.com.mx/api/v1/contacts?after=eyJ…" } }
}
Se pide la siguiente con ?after={cursor}. Cuando ya no hay más, paging.next no viene —
esa es la condición de fin, no un results vacío. El cursor va firmado: no se construye a mano.
Cuota y límites
Cada respuesta trae X-RateLimit-Limit, X-RateLimit-Remaining y X-RateLimit-Reset. Para
consultarlo sin gastar una llamada de negocio —y no enterarte con el primer 429:
GET https://app.atmos.com.mx/api/v1/usage
Devuelve el nombre del token, su modo (live/test), su alcance de datos, los
objetos a los que da acceso y usage con lo que queda de la cubeta de ráfaga y de la
diaria. usage puede venir en null si el contador de límites no está disponible: en ese caso
guíate por las cabeceras X-RateLimit-* de cualquier respuesta.
Reintentos e idempotencia
Los lotes de create y upsert aceptan la cabecera Idempotency-Key (cualquier cadena
única que elijas, p.ej. un UUID por lote):
POST https://app.atmos.com.mx/api/v1/contacts/batch/create
Idempotency-Key: 7f1c…
Si se corta la red y reintentas con la misma clave, Atmos devuelve el resultado de la
primera ejecución en vez de crear todo dos veces. La clave se recuerda 24 horas.
Alcance exacto, para que no te sorprenda: protege reintentos secuenciales, que es el caso
real (falla la red, vuelves a intentar). Dos peticiones simultáneas con la misma clave sí
pueden ejecutarse las dos — no hay bloqueo. No la uses para paralelizar el mismo lote.
Tokens de prueba
Un token puede crearse en modo prueba (test). Funciona igual, con su **propia cubeta de
límites**, y sus llamadas quedan marcadas como de prueba. Sirve para desarrollar la integración
sin ensuciar las métricas del token real. El modo se elige al crear el token y se consulta en
/v1/usage.
Servidor MCP (Model Context Protocol)
Además de REST, Atmos habla MCP: un asistente (Claude Desktop, Cursor, Cosmos) se conecta y
opera el CRM con las mismas reglas del token. No es una API paralela — por dentro corre el mismo
motor, el mismo scope, el mismo alcance de datos y los mismos límites. Una llamada MCP cuenta
como una llamada de API.
- Endpoint:
https://app.atmos.com.mx/api/v1/mcp(Streamable HTTP, JSON-RPC 2.0). - Auth: el mismo
Authorization: Bearer at-api-…. - Métodos:
initialize,ping,tools/list,tools/call.
Las herramientas se derivan del scope del token: verás list_, search_, get_, create_,
update_ y delete_ por cada objeto que el token tenga autorizado, y nada más — un token de
solo lectura no expone herramientas de escritura, así que el asistente no puede ni intentarlo.
Configuración típica en un cliente MCP:
{
"mcpServers": {
"atmos": {
"url": "https://app.atmos.com.mx/api/v1/mcp",
"headers": { "Authorization": "Bearer at-api-XXXX.sk_YYYY" }
}
}
}
Los errores usan el envelope único con correlationId (ver "Códigos de error"), útil para
soporte: identifica la llamada exacta.
Integración web (pixel de seguimiento + formularios)
Lo que casi siempre se quiere al conectar un sitio con Atmos. Nada de esto usa el token de
API en el navegador.
1. Pixel de seguimiento
Una etiqueta en el <head> de todas las páginas del sitio:
<script src="https://app.atmos.com.mx/api/public/track.js"
data-workspace="XXXXXXXXX"
async></script>
data-workspace es el código de portal (9 caracteres alfanuméricos); se ve en la URL del
CRM. El script no lleva token y es seguro en el frontend: solo escribe, nunca lee datos.
Captura automáticamente: vistas de página (con referrer y parámetros utm_*), tiempo en
página, clicks y profundidad de scroll (mapas de calor), y un latido cada 30 s mientras la
pestaña está activa. Respeta Do Not Track (si el navegador lo pide, no envía nada) y
soporta SPAs (escucha pushState/popstate, no hace falta recargar). Los clicks sobre
input, textarea y select se ignoran a propósito para no capturar datos personales.
API de JavaScript disponible después de cargar:
// Vincula la sesión anónima con un contacto (llamar tras un login o un envío de formulario)
window.Atmos.identify({ email: 'ada@example.com' });
// Evento propio
window.Atmos.track('demo_solicitada', { plan: 'growth' });
También se identifica solo si la URL trae ?atmos_ct={token} (los enlaces de campañas de
Atmos lo añaden), lo que atribuye la visita al contacto correcto.
2. Formularios
Dos caminos, en orden de preferencia:
a) Incrustar el formulario de Atmos — una línea, sin backend propio. El formulario se
crea en el CRM (Formularios) y ya trae anti-bot, Turnstile, campos condicionales, deduplicado
de contactos y disparo de automatizaciones:
<div data-form="{slug-del-formulario}" data-workspace="XXXXXXXXX"></div>
<script src="https://app.atmos.com.mx/embed.js" async></script>
data-form es el slug del formulario (el mismo de su URL pública
app.atmos.com.mx/{portal}/forms/{slug}). Se pueden incrustar varios en una misma página:
el script monta todos los contenedores que tengan data-form + data-workspace.
b) Formulario propio del sitio — cuando el diseño del formulario debe ser del sitio. El
envío va a tu servidor, y tu servidor llama a esta API:
POST https://app.atmos.com.mx/api/v1/contacts
Authorization: Bearer at-api-XXXX.sk_YYYY
Content-Type: application/json
{"firstName":"Ada","lastName":"Lovelace","email":"ada@example.com","phone":"+52...","source":"web"}
⚠️ El token at-api-… nunca va en el navegador. Es un secreto M2M con el scope completo
que le diste: publicado en el HTML o en un bundle de JavaScript, cualquiera puede leer y
escribir en el portal. Debe vivir en una variable de entorno del servidor (route handler de
Next.js, función serverless, backend propio) y el formulario postea a ese endpoint interno.
Después de un envío exitoso, llama a window.Atmos.identify({ email }) en el cliente para
que la navegación anónima previa quede atribuida al contacto recién creado.
Campos personalizados
Un campo personalizado se usa por su nombre interno, igual que uno de fábrica. Si en
Configuración → Campos creaste servicio, en la API es servicio. Sin prefijos ni envoltorios.
Consulta los campos de un objeto —de fábrica y personalizados— con:
GET /api/v1/properties/contact
El key de cada campo es exactamente el nombre que se usa para escribirlo y leerlo:
POST /api/v1/contacts
{"email":"ada@example.com","servicio":"Consultoría","presupuesto":15000}
GET /api/v1/contacts/C0001
→ {"friendlyId":"C0001","email":"ada@example.com","servicio":"Consultoría","presupuesto":15000,…}
Funcionan igual en ?fields= (?fields=email,servicio), en la búsqueda y en la
importación:
POST /api/v1/contacts/search
{"filterGroups":[{"filters":[{"field":"servicio","operator":"eq","value":"Consultoría"}]}]}
Detalles a tener en cuenta:
- Tipos. Un campo numérico devuelve un número; los de fecha, texto en formato
YYYY-MM-DD. - Operadores de búsqueda. Texto y desplegables:
eq,neq,in,nin,contains,
startsWith. Números y fechas: además gt, gte, lt, lte, between. Todos aceptan
isNull/isNotNull, que también cubren al registro que no tiene ese campo lleno.
- Nombres reservados. No se puede crear un campo personalizado con el nombre de uno de
fábrica del mismo objeto (email, phone, status…): un nombre identifica a un solo campo.
- Acceso. Un campo restringido por permisos no se devuelve (o llega como
****si así se
configuró), y filtrar por él responde 403 en vez de ignorar el filtro en silencio.
Convenciones
- Base de la API:
https://app.atmos.com.mx/api/v1 - OpenAPI 3.1 (JSON):
https://docs.atmos.com.mx/api/docs/openapi.json - Servidor MCP (Streamable HTTP, JSON-RPC 2.0):
https://app.atmos.com.mx/api/v1/mcp - Identificadores: friendlyId (
C0001contacto,Eempresa,Nnegocio,Aactividad,Tticket,Pproyecto,Ffactura). Nunca UUID. - Paginación por cursor:
?limit=&after=; la respuesta traepaging.next.after. - Selección de campos:
?fields=firstName,email. - Errores: envelope único
{ status, category, message, correlationId, errors[] }. - Límites de tasa: cabeceras
X-RateLimit-Limit,X-RateLimit-Remaining,X-RateLimit-Reset.
Endpoints
CRM
GET /api/v1/{object}
Lista registros de un objeto. Uno de: contacts, companies, deals, activities, tickets, projects, invoices, products, quotes, lists, forms, o el api_name de un objeto personalizado (#84) del portal.
- Parámetros de ruta:
object - Query:
limit,after,fields - operationId:
listRecords
POST /api/v1/{object}
Crea un registro. Los CAMPOS válidos dependen del portal: consúltalos en GET /v1/properties/{objectType} — el key de cada uno es el nombre que va en el body (los personalizados, por su nombre interno, sin prefijo). Objetos escribibles: contacts, companies, deals, activities, tickets, projects, invoices.
- Parámetros de ruta:
object - operationId:
createRecord
GET /api/v1/{object}/{id}
Obtiene un registro por friendlyId.
- Parámetros de ruta:
object,id - Query:
fields - operationId:
getRecord
PATCH /api/v1/{object}/{id}
Actualiza un registro por friendlyId (parcial: solo los campos enviados). Los campos válidos son los mismos de GET /v1/properties/{objectType}.
- Parámetros de ruta:
object,id - operationId:
updateRecord
DELETE /api/v1/{object}/{id}
Envía un registro a la papelera (soft delete).
- Parámetros de ruta:
object,id - operationId:
deleteRecord
POST /api/v1/{object}/search
Búsqueda con filterGroups (OR entre grupos, AND dentro).
- Parámetros de ruta:
object - Body:
filterGroups,sorts,fields,limit,after - operationId:
searchRecords
POST /api/v1/{object}/batch/{op}
Operación en lote (op: create|read|update|archive|upsert). 207 Multi-Status en éxito parcial.
- Parámetros de ruta:
object,op - Body:
inputs,idProperty - operationId:
batchRecords
POST /api/v1/{object}/{id}/permanent-delete
Borrado permanente / derecho al olvido (irreversible). Requiere { confirm: true }.
- Parámetros de ruta:
object,id - Body:
confirm - operationId:
permanentDeleteRecord
PUT /api/v1/{object}/{id}/associations/{toType}/{toId}
Vincula dos registros por su pivote nativo.
- Parámetros de ruta:
object,id,toType,toId - operationId:
associate
DELETE /api/v1/{object}/{id}/associations/{toType}/{toId}
Elimina el vínculo entre dos registros.
- Parámetros de ruta:
object,id,toType,toId - operationId:
dissociate
Soporte
GET /api/v1/users
Lista los miembros del portal.
- operationId:
listUsers
GET /api/v1/teams
Lista los equipos del portal.
- operationId:
listTeams
GET /api/v1/owners
Lista los usuarios asignables (owners).
- operationId:
listOwners
GET /api/v1/pipelines
Lista los pipelines de negocios.
- operationId:
listPipelines
GET /api/v1/pipelines/{id}/stages
Lista las etapas de un pipeline.
- Parámetros de ruta:
id - operationId:
listStages
Properties
GET /api/v1/properties/{objectType}
Lista las definiciones de campo (default + custom) de un objeto.
- Parámetros de ruta:
objectType - operationId:
listProperties
POST /api/v1/properties/{objectType}
Crea un campo personalizado.
- Parámetros de ruta:
objectType - operationId:
createProperty
PATCH /api/v1/properties/{objectType}/{fieldKey}
Edita un campo personalizado.
- Parámetros de ruta:
objectType,fieldKey - operationId:
updateProperty
DELETE /api/v1/properties/{objectType}/{fieldKey}
Elimina un campo personalizado.
- Parámetros de ruta:
objectType,fieldKey - operationId:
deleteProperty
Webhooks
GET /api/v1/webhooks
Lista las suscripciones de webhooks.
- operationId:
listWebhooks
POST /api/v1/webhooks
Crea una suscripción de webhook. Eventos válidos: contact.created, contact.updated, contact.deleted, company.created, company.updated, company.deleted, deal.created, deal.updated, deal.deleted, activity.created, activity.updated, activity.deleted, ticket.created, ticket.updated, ticket.deleted, project.created, project.updated, project.deleted, invoice.created, invoice.updated, invoice.deleted, product.created, product.updated, product.deleted, quote.created, quote.updated, quote.deleted, list.created, list.updated, list.deleted, form.created, form.updated, form.deleted.
- Body:
url,events,active - operationId:
createWebhook
GET /api/v1/webhooks/{id}
Obtiene una suscripción.
- Parámetros de ruta:
id - operationId:
getWebhook
PATCH /api/v1/webhooks/{id}
Edita una suscripción.
- Parámetros de ruta:
id - Body:
url,events,active - operationId:
updateWebhook
DELETE /api/v1/webhooks/{id}
Elimina una suscripción.
- Parámetros de ruta:
id - operationId:
deleteWebhook
GET /api/v1/webhooks/{id}/deliveries
Log de entregas de una suscripción.
- Parámetros de ruta:
id - operationId:
listDeliveries
POST /api/v1/webhooks/{id}/deliveries/{deliveryId}/replay
Reintenta una entrega.
- Parámetros de ruta:
id,deliveryId - operationId:
replayDelivery
Import
POST /api/v1/imports
Inicia una importación (JSON rows). Objetos: contacts, companies, deals, activities, tickets, projects, invoices.
- Body:
objectType,rows,csv,mode,dateFormat - operationId:
startImport
GET /api/v1/imports
Lista las importaciones.
- operationId:
listImports
GET /api/v1/imports/{id}
Estado/progreso de una importación.
- Parámetros de ruta:
id - operationId:
getImport
DELETE /api/v1/imports/{id}
Cancela una importación en curso.
- Parámetros de ruta:
id - operationId:
cancelImport
Token
GET /api/v1/usage
Consumo y cuota RESTANTE del token que hace la llamada: ráfaga y diaria, modo (live/test) y objetos a los que da acceso. Sirve para anticipar un 429 en vez de descubrirlo.
- operationId:
getUsage
POST /api/v1/mcp
Servidor MCP (Model Context Protocol) sobre Streamable HTTP, JSON-RPC 2.0: initialize, ping, tools/list, tools/call. Mismo token, mismo scope y mismos límites que REST. Ver la sección "Servidor MCP" de esta doc.
- operationId:
mcpEndpoint
Códigos de error
400 VALIDATION_ERROR— datos inválidos (detalle por campo enerrors[]).401 UNAUTHORIZED— token ausente, inválido o revocado.403 FORBIDDEN— el token no tiene esa acción, ese objeto o ese campo en su scope.404 NOT_FOUND— el friendlyId no existe en el portal del token.409 CONFLICT— conflicto de estado (p.ej. duplicado en upsert).429 RATE_LIMITED— límite de tasa excedido; reintentar segúnX-RateLimit-Reset.