Saltar al contenido principal
Un pool de round robin distribuye los leads entrantes entre una lista ordenada de participantes mediante rotación por puntero: cada pool recuerda a quién le toca el siguiente turno, asigna el lead a ese participante y luego avanza el puntero al siguiente (volviendo al primero después del último). El orden de rotación es el orden del arreglo participantIds. Las conexiones enrutan los leads entrantes hacia un pool según su origen — un webhook genérico, una página/formulario/anuncio/campaña de meta, un proveedor de automation (Zapier, Make, n8n) o un workflow. Cuando llega un lead, FlowEstate elige el pool activo cuya conexión coincide con el origen del lead y lo asigna a través de la rotación de ese pool. Cada endpoint en esta página opera dentro del tenant de la organización que llama — no puedes leer ni escribir pools de round robin de otra organización con la misma key.

Listar pools

GET /round-robin
Scope: round-robin:read. Lista los pools de round robin de la organización, del más reciente al más antiguo.

Query parameters

ParámetroTipoNotas
limitnumber1..100, default 50.
offsetnumberDefault 0.
querystringCoincidencia sin distinción de mayúsculas sobre el nombre del pool.
statusenumall (default), active o inactive.

Request

curl "https://panel.flowestate.app/api/v1/round-robin?status=active&limit=20" \
  -H "Authorization: Bearer fe_k_your_key_here"

Response 200

{
  "data": [
    {
      "id": "uuid",
      "organizationId": "uuid",
      "name": "Inbound — Leads de Meta",
      "isActive": true,
      "assignInboundLeads": true,
      "assignManualLeads": false,
      "emailNotificationsEnabled": false,
      "followerUserId": null,
      "goalTotalDeals": null,
      "goalWonDeals": null,
      "nextParticipantOrder": 2,
      "createdBy": "uuid",
      "createdByName": "Ada Lovelace",
      "followerName": null,
      "participantCount": 4,
      "assignmentCount": 128,
      "lastAssignmentAt": "2026-06-22T18:04:15.000Z",
      "createdAt": "2026-04-29T18:04:15.000Z",
      "updatedAt": "2026-06-22T18:04:15.000Z"
    }
  ],
  "pagination": { "total": 3, "limit": 20, "offset": 0, "hasMore": false }
}
nextParticipantOrder es el valor de orden (base 1) del participante que recibirá el siguiente lead. participantCount cuenta solo a los participantes activos.

Crear un pool

POST /round-robin
Scope: round-robin:write

Request body

CampoTipoNotas
namestringRequerido, 1..200 caracteres.
participantIdsstring[]Requerido, al menos un UUID. El orden del arreglo se convierte en el orden de rotación. Cada id debe ser miembro de la organización; sin duplicados.
followerUserIdstringUUID opcional. Un miembro que sigue la actividad del pool. Debe ser miembro de la organización.
goalTotalDealsnumberOpcional, entero ≥ 0.
goalWonDealsnumberOpcional, entero ≥ 0.
isActivebooleanDefault true. Solo los pools activos asignan leads.
assignInboundLeadsbooleanDefault true. Asignar leads que llegan desde conexiones (Meta, webhook, automation, workflow).
assignManualLeadsbooleanDefault false. Asignar leads creados manualmente (source: "manual").
emailNotificationsEnabledbooleanDefault false. Enviar email al participante asignado en cada asignación.
connectionsobject[]Default []. Ver objeto de conexión.

Objeto de conexión

Cada entrada en connections (y el body de POST .../connections) tiene esta forma:
CampoTipoNotas
sourceenumDefault webhook. Uno de RoundRobinConnectionSource: webhook, meta, automation, workflow.
providerenumRoundRobinConnectionProvider: custom, make, n8n, zapier. Requerido cuando source es automation.
sourceKeystringOpcional, 1..200 caracteres. Clave libre para coincidir con un origen personalizado.
metaPageId, metaFormId, metaAdId, metaCampaignIdstringOpcionales, 1..200 caracteres cada uno. Se usan para coincidir con leads de meta.
utmCampaignstringOpcional, 1..200 caracteres.
workflowIdstringOpcional, 1..200 caracteres. Requerido cuando source es workflow.
Solo un pool por organización puede tener la conexión genérica webhook, y la integración de webhook universal de leads de la organización debe estar habilitada. Las conexiones duplicadas (idénticas campo por campo) se rechazan.

Request

curl -X POST https://panel.flowestate.app/api/v1/round-robin \
  -H "Authorization: Bearer fe_k_your_key_here" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "Inbound — Leads de Meta",
    "participantIds": ["uuid-a", "uuid-b", "uuid-c"],
    "assignInboundLeads": true,
    "connections": [
      { "source": "meta", "metaFormId": "1234567890" }
    ]
  }'

Response 201

{
  "id": "uuid",
  "organizationId": "uuid",
  "name": "Inbound — Leads de Meta",
  "isActive": true,
  "assignInboundLeads": true,
  "assignManualLeads": false,
  "emailNotificationsEnabled": false,
  "followerUserId": null,
  "goalTotalDeals": null,
  "goalWonDeals": null,
  "nextParticipantOrder": 1,
  "createdBy": null,
  "createdAt": "2026-06-23T18:04:15.000Z",
  "updatedAt": "2026-06-23T18:04:15.000Z"
}

Errores comunes

  • 400 VALIDATION_ERROR — body inválido (participantIds vacío, conexión de automation sin provider, conexión de workflow sin workflowId, etc.).
  • 400 BAD_REQUEST — un participante o follower no es miembro de la organización, participantes duplicados o conexiones duplicadas.
  • 400 BAD_REQUEST — se solicitó una conexión webhook pero la integración de webhook universal de leads no está habilitada.
  • 409 CONFLICT — la conexión webhook universal ya está asignada a otro pool.

Obtener un pool

GET /round-robin/{roundRobinId}
Scope: round-robin:read. Devuelve el pool con sus participantes ordenados, sus conexiones, un resumen settings y las estadísticas de asignación stats. 404 NOT_FOUND si el pool no existe o pertenece a otra organización.

Response 200

{
  "id": "uuid",
  "organizationId": "uuid",
  "name": "Inbound — Leads de Meta",
  "isActive": true,
  "assignInboundLeads": true,
  "assignManualLeads": false,
  "emailNotificationsEnabled": false,
  "followerUserId": null,
  "goalTotalDeals": null,
  "goalWonDeals": null,
  "nextParticipantOrder": 2,
  "createdBy": "uuid",
  "createdAt": "2026-04-29T18:04:15.000Z",
  "updatedAt": "2026-06-22T18:04:15.000Z",
  "participants": [
    {
      "id": "uuid",
      "roundRobinId": "uuid",
      "organizationId": "uuid",
      "userId": "uuid",
      "order": 1,
      "isActive": true,
      "createdAt": "2026-04-29T18:04:15.000Z",
      "updatedAt": "2026-04-29T18:04:15.000Z",
      "user": {
        "id": "uuid",
        "name": "Ada Lovelace",
        "email": "ada@example.com",
        "image": null
      }
    }
  ],
  "connections": [
    {
      "id": "uuid",
      "roundRobinId": "uuid",
      "organizationId": "uuid",
      "source": "meta",
      "metaPageId": null,
      "metaFormId": "1234567890",
      "metaAdId": null,
      "metaCampaignId": null,
      "provider": null,
      "sourceKey": null,
      "utmCampaign": null,
      "workflowId": null,
      "isActive": true,
      "createdAt": "2026-04-29T18:04:15.000Z",
      "updatedAt": "2026-04-29T18:04:15.000Z"
    }
  ],
  "settings": {
    "id": "uuid",
    "name": "Inbound — Leads de Meta",
    "isActive": true,
    "assignInboundLeads": true,
    "assignManualLeads": false,
    "emailNotificationsEnabled": false,
    "followerUserId": null,
    "goalTotalDeals": null,
    "goalWonDeals": null
  },
  "stats": {
    "totalAssignments": 128,
    "lastAssignmentAt": "2026-06-22T18:04:15.000Z",
    "participantAssignments": [
      { "assignedUserId": "uuid", "assignmentCount": 32, "lastAssignedAt": "2026-06-22T18:04:15.000Z" }
    ]
  }
}
Los participantes se devuelven en orden de rotación (order ascendente).

Actualizar un pool

PATCH /round-robin/{roundRobinId}
Scope: round-robin:write. El body es el de crear pero sin la obligatoriedad de name — todos los campos son opcionales; envía solo lo que quieras cambiar. 404 NOT_FOUND si el pool no existe o pertenece a otra organización.
CampoTipoNotas
namestring1..200 caracteres.
isActivebooleanActivar o desactivar el pool. Los pools desactivados dejan de recibir leads.
participantIdsstring[]Al menos un UUID. Reemplaza toda la lista de participantes; el orden del arreglo se convierte en el nuevo orden de rotación y reinicia el puntero al primer participante.
followerUserIdstring | nullUUID o null para limpiar.
goalTotalDealsnumber | nullEntero ≥ 0 o null.
goalWonDealsnumber | nullEntero ≥ 0 o null.
assignInboundLeadsboolean
assignManualLeadsboolean
emailNotificationsEnabledboolean
connectionsobject[]Reemplaza toda la lista de conexiones. Ver objeto de conexión.

Request

Reordenar la rotación y desactivar el pool:
curl -X PATCH https://panel.flowestate.app/api/v1/round-robin/uuid \
  -H "Authorization: Bearer fe_k_your_key_here" \
  -H "Content-Type: application/json" \
  -d '{
    "isActive": false,
    "participantIds": ["uuid-c", "uuid-a", "uuid-b"]
  }'

Response 200

{ "success": true }

Errores comunes

  • 400 VALIDATION_ERROR / 400 BAD_REQUEST — mismas reglas de validación que crear (membresía, duplicados, requisitos de conexión).
  • 409 CONFLICT — la conexión webhook universal ya pertenece a otro pool.

Eliminar un pool

DELETE /round-robin/{roundRobinId}
Scope: round-robin:write. Elimina el pool junto con sus participantes, conexiones e historial de asignaciones. 404 NOT_FOUND si el pool no existe o pertenece a otra organización.

Response 200

{ "deleted": true, "id": "uuid" }

Agregar una conexión

POST /round-robin/{roundRobinId}/connections
Scope: round-robin:write. Agrega una única conexión de enrutamiento a un pool existente. El body es el objeto de conexión. 404 NOT_FOUND si el pool no existe o pertenece a otra organización.

Request

curl -X POST https://panel.flowestate.app/api/v1/round-robin/uuid/connections \
  -H "Authorization: Bearer fe_k_your_key_here" \
  -H "Content-Type: application/json" \
  -d '{
    "connection": {
      "source": "automation",
      "provider": "zapier",
      "sourceKey": "q3-launch"
    }
  }'

Response 201

{
  "id": "uuid",
  "roundRobinId": "uuid",
  "organizationId": "uuid",
  "source": "automation",
  "metaPageId": null,
  "metaFormId": null,
  "metaAdId": null,
  "metaCampaignId": null,
  "provider": "zapier",
  "sourceKey": "q3-launch",
  "utmCampaign": null,
  "workflowId": null,
  "isActive": true,
  "createdAt": "2026-06-23T18:04:15.000Z",
  "updatedAt": "2026-06-23T18:04:15.000Z"
}

Errores comunes

  • 400 VALIDATION_ERROR — conexión de automation sin provider, o conexión de workflow sin workflowId.
  • 400 BAD_REQUEST — se solicitó una conexión webhook pero la integración de webhook universal de leads no está habilitada.
  • 409 CONFLICT — ya existe una conexión idéntica en este pool, o la conexión webhook universal pertenece a otro pool.

Eliminar una conexión

DELETE /round-robin/{roundRobinId}/connections/{connectionId}
Scope: round-robin:write. 404 NOT_FOUND si la conexión no existe en ese pool o pertenece a otra organización.

Response 200

{ "deleted": true, "id": "uuid" }

Listar asignaciones

GET /round-robin/{roundRobinId}/assignments
Scope: round-robin:read. Lista el historial de asignaciones del pool, de la más reciente a la más antigua.

Query parameters

ParámetroTipoNotas
limitnumber1..100, default 50.
offsetnumberDefault 0.
sourceenumOpcional. Filtrar por RoundRobinAssignmentSource: manual, meta, webhook, whatsapp, system.

Response 200

{
  "data": [
    {
      "id": "uuid",
      "leadId": "uuid",
      "assignedUserId": "uuid",
      "source": "meta",
      "turnOrder": 2,
      "metadata": "{\"match\":{\"fallbackType\":\"meta_form\",\"connectionId\":\"uuid\"}}",
      "createdAt": "2026-06-22T18:04:15.000Z",
      "userName": "Ada Lovelace",
      "userEmail": "ada@example.com"
    }
  ],
  "pagination": { "total": 128, "limit": 50, "offset": 0, "hasMore": true }
}
turnOrder es el valor de orden del participante al momento de la asignación. metadata es una cadena codificada en JSON (o null) que describe cómo el lead coincidió con una conexión.

Asignar un lead

POST /round-robin/assign
Scope: round-robin:write. Pasa un lead por la rotación por puntero del pool activo que coincide, lo asigna al siguiente participante elegible y avanza el puntero.

Request body

CampoTipoNotas
leadIdstringUUID requerido. El lead debe pertenecer a tu organización.
sourceenumDefault system. Uno de RoundRobinAssignmentSource: manual, meta, webhook, whatsapp, system. Un origen manual se enruta por pools con assignManualLeads habilitado; el resto de los orígenes se enrutan por pools con assignInboundLeads habilitado.

Request

curl -X POST https://panel.flowestate.app/api/v1/round-robin/assign \
  -H "Authorization: Bearer fe_k_your_key_here" \
  -H "Content-Type: application/json" \
  -d '{ "leadId": "uuid", "source": "system" }'

Response 200

Cuando se asigna un participante:
{
  "assigned": true,
  "roundRobinId": "uuid",
  "assignedToId": "uuid",
  "turnOrder": 2
}
Cuando no ocurre ninguna asignación — ningún pool activo coincide con el origen, el pool encontrado no tiene participantes elegibles, o el lead ya tiene un responsable asignado — la respuesta es:
{ "assigned": false }
El lead solo se asigna si actualmente no tiene responsable. Un lead que ya tiene dueño devuelve { "assigned": false } y queda intacto.

Errores comunes

  • 400 VALIDATION_ERRORleadId no es un UUID, o source no es un valor conocido.
  • 404 NOT_FOUND — el lead no existe o pertenece a otra organización.