Relm
CRM API-primero para agentes de IA: contactos, empresas, negocios, pipelines y automatizaciones a través de 41 herramientas MCP, OAuth 2.1 o clave bearer.
Documentación
Documentación de la API
Relm es API-first. Todo lo que puedes hacer en el panel de control, un agente puede hacerlo a través de REST o del servidor MCP nativo, con la misma clave bearer.
URL base y autenticación
La API se encuentra en https://api.relmcrm.com. Autentica cada solicitud con una clave bearer de ámbito de espacio de trabajo. Las claves se muestran una sola vez, se almacenan con hash SHA-256 y vienen en variantes live y test.
Authorization: Bearer relm_live_...
Genera claves en el panel de control. Las claves relm_test_ escriben en un conjunto de datos de prueba aislado que es gratuito e invisible para la facturación y el panel de control: úsalas libremente para desarrollar. El modo de prueba es un entorno aislado, no un almacenamiento: los registros de prueba se eliminan automáticamente 7 días después de su creación.
Inicio rápido
Crea tu primer contacto en una sola llamada:
curl https://api.relmcrm.com/v1/contacts \
-H "Authorization: Bearer relm_live_..." \
-H "Content-Type: application/json" \
-d '{ "email": "[email protected]", "first_name": "Ada", "last_name": "Lovelace" }'
Respuesta:
{
"id": "con_x8f3k2m9q2",
"object": "contact",
"email": "[email protected]",
"first_name": "Ada",
"last_name": "Lovelace",
"created_at": "2026-07-09T12:00:00.000Z"
}
SDK de TypeScript
¿Prefieres tipos en lugar de curl? El SDK oficial es un envoltorio sin dependencias sobre la misma API.
npm i relmcrm
import { Relm } from "relmcrm";
const relm = new Relm(process.env.RELM_KEY!);
const ada = await relm.contacts.create({ email: "[email protected]", first_name: "Ada" });
await relm.deals.create({ title: "Acme - annual", stage: "lead" });
// page through everything
for await (const c of relm.contacts.all()) console.log(c.id, c.email);
Las llamadas fallidas lanzan un RelmError que puedes leer para autocorregirte: e.status, e.validOptions, e.hint. Funciona en Node 18+, Bun, Deno y el navegador. En npm: npmjs.com/package/relmcrm.
Convenciones
- IDs con prefijo -
con_contactos,cmp_empresas,deal_negocios,act_actividades. Autodescriptivos y seguros para copiar y pegar. - Sobre (envelope) - los endpoints de listado devuelven
{ "object": "list", "data": [...], "has_more": true, "next_cursor": "..." }. - Paginación por cursor - pasa
?limit=100&cursor=.... Keyset sobre(created_at, id), estable bajo escrituras.limitpor defecto es25y está limitado a100(los valores mayores se ajustan). - Búsqueda y filtros - los endpoints de listado aceptan
?q=para una coincidencia de subcadena sin distinción de mayúsculas (contactos: nombre, correo, teléfono, LinkedIn; empresas: nombre, dominio; negocios: título), además de filtros exactos como?company_id=,?stage=,?pipeline=(alias?pipeline_id=). Un filtro no reconocido se rechaza con400+valid_options, para que nunca obtengas resultados sin filtrar silenciosamente. - Idempotencia - envía un encabezado
Idempotency-Keyen una creación; un reintento devuelve el registro original en lugar de duplicarlo. - Concurrencia optimista - cada registro lleva un
version; envíaIf-Matchpara protegerte contra actualizaciones perdidas. Una escritura obsoleta devuelve412 version_conflict. - Modos - la clave decide
testvslive; los datos nunca se cruzan.
Objetos principales
Contactos, empresas, negocios y actividades tienen CRUD completo en /v1/<object> con herramientas MCP correspondientes (relm_create, relm_list, relm_get, relm_update, relm_delete). Las superficies restantes tienen endpoints y herramientas de propósito específico.
| Objeto | Endpoint | Qué es |
|---|---|---|
| Contacto | /v1/contacts | Personas. Correo opcional: los leads solo con teléfono o LinkedIn son válidos. |
| Empresa | /v1/companies | Cuentas. Los contactos y negocios se vinculan a ellas. |
| Negocio | /v1/deals | Oportunidades en un pipeline + etapa. Lleva un monto. |
| Actividad | /v1/activities | Notas, llamadas, correos, reuniones. Se puede retrofechar mediante occurred_at. |
| Pipeline | /v1/pipelines | Pipelines con nombre, cada uno con etapas ordenadas. |
| Automatización | /v1/automations | Reglas activadas por eventos "cuando X entonces Y". |
| Secuencia | /v1/sequences | Secuencias de goteo de varios pasos con inscripción automática y condiciones de salida. |
| Plantilla | /v1/templates | Plantillas de correo reutilizables referenciadas por automatizaciones y secuencias. |
| Webhook | /v1/webhooks | Suscribe un endpoint https a eventos. Firmado con HMAC, con reintentos y cola de mensajes fallidos. |
| Búsqueda | /v1/search | Búsqueda entre objetos sobre contactos, empresas y negocios. |
| Esquema | /v1/schema | Registro en vivo y autodescriptivo de objetos + campos + enums. |
Lee el esquema primero
Antes de escribir, un agente debe GET /v1/schema para aprender qué objetos, campos y valores de enum existen. Si luego envía un valor desconocido, el error le indica exactamente qué es válido:
POST /v1/contacts { "type": "prospect" }
422 Unprocessable Entity (application/problem+json)
{
"type": "https://relmcrm.com/errors/unknown_value",
"title": "Unknown Value",
"status": 422,
"detail": "'prospect' is not a valid contact type.",
"code": "unknown_value",
"field": "contact type",
"valid_options": ["lead", "customer"]
}
Este es el contrato de "nunca confundirse": los agentes se autocorrigen a partir del error en lugar de fallar a ciegas o alucinar un campo. ¿Necesitas un nuevo valor? Créalo: relm_create_enum_value, relm_create_field, relm_create_type.
Escrituras por lotes
Importa muchos registros en un solo viaje de ida y vuelta con POST /v1/batch (o la herramienta MCP relm_batch). Cada operación se mide individualmente: el lote ahorra viajes de ida y vuelta, no cuota.
POST /v1/batch
{ "operations": [
{ "method": "create", "object": "contact", "data": { "email": "[email protected]" } },
{ "method": "create", "object": "deal", "data": { "title": "Acme" } }
]}
Conéctate vía MCP
Relm incluye un servidor nativo de Model Context Protocol en https://api.relmcrm.com/mcp (HTTP Streamable, solicitud/respuesta). Cada operación de CRM es una herramienta MCP tipada. No se necesita clave para initialize o tools/list: el catálogo es público para que clientes y directorios puedan descubrirlo; tools/call requiere una credencial.
Dos formas de conectarte. Si tu cliente admite OAuth (la mayoría de los clientes de chat lo hacen), solo apúntalo a la URL del servidor y te guiará para iniciar sesión: el cliente se registra, tú apruebas en un navegador y nunca manejas un secreto. Si prefieres pegar una clave, o estás configurando un servidor o un trabajo de CI, usa una clave de API en un encabezado:
{
"mcpServers": {
"relm": {
"type": "http",
"url": "https://api.relmcrm.com/mcp",
"headers": { "Authorization": "Bearer relm_live_..." }
}
}
}
Luego habla con él en lenguaje natural: "añade estos cinco leads y abre un negocio para cada uno en el pipeline de ventas". El agente llama a relm_describe_schema y luego agrupa las escrituras. Un solo POST de MCP puede llevar un array de llamadas a herramientas; cada una se mide por llamada.
OAuth 2.1
Para clientes que autorizan con OAuth, todo es descubrible: no hay nada que registrar manualmente:
- Metadatos de recurso protegido:
https://api.relmcrm.com/.well-known/oauth-protected-resource - Metadatos del servidor de autorización:
https://api.relmcrm.com/.well-known/oauth-authorization-server - Registro dinámico de clientes:
POST https://api.relmcrm.com/oauth/register(RFC 7591) - Código de autorización + PKCE (
S256requerido) y tokens de actualización con rotación. Ámbito:crm.
Un tools/call no autenticado devuelve 401 con un encabezado WWW-Authenticate que apunta a esos metadatos, que es como un cliente sabe que debe ofrecerte un botón de Conectar. Las concesiones de OAuth actúan sobre datos en vivo; el modo de prueba sigue siendo solo con clave de API.
Conéctate vía A2A
Relm también habla Agent2Agent en https://api.relmcrm.com/a2a (JSON-RPC 2.0). Envía un message/send cuya parte de datos sea {"tool":"relm_...","arguments":{...}}; Relm lo ejecuta de forma síncrona contra las mismas herramientas validadas y devuelve una Task terminal. La tarjeta de agente está en /.well-known/agent-card.json.
OpenAPI
Toda la superficie REST está descrita por una especificación OpenAPI 3.1 legible por máquina: impórtala en tu generador de clientes, Postman o una cadena de herramientas de agente.
Webhooks
Suscribe un endpoint https a eventos de CRM. Regístrate con POST /v1/webhooks (o relm_create_webhook): la respuesta devuelve un secret de firma una sola vez. Eventos: contact.created, contact.updated, deal.created, deal.updated, deal.stage_changed (o ["*"] para todos).
curl https://api.relmcrm.com/v1/webhooks \
-H "Authorization: Bearer relm_live_..." -H "Content-Type: application/json" \
-d '{ "url": "https://your.app/relm", "events": ["deal.stage_changed"] }'
# -> { "id": "wh_...", "secret": "whsec_...", ... } (store the secret; shown once)
Cada entrega es un POST JSON con los encabezados Relm-Event, Relm-Delivery y Relm-Signature: t=<unix>,v1=<hmac>. Verifícalo recalculando HMAC-SHA256 de "<t>.<raw body>" con tu secreto:
import crypto from "node:crypto";
function verify(secret, rawBody, header) {
const { t, v1 } = Object.fromEntries(header.split(",").map(p => p.split("=")));
const expected = crypto.createHmac("sha256", secret).update(\`${t}.${rawBody}\`).digest("hex");
return crypto.timingSafeEqual(Buffer.from(v1), Buffer.from(expected));
}
Los no-2xx o los tiempos de espera se reintentan con retroceso (1m, 5m, 30m, 2h, 6h) y se envían a la cola de mensajes fallidos después de 6 intentos. Inspecciona los intentos recientes en GET /v1/webhooks/{id}/deliveries. Las URL en modo en vivo deben ser https públicas (se rechazan hosts privados, de bucle local y de enlace local); las claves de modo de prueba pueden apuntar a localhost.
Errores
Cada error es problem+JSON RFC-9457. type es un URI estable (https://relmcrm.com/errors/<code>) que resuelve a una página de referencia breve, con un title legible, un code de máquina y, cuando es útil, valid_options y un suggestion.
| Estado | code | Significado |
|---|---|---|
| 400 | bad_request | JSON malformado o parámetro incorrecto. |
| 401 | unauthorized | Clave de API faltante o inválida. |
| 403 | plan_limit / forbidden | Límite del plan alcanzado (Free permite 2 automatizaciones / 1 secuencia) o acción no permitida para esta clave. |
| 404 | not_found | No existe tal registro en este espacio de trabajo/modo. |
| 409 | conflict / idempotency_key_reused | Duplicado (p. ej., correo: devuelve el registro existente) o clave de idempotencia reutilizada. |
| 412 | version_conflict | El registro cambió desde que lo leíste: vuelve a obtenerlo y a aplicarlo. |
| 422 | unknown_value / unknown_field / validation_failed / invalid_reference | Entrada no procesable: consulta valid_options y suggestion. |
| 429 | rate_limited / quota_exceeded / spend_cap_reached | Reduce la velocidad, cuota mensual agotada o límite de gasto alcanzado. |
Límites de velocidad y cuotas
Las solicitudes tienen límite de velocidad por espacio de trabajo por minuto y se cuentan contra una cuota mensual. Las respuestas llevan los encabezados X-RateLimit-* y X-Quota-*.
| Plan | Solicitudes mensuales | Por encima del límite |
|---|---|---|
| Free | 1,000 | Se detiene en seco (429) |
| Pro - $29/mes | 100,000 | Exceso medido, $0.0001/solicitud |
| Scale - $249/mes | 2,000,000 | Exceso medido, $0.0001/solicitud |
En los planes de pago puedes establecer un límite de gasto duro; en $0 se comporta como Free y se detiene en la cuota en lugar de facturar el exceso. El modo de prueba nunca cuenta.
¿Listo para construir?
Genera una clave gratuita y apunta tu agente hacia ella.