¿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.

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:

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.

fábrica del mismo objeto (email, phone, status…): un nombre identifica a un solo campo.

configuró), y filtrar por él responde 403 en vez de ignorar el filtro en silencio.

Convenciones

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.

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.

GET /api/v1/{object}/{id}

Obtiene un registro por friendlyId.

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}.

DELETE /api/v1/{object}/{id}

Envía un registro a la papelera (soft delete).

POST /api/v1/{object}/search

Búsqueda con filterGroups (OR entre grupos, AND dentro).

POST /api/v1/{object}/batch/{op}

Operación en lote (op: create|read|update|archive|upsert). 207 Multi-Status en éxito parcial.

POST /api/v1/{object}/{id}/permanent-delete

Borrado permanente / derecho al olvido (irreversible). Requiere { confirm: true }.

PUT /api/v1/{object}/{id}/associations/{toType}/{toId}

Vincula dos registros por su pivote nativo.

DELETE /api/v1/{object}/{id}/associations/{toType}/{toId}

Elimina el vínculo entre dos registros.

Soporte

GET /api/v1/users

Lista los miembros del portal.

GET /api/v1/teams

Lista los equipos del portal.

GET /api/v1/owners

Lista los usuarios asignables (owners).

GET /api/v1/pipelines

Lista los pipelines de negocios.

GET /api/v1/pipelines/{id}/stages

Lista las etapas de un pipeline.

Properties

GET /api/v1/properties/{objectType}

Lista las definiciones de campo (default + custom) de un objeto.

POST /api/v1/properties/{objectType}

Crea un campo personalizado.

PATCH /api/v1/properties/{objectType}/{fieldKey}

Edita un campo personalizado.

DELETE /api/v1/properties/{objectType}/{fieldKey}

Elimina un campo personalizado.

Webhooks

GET /api/v1/webhooks

Lista las suscripciones de webhooks.

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.

GET /api/v1/webhooks/{id}

Obtiene una suscripción.

PATCH /api/v1/webhooks/{id}

Edita una suscripción.

DELETE /api/v1/webhooks/{id}

Elimina una suscripción.

GET /api/v1/webhooks/{id}/deliveries

Log de entregas de una suscripción.

POST /api/v1/webhooks/{id}/deliveries/{deliveryId}/replay

Reintenta una entrega.

Import

POST /api/v1/imports

Inicia una importación (JSON rows). Objetos: contacts, companies, deals, activities, tickets, projects, invoices.

GET /api/v1/imports

Lista las importaciones.

GET /api/v1/imports/{id}

Estado/progreso de una importación.

DELETE /api/v1/imports/{id}

Cancela una importación en curso.

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.

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.

Códigos de error