Volver al inicio
Referencia · v1

API de YaCRM

Lee pedidos, cotizaciones, productos, clientes, chats y mensajes, y maneja etiquetas y automatizaciones de tu negocio desde n8n, Make, tu ERP o tu propio código. Cada llamada pertenece a un solo negocio y respeta sus permisos.

Aislado por negocio JSON + paginación Llaves por conexión

Introducción

La URL base es https://yacrm.pro/api/public/v1. Las lecturas son GET y los comandos son POST, PUT o DELETE; todo en JSON.

Especificación para importar en n8n, ChatGPT (Acciones) u otras herramientas: https://yacrm.pro/api/public/v1/openapi.json. Desde el asistente MCP de YaCRM, pide «cómo conecto mi tienda por la API» y te dará esta referencia con tu ID.

La API no envía mensajes a tus clientes. Los comandos solo cambian etiquetas y automatizaciones, con las mismas reglas que la pantalla.

Inicio rápido

  1. Entra a YaCRM → Perfil → Conexión MCP / API.
  2. Copia el ID del negocio (botón del ojito) y crea una conexión con los permisos que necesitas. Copia la llave: solo se muestra una vez.
  3. Reemplaza $BUSINESS_ID y $YACRM_TOKEN (la llave) en el ejemplo y ejecútalo.
  4. Recibirás data (la lista) y next_cursor (la página siguiente, o null).
Tu primera llamada
curl "https://yacrm.pro/api/public/v1/businesses/$BUSINESS_ID/orders?limit=5" \
  -H "Authorization: Bearer $YACRM_TOKEN"

Autenticación

Envía la llave en el encabezado Authorization: Bearer <llave>. Sin ella, la respuesta es 401 missing_or_invalid_token.

  • Llave de conexión (yak_…): para n8n, Make, ChatGPT o tu ERP. La crea el dueño o un administrador en Perfil → Conexión MCP / API. Puede vencer en 1, 7, 30 o 90 días, en un plazo personalizado (hasta 3.650) o nunca, y solo puede lo que marcaste.
  • Token de sesión: solo para probar lecturas; vence en ~1 hora. Los comandos no lo aceptan (401 api_key_required).

Rotar sin cortes: «Nueva llave» crea otra y la anterior sigue funcionando 24 horas como máximo. «Revocar» corta todo de inmediato. Cada conexión actúa como la persona que la creó: si deja de ser dueña o administradora, la llave deja de funcionar (403 api_actor_inactive).

Trata la llave como una contraseña: no la pegues en chats, capturas ni repositorios. YaCRM no la guarda; si la pierdes, crea una nueva.

Límites por llave y minuto: 120 lecturas y 30 comandos. Si los pasas recibes 429 rate_limited.

Negocio y permisos

Cada ruta incluye el business_id. La API comprueba en cada llamada que la llave sea de ese negocio, tenga el permiso y que quien la creó siga teniendo acceso al módulo:

  • Pedidos → permiso orders:read · módulo orders
  • Cotizaciones → permiso quotes:read · módulo quotes
  • Productos → permiso catalog:read · módulo catalog
  • Clientes → permiso customers:read · módulo customers
  • Chats → permiso conversations:read · módulo inbox
  • Mensajes → permiso conversations:read · módulo inbox
  • Etiquetas → permiso labels:read · módulo inbox
  • Etiquetas puestas en chats → permiso labels:read · módulo inbox
  • Automatizaciones → permiso automations:read · módulo inbox
  • Canales conectados → permiso conversations:read · módulo inbox

Permisos disponibles al crear una conexión:

  • orders:read — Leer pedidos
  • quotes:read — Leer cotizaciones
  • catalog:read — Leer catálogo
  • catalog:write — Crear y actualizar productos desde una fuente de catálogo (ERP)
  • customers:read — Leer clientes
  • conversations:read — Leer chats y mensajes
  • labels:read — Leer etiquetas
  • labels:write — Crear y editar etiquetas, ponerlas y quitarlas en chats
  • automations:read — Leer automatizaciones
  • automations:write — Crear, editar y borrar automatizaciones

Si tienes varias tiendas, cambia solo el business_id de la URL; nunca se mezclan datos entre negocios. Si un miembro pierde el permiso, la siguiente página ya responde 403 module_forbidden.

Paginación

Parámetros permitidos (cada uno una sola vez):

  • limit: entero de 1 a 100. Por defecto 50.
  • cursor: el valor next_cursor (o sync_cursor) de la respuesta anterior.
  • order: desc (por defecto) o asc.
  • created_after o updated_after (según el orden del recurso): fecha ISO 8601 con zona, por ejemplo 2026-11-12T00:00:00Z.
  • Filtros propios de cada recurso (ver su tabla). Cualquier otro parámetro responde 422 invalid_query.

Los resultados vienen del más reciente al más antiguo. Repite con el nuevo next_cursor hasta que sea null. El cursor solo sirve para el mismo negocio, recurso, orden y filtros; no lo construyas a mano.

Página siguiente
curl "https://yacrm.pro/api/public/v1/businesses/$BUSINESS_ID/orders?limit=100&cursor=$NEXT_CURSOR" \
  -H "Authorization: Bearer $YACRM_TOKEN"

Sincronizar sin huecos (n8n)

Para recibir todo lo nuevo (mensajes, chats que cambiaron, etiquetas puestas) sin perder ni repetir nada:

  1. Consulta con order=asc y, la primera vez, created_after con la fecha desde la que quieres empezar.
  2. Cada respuesta trae sync_cursor. Guárdalo (en n8n: $getWorkflowStaticData('global')).
  3. En la próxima consulta envía los mismos parámetros y cursor=<sync_cursor>. Si next_cursor no es null, pide la página siguiente enseguida.

En orden ascendente, cada fila aparece 30 segundos después de creada o cambiada. Así una escritura que aún no termina no queda saltada.

n8n: mensajes nuevos cada 5 minutos
1) Schedule Trigger: cada 5 minutos
2) Code: const s = $getWorkflowStaticData('global'); return [{ json: { cursor: s.cursor ?? '' } }];
3) HTTP Request (GET)
   URL: https://yacrm.pro/api/public/v1/businesses/TU_BUSINESS_ID/messages
   Query: order=asc · direction=inbound · created_after=2026-11-12T00:00:00Z
          limit=100 · cursor={{ $json.cursor }} (omítelo si está vacío)
   Auth: Header Auth → Authorization: Bearer TU_LLAVE
4) Code: $getWorkflowStaticData('global').cursor = $json.sync_cursor;
   y devuelve $json.data para procesar cada mensaje

Errores

Todo error devuelve el mismo formato. Guarda el request_id: identifica la llamada si necesitas ayuda.

Formato de error
{
  "error": "module_forbidden",
  "request_id": "6f1c…"
}

Para errores 503, reintenta con espera creciente (1 s, 2 s, 4 s…). Los 4xx no se resuelven reintentando.

HTTPCódigoCausaQué hacer
401missing_or_invalid_tokenFalta el encabezado Authorization, o la llave o el token no son válidos.Envía «Authorization: Bearer <llave>» con una llave de Perfil → Conexión MCP / API.
401api_key_revokedLa llave o su conexión fueron revocadas.Crea una conexión nueva o rota la llave.
401api_key_expiredLa llave venció.Rota la llave en Perfil → Conexión MCP / API.
401api_key_requiredLos comandos (crear, editar, borrar) solo aceptan llaves de integración, no el token de sesión.Usa una llave con el permiso del comando.
422invalid_business_idEl business_id de la URL no tiene formato UUID.Copia el ID desde Perfil → Conexión MCP / API.
403business_scope_mismatchEl encabezado x-business-id no coincide con el negocio de la URL.Quita el encabezado o usa el mismo ID.
403business_forbiddenLa llave o el usuario no pertenecen a ese negocio.Usa la llave creada en ese negocio.
403api_actor_inactiveQuien creó la conexión ya no es dueño o administrador activo, o la tienda está suspendida.Un dueño o administrador debe crear una conexión nueva.
403scope_forbiddenLa llave no tiene el permiso de ese recurso o comando.Crea una conexión con ese permiso marcado.
403module_forbiddenNo hay permiso de ver o editar ese módulo (pedidos, cotizaciones, catálogo, clientes o bandeja).El dueño o administrador debe dar el permiso en Equipo.
429rate_limitedMás de 120 lecturas o 30 comandos por minuto con la misma llave.Espera al minuto siguiente y reintenta con espera creciente.
422invalid_querySe envió un parámetro no permitido, repetido o con valor inválido.Usa solo limit, cursor, order, <campo>_after y los filtros de ese recurso, una vez cada uno.
422invalid_limitlimit no es un entero entre 1 y 100.Usa un valor entre 1 y 100 (por defecto 50).
422invalid_cursorEl cursor está alterado o pertenece a otro negocio, recurso, orden o filtros.Usa exactamente el next_cursor o sync_cursor de la misma consulta (mismos filtros y orden).
428idempotency_key_requiredFalta el encabezado Idempotency-Key en un comando.Envía una clave única por operación (8 a 200 caracteres: letras, números, . _ : -).
422invalid_idempotency_keyLa Idempotency-Key no tiene el formato permitido.Usa 8 a 200 caracteres: letras, números, . _ : -
409idempotency_conflictEsa Idempotency-Key ya se usó con otro contenido.Usa una clave nueva para una operación distinta.
422invalid_bodyEl cuerpo no es JSON válido o no cumple el formato del comando.Revisa el campo «detail» y el ejemplo del comando.
422command_rejectedLa tienda rechazó el comando por una regla (campo «reason»).Lee «reason»: por ejemplo label_paid_protected, label_rule_loop, label_not_found, catalog_source_not_found o catalog_source_conflict_meli (enciende «Descontar stock local en Mercado Libre» en cada cuenta ML), erp_ml_variations_unsupported, o en fotos photo_not_uploaded (falta subirla), photo_invalid (no es jpg/png/webp o pasa de 5 MB), photo_path_forbidden (path de otra tienda o fuente) y photo_duplicated.
404not_foundLa ruta no existe en la API v1.Revisa la URL en esta referencia.
405method_not_allowedEse método no existe en esta ruta.Revisa el método en esta referencia.
503business_scope_unavailableNo se pudo comprobar el negocio en este momento.Reintenta con espera creciente.
503permission_unavailableNo se pudo comprobar la llave o el permiso en este momento.Reintenta con espera creciente.
503resource_read_unavailableLa lectura falló temporalmente.Reintenta con espera creciente.
503command_unavailableEl comando no se pudo ejecutar en este momento; no se aplicó nada.Reintenta con la misma Idempotency-Key.
503read_unavailableError interno inesperado.Reintenta; si persiste, comparte el request_id con soporte.

Pedidos

GET/api/public/v1/businesses/{business_id}/orders

Lista los pedidos del negocio, del más reciente al más antiguo.

Campos de cada elemento

id
uuid
Identificador único del pedido.
order_number
string · puede ser null
Número visible del pedido en YaCRM.
status
string
Estado general del pedido.
payment_status
string
Estado del pago registrado por la tienda.
fulfillment_status
string
Estado de preparación o despacho.
currency
string
Moneda del total (por ejemplo USD).
total
number
Total del pedido en su moneda.
created_at
datetime
Fecha de creación (ISO 8601, UTC).

Permiso de la llave: orders:read (módulo orders). Orden: created_at descendente.

Solicitud · cURL
curl "https://yacrm.pro/api/public/v1/businesses/$BUSINESS_ID/orders?limit=20" \
  -H "Authorization: Bearer $YACRM_TOKEN"
Respuesta 200 (ejemplo ilustrativo)
{
  "data": [
    {
      "id": "3f6c1e2a-8b1d-4c5e-9a0f-1b2c3d4e5f60",
      "order_number": "…",
      "status": "…",
      "payment_status": "…",
      "fulfillment_status": "…",
      "currency": "USD",
      "total": 132,
      "created_at": "2026-11-12T07:46:00.123456+00:00"
    }
  ],
  "next_cursor": "eyJ2IjoxLC4uLn0"
}

Cotizaciones

GET/api/public/v1/businesses/{business_id}/quotes

Lista las cotizaciones del negocio, de la más reciente a la más antigua.

Campos de cada elemento

id
uuid
Identificador único de la cotización.
number_seq
integer
Número correlativo de la cotización.
status
string
Estado de la cotización.
currency
string
Moneda de la cotización.
created_at
datetime
Fecha de creación (ISO 8601, UTC).

Permiso de la llave: quotes:read (módulo quotes). Orden: created_at descendente.

Solicitud · cURL
curl "https://yacrm.pro/api/public/v1/businesses/$BUSINESS_ID/quotes?limit=20" \
  -H "Authorization: Bearer $YACRM_TOKEN"
Respuesta 200 (ejemplo ilustrativo)
{
  "data": [
    {
      "id": "3f6c1e2a-8b1d-4c5e-9a0f-1b2c3d4e5f60",
      "number_seq": 1024,
      "status": "…",
      "currency": "USD",
      "created_at": "2026-11-12T07:46:00.123456+00:00"
    }
  ],
  "next_cursor": "eyJ2IjoxLC4uLn0"
}

Productos

GET/api/public/v1/businesses/{business_id}/catalog/products

Lista el catálogo, empezando por los productos modificados más recientemente.

Campos de cada elemento

id
uuid
Identificador único del producto.
sku
string
Código interno (SKU) de la tienda.
name
string
Nombre del producto.
brand
string · puede ser null
Marca.
status
string
Estado del producto en el catálogo.
base_price
number · puede ser null
Precio base de catálogo.
currency
string · puede ser null
Moneda del precio.
updated_at
datetime
Última modificación (ISO 8601, UTC).

Permiso de la llave: catalog:read (módulo catalog). Orden: updated_at descendente.

Solicitud · cURL
curl "https://yacrm.pro/api/public/v1/businesses/$BUSINESS_ID/catalog/products?limit=20" \
  -H "Authorization: Bearer $YACRM_TOKEN"
Respuesta 200 (ejemplo ilustrativo)
{
  "data": [
    {
      "id": "3f6c1e2a-8b1d-4c5e-9a0f-1b2c3d4e5f60",
      "sku": "…",
      "name": "…",
      "brand": "…",
      "status": "…",
      "base_price": 132,
      "currency": "USD",
      "updated_at": "2026-11-12T07:46:00.123456+00:00"
    }
  ],
  "next_cursor": "eyJ2IjoxLC4uLn0"
}

Clientes

GET/api/public/v1/businesses/{business_id}/customers

Lista los clientes del negocio. No incluye nombres ni datos de contacto.

Campos de cada elemento

id
uuid
Identificador único del cliente.
first_seen_at
datetime
Primera vez que escribió al negocio.
last_interaction_at
datetime · puede ser null
Última interacción registrada.

Permiso de la llave: customers:read (módulo customers). Orden: created_at descendente.

Solicitud · cURL
curl "https://yacrm.pro/api/public/v1/businesses/$BUSINESS_ID/customers?limit=20" \
  -H "Authorization: Bearer $YACRM_TOKEN"
Respuesta 200 (ejemplo ilustrativo)
{
  "data": [
    {
      "id": "3f6c1e2a-8b1d-4c5e-9a0f-1b2c3d4e5f60",
      "first_seen_at": "2026-11-12T07:46:00.123456+00:00",
      "last_interaction_at": "2026-11-12T07:46:00.123456+00:00"
    }
  ],
  "next_cursor": "eyJ2IjoxLC4uLn0"
}

Chats

GET/api/public/v1/businesses/{business_id}/conversations

Lista los chats de todos los canales, empezando por los que cambiaron más recientemente. No incluye nombre ni contacto.

Campos de cada elemento

id
uuid
Identificador único del chat.
channel
string
Canal: whatsapp, instagram, ml_question, ml_message o ml_postsale.
channel_id
uuid · puede ser null
Conexión exacta (número o cuenta) por la que llegó; null en chats antiguos que no la guardaron.
status
string
Estado del chat: open, pending, closed o escalated.
customer_id
uuid · puede ser null
Cliente del chat (ver Clientes).
assigned_user_id
uuid · puede ser null
Persona del equipo responsable del chat.
unread_count
integer
Mensajes sin leer.
last_message_at
datetime · puede ser null
Último mensaje en cualquier sentido.
last_inbound_at
datetime · puede ser null
Último mensaje del cliente.
created_at
datetime
Fecha de creación (ISO 8601, UTC).
updated_at
datetime
Última modificación (ISO 8601, UTC).

Filtros

  • channel — Solo chats de ese canal. Valores: whatsapp, instagram, ml_question, ml_message, ml_postsale.
  • status — Solo chats en ese estado. Valores: open, pending, closed, escalated.
  • customer_id — Solo chats de ese cliente. (UUID).
  • channel_id — Solo chats de esa conexión (ver Canales conectados). (UUID).

Permiso de la llave: conversations:read (módulo inbox). Orden: updated_at descendente.

Solicitud · cURL
curl "https://yacrm.pro/api/public/v1/businesses/$BUSINESS_ID/conversations?limit=20" \
  -H "Authorization: Bearer $YACRM_TOKEN"
Respuesta 200 (ejemplo ilustrativo)
{
  "data": [
    {
      "id": "3f6c1e2a-8b1d-4c5e-9a0f-1b2c3d4e5f60",
      "channel": "…",
      "channel_id": "3f6c1e2a-8b1d-4c5e-9a0f-1b2c3d4e5f60",
      "status": "…",
      "customer_id": "3f6c1e2a-8b1d-4c5e-9a0f-1b2c3d4e5f60",
      "assigned_user_id": "3f6c1e2a-8b1d-4c5e-9a0f-1b2c3d4e5f60",
      "unread_count": 1024,
      "last_message_at": "2026-11-12T07:46:00.123456+00:00",
      "last_inbound_at": "2026-11-12T07:46:00.123456+00:00",
      "created_at": "2026-11-12T07:46:00.123456+00:00",
      "updated_at": "2026-11-12T07:46:00.123456+00:00"
    }
  ],
  "next_cursor": "eyJ2IjoxLC4uLn0"
}

Mensajes

GET/api/public/v1/businesses/{business_id}/messages

Lista los mensajes de todos los canales. Para recibir los nuevos sin perder ninguno usa order=asc y guarda el sync_cursor de cada respuesta (ver Sincronizar).

Campos de cada elemento

id
uuid
Identificador único del mensaje.
conversation_id
uuid
Chat al que pertenece (ver Chats).
channel
string
Canal del mensaje.
direction
string
inbound (del cliente) u outbound (de la tienda).
role
string
Quién lo escribió: customer, agent (equipo), ai (Sofi) o system.
kind
string
Tipo: text, image, audio, video, document, location…
body
string · puede ser null
Texto del mensaje (los archivos no se incluyen).
status
string
Estado de envío: pending, sent, delivered, read o failed.
created_at
datetime
Fecha de registro (ISO 8601, UTC).

Filtros

  • conversation_id — Solo mensajes de ese chat. (UUID).
  • channel — Solo mensajes de ese canal. Valores: whatsapp, instagram, ml_question, ml_message, ml_postsale.
  • direction — inbound = del cliente; outbound = de la tienda. Valores: inbound, outbound.
  • role — Quién lo escribió. Valores: customer, agent, ai, system.

Permiso de la llave: conversations:read (módulo inbox). Orden: created_at descendente.

Solicitud · cURL
curl "https://yacrm.pro/api/public/v1/businesses/$BUSINESS_ID/messages?limit=20" \
  -H "Authorization: Bearer $YACRM_TOKEN"
Respuesta 200 (ejemplo ilustrativo)
{
  "data": [
    {
      "id": "3f6c1e2a-8b1d-4c5e-9a0f-1b2c3d4e5f60",
      "conversation_id": "3f6c1e2a-8b1d-4c5e-9a0f-1b2c3d4e5f60",
      "channel": "…",
      "direction": "…",
      "role": "…",
      "kind": "…",
      "body": "…",
      "status": "…",
      "created_at": "2026-11-12T07:46:00.123456+00:00"
    }
  ],
  "next_cursor": "eyJ2IjoxLC4uLn0"
}

Etiquetas

GET/api/public/v1/businesses/{business_id}/labels

Lista las etiquetas de venta de la tienda (las del tablero), de la más nueva a la más antigua.

Campos de cada elemento

id
uuid
Identificador único de la etiqueta.
key
string
Clave interna estable (las predeterminadas empiezan por lead_).
label
string
Nombre visible.
color_token
string
Color de la etiqueta.
ai_mode
string
Quién la pone: manual (equipo), auto (Sofi) o rules (activadores).
is_active
boolean
Si está en uso.
channels
string[]
Canales donde se usa.
created_at
datetime
Fecha de creación (ISO 8601, UTC).

Permiso de la llave: labels:read (módulo inbox). Orden: created_at descendente.

Solicitud · cURL
curl "https://yacrm.pro/api/public/v1/businesses/$BUSINESS_ID/labels?limit=20" \
  -H "Authorization: Bearer $YACRM_TOKEN"
Respuesta 200 (ejemplo ilustrativo)
{
  "data": [
    {
      "id": "3f6c1e2a-8b1d-4c5e-9a0f-1b2c3d4e5f60",
      "key": "…",
      "label": "…",
      "color_token": "…",
      "ai_mode": "…",
      "is_active": "…",
      "channels": "…",
      "created_at": "2026-11-12T07:46:00.123456+00:00"
    }
  ],
  "next_cursor": "eyJ2IjoxLC4uLn0"
}

Etiquetas puestas en chats

GET/api/public/v1/businesses/{business_id}/conversation-labels

Lista qué etiqueta tiene cada chat, de la puesta más reciente a la más antigua.

Campos de cada elemento

id
uuid
Identificador de la asignación.
conversation_id
uuid
Chat etiquetado.
tag_definition_id
uuid
Etiqueta puesta (ver Etiquetas).
source
string
Quién la puso: human, ai o rule.
created_at
datetime
Cuándo se puso (ISO 8601, UTC).

Filtros

  • conversation_id — Solo etiquetas de ese chat. (UUID).
  • tag_definition_id — Solo chats con esa etiqueta. (UUID).

Permiso de la llave: labels:read (módulo inbox). Orden: created_at descendente.

Solicitud · cURL
curl "https://yacrm.pro/api/public/v1/businesses/$BUSINESS_ID/conversation-labels?limit=20" \
  -H "Authorization: Bearer $YACRM_TOKEN"
Respuesta 200 (ejemplo ilustrativo)
{
  "data": [
    {
      "id": "3f6c1e2a-8b1d-4c5e-9a0f-1b2c3d4e5f60",
      "conversation_id": "3f6c1e2a-8b1d-4c5e-9a0f-1b2c3d4e5f60",
      "tag_definition_id": "3f6c1e2a-8b1d-4c5e-9a0f-1b2c3d4e5f60",
      "source": "…",
      "created_at": "2026-11-12T07:46:00.123456+00:00"
    }
  ],
  "next_cursor": "eyJ2IjoxLC4uLn0"
}

Automatizaciones

GET/api/public/v1/businesses/{business_id}/automations

Lista los activadores que ponen o quitan etiquetas solos.

Campos de cada elemento

id
uuid
Identificador del activador.
name
string
Nombre corto.
trigger_kind
string
Disparador (ver Comandos → Automatizaciones).
idle_minutes
integer · puede ser null
Minutos de espera para disparadores de tiempo.
from_label_id
uuid · puede ser null
Etiqueta que debe tener el chat.
add_label_id
uuid · puede ser null
Etiqueta que pone.
remove_from_label
boolean
Si quita la etiqueta de origen.
override_manual
boolean
Si actúa aunque la etiqueta la haya puesto una persona.
enabled
boolean
Si está encendido.
created_at
datetime
Fecha de creación (ISO 8601, UTC).

Permiso de la llave: automations:read (módulo inbox). Orden: created_at descendente.

Solicitud · cURL
curl "https://yacrm.pro/api/public/v1/businesses/$BUSINESS_ID/automations?limit=20" \
  -H "Authorization: Bearer $YACRM_TOKEN"
Respuesta 200 (ejemplo ilustrativo)
{
  "data": [
    {
      "id": "3f6c1e2a-8b1d-4c5e-9a0f-1b2c3d4e5f60",
      "name": "…",
      "trigger_kind": "…",
      "idle_minutes": 1024,
      "from_label_id": "3f6c1e2a-8b1d-4c5e-9a0f-1b2c3d4e5f60",
      "add_label_id": "3f6c1e2a-8b1d-4c5e-9a0f-1b2c3d4e5f60",
      "remove_from_label": "…",
      "override_manual": "…",
      "enabled": "…",
      "created_at": "2026-11-12T07:46:00.123456+00:00"
    }
  ],
  "next_cursor": "eyJ2IjoxLC4uLn0"
}

Canales conectados

GET/api/public/v1/businesses/{business_id}/channels

Cada número de WhatsApp, cuenta de Instagram o cuenta de Mercado Libre conectada, con su ID fijo. Ese ID es el channel_id de chats y avisos. Sin llaves ni tokens.

Campos de cada elemento

id
uuid
ID de la conexión (channel_id).
provider
string
waha (WhatsApp), instagram o meli (Mercado Libre).
display_name
string · puede ser null
Nombre que le diste a la conexión.
status
string
pending, connected, expired, revoked o error.
connected_at
datetime · puede ser null
Cuándo se conectó.
created_at
datetime
Fecha de creación (ISO 8601, UTC).

Filtros

  • provider — waha = WhatsApp, instagram = Instagram, meli = Mercado Libre. Valores: waha, instagram, meli.
  • status — Estado de la conexión. Valores: pending, connected, expired, revoked, error.

Permiso de la llave: conversations:read (módulo inbox). Orden: created_at descendente.

Solicitud · cURL
curl "https://yacrm.pro/api/public/v1/businesses/$BUSINESS_ID/channels?limit=20" \
  -H "Authorization: Bearer $YACRM_TOKEN"
Respuesta 200 (ejemplo ilustrativo)
{
  "data": [
    {
      "id": "3f6c1e2a-8b1d-4c5e-9a0f-1b2c3d4e5f60",
      "provider": "…",
      "display_name": "…",
      "status": "…",
      "connected_at": "2026-11-12T07:46:00.123456+00:00",
      "created_at": "2026-11-12T07:46:00.123456+00:00"
    }
  ],
  "next_cursor": "eyJ2IjoxLC4uLn0"
}

Comandos

Los comandos exigen una llave de conexión con el permiso indicado y el encabezado Idempotency-Key: una clave única por operación (8 a 200 caracteres: letras, números, . _ : -).

  • Si se corta la red, reintenta con la misma clave y el mismo cuerpo: no se repite el cambio y recibes la misma respuesta con "replayed": true.
  • La misma clave con otro cuerpo responde 409 idempotency_conflict. Un comando rechazado no guarda la clave: corrige y reintenta.
  • Respuesta correcta: 200 con { data, replayed }. Una regla de la tienda rechaza con 422 command_rejected y el motivo en reason.
  • «Pagó» nunca se pone ni se quita por la API: solo la pone un pago acreditado.

POST/api/public/v1/businesses/{business_id}/labels

Crear etiqueta

Crea una etiqueta de venta. Si envías «activators» o «removers», la llave también necesita automations:write. Permiso: labels:write.

Cuerpo (JSON)
{
  "label": "Mayorista",
  "color": "info",
  "mode": "manual",
  "instructions": "",
  "isActive": true,
  "channels": [
    "whatsapp",
    "instagram"
  ]
}

PUT/api/public/v1/businesses/{business_id}/labels/{label_id}

Editar etiqueta

Reemplaza nombre, color, quién la pone, instrucciones, estado y canales. Sin «activators»/«removers» no se tocan sus automatizaciones. Permiso: labels:write.

Cuerpo (JSON)
{
  "label": "Mayorista VIP",
  "color": "info",
  "mode": "manual",
  "instructions": "",
  "isActive": true,
  "channels": [
    "whatsapp"
  ]
}

POST/api/public/v1/businesses/{business_id}/conversations/{conversation_id}/labels

Poner etiqueta en un chat

Pone la etiqueta como si la pusiera el dueño de la conexión. «Pagó» no se puede poner: solo la pone un pago acreditado. Permiso: labels:write.

Cuerpo (JSON)
{
  "label_id": "3f6c1e2a-8b1d-4c5e-9a0f-1b2c3d4e5f60"
}

DELETE/api/public/v1/businesses/{business_id}/conversations/{conversation_id}/labels/{label_id}

Quitar etiqueta de un chat

Quita la etiqueta del chat. «Pagó» no se puede quitar por la API. Permiso: labels:write.

POST/api/public/v1/businesses/{business_id}/automations

Crear automatización

Crea un activador que pone una etiqueta sola. Mismas reglas que la pantalla (máximo 20, sin círculos, nunca «Pagó»). Permiso: automations:write.

Cuerpo (JSON)
{
  "name": "Sin respuesta 1 día",
  "trigger": "customer_idle",
  "idleMinutes": 1440,
  "fromLabelId": "8a2d4c6e-1f3b-4d5a-9c7e-2b4d6f8a0c1e",
  "addLabelId": "3f6c1e2a-8b1d-4c5e-9a0f-1b2c3d4e5f60",
  "removeFromLabel": true,
  "overrideManual": false,
  "enabled": true
}

PUT/api/public/v1/businesses/{business_id}/automations/{automation_id}

Editar automatización

Reemplaza todos los campos del activador. Permiso: automations:write.

Cuerpo (JSON)
{
  "name": "Sin respuesta 2 días",
  "trigger": "customer_idle",
  "idleMinutes": 2880,
  "fromLabelId": "8a2d4c6e-1f3b-4d5a-9c7e-2b4d6f8a0c1e",
  "addLabelId": "3f6c1e2a-8b1d-4c5e-9a0f-1b2c3d4e5f60",
  "removeFromLabel": true,
  "overrideManual": false,
  "enabled": true
}

DELETE/api/public/v1/businesses/{business_id}/automations/{automation_id}

Borrar automatización

Borra el activador. Permiso: automations:write.

POST/api/public/v1/businesses/{business_id}/catalog/sources/{source_id}/products

Enviar productos desde tu ERP

Hasta 50 por llamada. Crea o actualiza por external_id (el ID del producto en tu ERP) y solo escribe lo que cambió. Si el SKU ya existe en otra ficha no crea nada: queda en «Posibles duplicados» hasta que la tienda decida. Responde fila por fila: created, updated, unchanged, pending_merge o error. Rechaza todo si Mercado Libre está conectado (una sola fuente manda la existencia). Permiso: catalog:write.

Cuerpo (JSON)
{
  "items": [
    {
      "external_id": "ERP-1001",
      "sku": "PF-COR-0812",
      "name": "Pastilla de freno delantera Corolla 2008-2013",
      "description": "Juego de 4",
      "brand": "Bosch",
      "price": 25.5,
      "currency": "USD",
      "stock": 12,
      "status": "active",
      "photos": [
        {
          "path": "5d2e8a1c-3b4f-4a6d-8e9f-0a1b2c3d4e5f/7c9e1a3b-5d6f-4b8a-9c0d-1e2f3a4b5c6d/0b6f3c1e-2a4d-4e8f-9b1c-3d5e7f9a1b2c.jpg"
        }
      ]
    }
  ]
}

POST/api/public/v1/businesses/{business_id}/catalog/sources/{source_id}/photo-uploads

Pedir permiso para subir fotos

Hasta 10 por llamada (jpg, png o webp). Devuelve por foto un «path» y un «upload_url» de un solo uso (vence en 2 horas): sube los bytes con PUT a upload_url (Content-Type de la imagen, máx. 5 MB) y luego envía el path en «photos» de catalog.upsert. Las fotos no pasan por YaCRM. En catalog.upsert, «photos» reemplaza solo las fotos que puso tu ERP (la lista vacía las quita); las que subió la tienda no se tocan. En productos publicados en Mercado Libre se ignoran. Permiso: catalog:write.

Cuerpo (JSON)
{
  "files": [
    {
      "type": "jpg"
    },
    {
      "type": "png"
    }
  ]
}

POST/api/public/v1/businesses/{business_id}/catalog/sources/{source_id}/stock

Actualizar existencia y precio desde tu ERP

Liviano, hasta 50 por llamada: solo stock y price de productos ya enlazados (por external_id). Lo no enlazado vuelve como error not_linked. Permiso: catalog:write.

Cuerpo (JSON)
{
  "items": [
    {
      "external_id": "ERP-1001",
      "stock": 9,
      "price": 24.9
    }
  ]
}

Colores: info, warning, success, danger, muted, new, followup. Quién pone la etiqueta (mode): manual, auto (Sofi, con instrucciones de al menos una frase) o rules (activadores). Disparadores: first_inbound, inbound_unlabeled, customer_idle, customer_replied, order_created, order_paid, quote_created, quote_accepted, ml_purchase, case_opened, assigned, ai_paused, label_age.

Poner una etiqueta (cURL)
curl -X POST "https://yacrm.pro/api/public/v1/businesses/$BUSINESS_ID/conversations/$CONVERSATION_ID/labels" \
  -H "Authorization: Bearer $YACRM_TOKEN" \
  -H "Idempotency-Key: n8n-$EXECUTION_ID" \
  -H "Content-Type: application/json" \
  -d '{"label_id":"$LABEL_ID"}'

Avisos al instante (webhooks)

En vez de preguntar cada pocos minutos, YaCRM llama a tu n8n en cuanto pasa algo. Lo creas en Perfil → Avisos al instante o pidiéndoselo al asistente por MCP.

Llega un mensajeYaCRM lo guardaAviso firmadoTu n8n
El aviso se envía aparte del guardado: si tu n8n está caído, el mensaje igual queda guardado y el aviso se reintenta.
  • Eventos: message.received, message.sent, conversation_label.added, conversation_label.removed, order.created, order.updated (cambió estado, pago o despacho; trae changes con antes y después) y customer.created. El filtro por canal y conexión aplica a mensajes y etiquetas; pedidos y clientes llegan de todos los canales. Pedidos y clientes traen los mismos datos que la API, sin nombre ni contacto del comprador.
  • «Mensaje enviado» significa registrado en YaCRM; el estado (pendiente, enviado, entregado) viaja en data.status.
  • Encabezados: webhook-id (único: úsalo para no procesar dos veces), webhook-timestamp y webhook-signature (HMAC-SHA256, formato Standard Webhooks).
  • Responde 2xx en menos de 10 s. Si falla se reintenta con espera creciente. Con 5 fallos seguidos se frena unos minutos; si además lleva 24 horas sin una entrega buena, se pausa solo hasta que lo reactives.
  • Prueba en 60 segundos: crea un nodo Webhook (POST) en n8n, pega su URL de producción en el aviso y pulsa Probar.
Verificar la firma en n8n
// n8n · nodo Webhook con la opción «Raw Body» activada (la firma se calcula sobre el texto exacto)
// n8n · nodo Code siguiente:
const crypto = require('crypto');
const secret = 'whsec_…'; // la firma que te mostró YaCRM (guárdala como credencial)
const id = $json.headers['webhook-id'];
const ts = $json.headers['webhook-timestamp'];
const body = Buffer.from($binary.data.data, 'base64').toString('utf8');
const key = Buffer.from(secret.slice(6), 'base64');
const expected = 'v1,' + crypto.createHmac('sha256', key).update(`${id}.${ts}.${body}`).digest('base64');
const ok = $json.headers['webhook-signature'].split(' ').includes(expected);
if (!ok) throw new Error('Firma inválida');
return [{ json: JSON.parse(body) }];
Lo que recibe n8n (POST)
{
  "id": "8f6c…",
  "type": "message.received",
  "business_id": "TU_BUSINESS_ID",
  "created_at": "2026-11-12T21:04:11Z",
  "data": {
    "message_id": "…",
    "conversation_id": "…",
    "channel": "whatsapp",
    "direction": "inbound",
    "body": "Hola, ¿tienen pastillas para Corolla 2010?",
    "status": "delivered"
  }
}

Productos desde tu ERP

Tu ERP sigue siendo el dueño del catálogo; n8n traduce sus campos y YaCRM los recibe como una fuente con nombre propio, igual que llegan los de Mercado Libre.

Tu ERPn8n traduceYaCRM comparaSofi vende
Solo se escribe lo que cambió: reenviar el mismo catálogo no genera trabajo.
  1. Crea la fuente en Perfil → Fuentes de catálogo (ERP) y copia su ID.
  2. Crea una conexión API con el permiso catalog:write.
  3. En n8n, lee tu ERP, arma lotes de hasta 50 y envíalos a los comandos de abajo con un Idempotency-Key distinto por lote.
  • Enviar productos desde tu ERP (catalog.upsert): Hasta 50 por llamada. Crea o actualiza por external_id (el ID del producto en tu ERP) y solo escribe lo que cambió. Si el SKU ya existe en otra ficha no crea nada: queda en «Posibles duplicados» hasta que la tienda decida. Responde fila por fila: created, updated, unchanged, pending_merge o error. Rechaza todo si Mercado Libre está conectado (una sola fuente manda la existencia).
  • Pedir permiso para subir fotos (catalog.photo_upload): Hasta 10 por llamada (jpg, png o webp). Devuelve por foto un «path» y un «upload_url» de un solo uso (vence en 2 horas): sube los bytes con PUT a upload_url (Content-Type de la imagen, máx. 5 MB) y luego envía el path en «photos» de catalog.upsert. Las fotos no pasan por YaCRM. En catalog.upsert, «photos» reemplaza solo las fotos que puso tu ERP (la lista vacía las quita); las que subió la tienda no se tocan. En productos publicados en Mercado Libre se ignoran.
  • Actualizar existencia y precio desde tu ERP (catalog.stock_set): Liviano, hasta 50 por llamada: solo stock y price de productos ya enlazados (por external_id). Lo no enlazado vuelve como error not_linked.
  • Fotos: pide permiso con catalog.photo_upload, sube cada foto con PUT a su upload_url (jpg, png o webp, hasta 5 MB) y envía los path en photos de catalog.upsert. Las fotos van directo de n8n al almacén de YaCRM; YaCRM nunca descarga enlaces de terceros.
  • Si un SKU ya existe en tu catálogo, no se crea ni se pisa: queda en Inventario → Posibles duplicados para que elijas «Unirlos» o «Son distintos».
  • Con Mercado Libre conectado, el ERP escribe solo si cada cuenta de Mercado Libre tiene encendido «Descontar stock local en Mercado Libre» en Canales; si no, responde catalog_source_conflict_meli.
  • En un producto publicado en Mercado Libre el ERP manda solo la existencia: título, precio y estado siguen siendo los de Mercado Libre, y YaCRM sube la existencia nueva a Mercado Libre. Productos con varias variaciones en Mercado Libre se rechazan (erp_ml_variations_unsupported).
  • Las ventas de Mercado Libre no se restan solas en tu ERP: escucha el aviso order.created en n8n, descuenta en el ERP y vuelve a mandar la existencia con catalog.stock_set.
Pide con cursorProcesa la páginaGuarda sync_cursorRepite
Para leer de YaCRM hacia tu sistema (pedidos, mensajes, clientes) usa order=asc y guarda sync_cursor: nunca se salta ni repite una fila.
catalog.upsert (cURL)
curl -X POST "https://yacrm.pro/api/public/v1/businesses/$BUSINESS_ID/catalog/sources/$SOURCE_ID/products" \
  -H "Authorization: Bearer $YACRM_TOKEN" \
  -H "Idempotency-Key: erp-lote-2026-11-12-001" \
  -H "Content-Type: application/json" \
  -d '{"items":[{"external_id":"ERP-1001","sku":"PF-COR-0812","name":"Pastilla de freno delantera Corolla 2008-2013","description":"Juego de 4","brand":"Bosch","price":25.5,"currency":"USD","stock":12,"status":"active","photos":[{"path":"5d2e8a1c-3b4f-4a6d-8e9f-0a1b2c3d4e5f/7c9e1a3b-5d6f-4b8a-9c0d-1e2f3a4b5c6d/0b6f3c1e-2a4d-4e8f-9b1c-3d5e7f9a1b2c.jpg"}]}]}'

Odoo, Shopify, WooCommerce, Cachicamo y Profit Plus

En todos los casos n8n es el traductor: lee el sistema de origen, convierte cada campo y llama a catalog.upsert. Solo cambian el nodo de lectura y los nombres de campo.

Odoo

n8n tiene nodo Odoo: Schedule Trigger → Odoo (Get All, modelo product.product) → Code arma lotes de 50 → HTTP Request a catalog.upsert.

YaCRMOdoo
external_idid
skudefault_code
namename
pricelist_price
stockqty_available

qty_available es la existencia a mano en Odoo; si vendes por almacén, usa la de tu almacén.

Shopify

Nodo Shopify o HTTP Request a la Admin API GraphQL (productVariants). Shopify marcó su API REST como heredada: para apps nuevas usa GraphQL.

YaCRMShopify
external_idid de la variante
skusku
nametítulo del producto + variante
priceprice
stockinventoryQuantity

Cada variante de Shopify es un producto en YaCRM (un external_id por variante).

WooCommerce

Nodo WooCommerce (Product → Get All) → Code en lotes de 50 → catalog.upsert. Para cambios rápidos: webhook «product.updated» de WooCommerce → catalog.stock_set.

YaCRMWooCommerce
external_idid
skusku
namename
priceprice
stockstock_quantity

stock_quantity solo existe si el producto tiene «Gestionar inventario» activado.

Cachicamo

Cachicamo publica una API REST con webhooks (api.cachicamo.app/docs). En n8n: HTTP Request a su inventario con tu token de Cachicamo → Code → catalog.upsert; o su webhook de inventario → catalog.stock_set.

YaCRMCachicamo
external_idid del producto (UUID)
skucódigo
namenombre
priceprecio
stockexistencia

Toma los nombres exactos de campo de la documentación vigente de Cachicamo.

Profit Plus

Profit Plus suele instalarse en un servidor local. Opciones: su API REST (si tu proveedor la tiene activa), una consulta programada a la base de datos con el nodo SQL de n8n, o un archivo exportado. Luego Code → catalog.upsert.

YaCRMProfit Plus
external_idcódigo del artículo
skucódigo o referencia
namedescripción
priceprecio de venta
stockexistencia actual

Los nombres de tablas y campos dependen de tu versión: confírmalos con tu proveedor de Profit Plus.

Desde ChatGPT o Claude (MCP)

Conecta YaCRM como servidor MCP y pide en tus palabras: «crea una conexión para n8n con todos los permisos», «avísame en este webhook cuando llegue un WhatsApp», «crea la fuente ERP Galpón», «muéstrame los posibles duplicados».

  • Herramientas: manage_api_connections, manage_webhooks, manage_catalog_sources, review_catalog_duplicates y la guía get_api_reference.
  • Cada llamada trabaja sobre una sola tienda; si tu cuenta tiene varias, el asistente te pide cuál.
  • Llaves y firmas se muestran una sola vez y quedan en el historial del chat: puedes rotarlas cuando quieras. Unir duplicados exige tu confirmación explícita.

Próximamente (no disponible todavía)

Lo siguiente está en diseño. No existe aún y no debes construir sobre ello. Se publicará en esta misma página cuando esté probado.

  • Crear clientes y pedidos desde tu ERP, con la misma clave de idempotencia.
  • Fotos de producto por enlace desde tu ERP.

¿Dudas? Revisa el centro de ayuda.