Construir un conector

Guía técnica para integradores: cómo construir desde cero un conector que traiga datos externos al ecosistema y los deje disponibles en las fichas y en el bot.

Un conector es cualquier integración que trae datos de un sistema externo (MercadoPago, TiendaNube, Google Analytics, un banco, un broker) al ecosistema del usuario. Este artículo es para developers e integradores. Si sos usuario y solo querés conectar tus sistemas, mirá el artículo de usuario.

Antes de escribir código

Definí estas cuatro cosas antes de tocar el editor:

  • Tipo. Los tipos soportados son rest_api, mcp y webhook. La mayoría son REST vía OAuth2 o API key. Email Ingest ya está implementado aparte (/api/ingest/).
  • Scope. Todo conector tiene un scope: profile, entity o ambos. Se declara en connector_field_map, junto con si propagates_to_children. Las credenciales nunca cruzan scopes: si el conector es de scope entity, sus credenciales solo se usan dentro de esa entidad, y RLS lo refuerza.
  • Mapa de campos. Definí exactamente qué campos alimenta el conector en connector_field_map antes de escribir una línea. Se seedea en la migración.
  • Audit. Cada conexión y desconexión se registra en connector_scope_audit. El conector tiene que llamar a esa función al conectar y al desconectar.

Los pasos

  1. Migración de la tabla. Creá la tabla de credenciales del conector con RLS activado (política por profile_id = auth.uid()). Guardá estado de sync (sync_status con CHECK pendiente | sincronizando | ok | error), ultima_sync y metadata. Poblá connector_field_map en la misma migración.
  2. Autenticación. Implementá OAuth2 (una ruta que redirige a la autorización externa + un callback que intercambia el code por token) o API key. Antes de guardar, encriptá el token: AES-256-GCM con encrypt/decrypt de @/lib/encryption, guardando credentials_enc, credentials_iv y credentials_tag. Nunca en texto plano, nunca en el frontend.
  3. Sincronización. En la ruta de sync: checkRateLimit de @/lib/rate-limit antes de cada llamada externa, desencriptá el token, llamá a la API y guardá cada registro en connector_snapshots con external_id (ID en el sistema externo) y connector_source (slug del conector), con onConflict para idempotencia. Los snapshots son diarios, con UNIQUE (connector_id, snapshot_date). Al terminar, actualizá sync_status. Dejá un fallback graceful si la API externa no responde.
  4. Field contributions. Los datos que alimentan las fichas no se escriben directo a las tablas de dominio: van a field_contributions con source_type = 'connector', source_id = slug del conector, y scope_level / scope_id correctos. Al instalar el conector, la auto-conexión crea estas contribuciones automáticamente.
  5. Tools del bot. Registrá las tools del conector en connector_tools (nombre, descripción, endpoint_url, auth_type, category, required_entity_types) con onConflict('connector_name,name'). El bot carga las tools activas del usuario en cada sesión, así puede responder sobre los datos del conector.
  6. UI y catálogo. El conector aparece en el catálogo de /dashboard/conectores y en Configuración → Conectores vía ConnectorCard. Cambiá su status en connector_catalog de coming_soon a available para que la card muestre el botón "Conectar".

Catálogo y waitlist

El catálogo vive en connector_catalog (slug, name, description, category, status, icon, waitlist_count). Mientras un conector no existe, los usuarios votan demanda con "Lo necesito": cada voto es una fila en connector_waitlist (profile_id + connector_id UNIQUE) y un trigger actualiza waitlist_count. Endpoints reales:

  • GET /api/connectors/catalog — catálogo agrupado por categoría, con user_in_waitlist.
  • POST /api/connectors/waitlist — toggle de voto (INSERT/DELETE).

Estados posibles: available, coming_soon, connected.

Checklist de cierre

Tabla con RLS · credenciales encriptadas · OAuth2/API key · rate limiting antes de cada llamada externa · fallback graceful · datos con external_id y connector_source · tools en connector_tools · UI en Configuración → Conectores · variables de entorno en .env.example · tests de integración en src/__tests__/integration/ · connector_field_map seedeado · auto-conexión crea las field_contributions · connector_scope_audit registra la conexión.

El razonamiento de scopes y fuentes está en DEC-010 y DEC-011.