Para desarrolladores

Integrá tu API con Dale

Un paquete npm y tus usuarios van a poder usar tu producto desde WhatsApp — con seguridad, aprobaciones y auditoría incluidas.

¿Qué es un plugin de Dale?

Un plugin es un paquete npm que le enseña a Dale a hablar con tu API. Tiene dos partes: un conector (habla con tu API) y un pack (define qué puede hacer el usuario). Dale se encarga del resto: WhatsApp, aprobaciones, seguridad y auditoría.

Arquitectura

┌─────────────────────────────────────────┐
│           tu-empresa-dale-plugin        │  ← UN paquete npm
│                                         │
│  ┌──────────────┐  ┌─────────────────┐  │
│  │  Connector   │  │      Pack       │  │
│  │  (HTTP a     │  │ (flujo + params │  │
│  │   tu API)    │  │  + keywords)    │  │
│  └──────────────┘  └─────────────────┘  │
│                                         │
│  export installMiPlugin(ctx) → {}       │  ← UNA función pública
└─────────────────────────────────────────┘
         │
         │ installMiPlugin({ connectors, packs })
         ▼
┌─────────────────────────────────────────┐
│            Dale Core OS                 │
│  ✓ Brain (IA) — extrae params del chat  │
│  ✓ HITL — aprobaciones humanas          │
│  ✓ Vault — credenciales encriptadas     │
│  ✓ Evidence — ledger de auditoría       │
│  ✓ WhatsApp — canal listo para usar     │
└─────────────────────────────────────────┘
         │
         │ HTTP call en runtime
         ▼
┌─────────────────────────────────────────┐
│         TU API (tus servidores)         │
│  Tu lógica · Tu data · Tu control      │
└─────────────────────────────────────────┘

Tu API corre en tus servidores. Dale solo la llama. Tu infraestructura, tu data, tu control.

Conceptos clave

Conector

Habla con tu API. Define las acciones disponibles (crear reserva, consultar saldo, etc). Recibe credenciales del vault de Dale, nunca maneja secretos directamente.

Pack

Define el flujo conversacional. Qué frases lo activan, qué pasos sigue, y cuáles necesitan aprobación del usuario.

ParamSchema

Declarás qué datos necesita cada acción. Dale los extrae del mensaje del usuario automáticamente y pregunta lo que falte.

Seguridad incluida

Dale maneja las credenciales encriptadas, pide aprobación para acciones sensibles, y registra todo en un ledger de auditoría. Tu plugin no toca nada de eso.

Crear un plugin en 5 pasos

1

Definí tus acciones

¿Qué puede hacer tu API? Listá las acciones (ej: 'crearReserva', 'consultarEstado'). Cada acción recibe parámetros y devuelve un resultado.

2

Armá el conector

Creá una clase que implemente DaleConnectorAdapter. Un switch por acción, llamás a tu API, devolvés el resultado normalizado.

3

Declará los parámetros

Usá paramsSchema para decirle a Dale qué datos necesita cada acción. Dale los extrae del mensaje o se los pregunta al usuario.

4

Armá el pack

Definí el grafo (flujo de pasos), las frases que lo activan, y qué acciones necesitan aprobación humana (policy: 'confirm').

5

Publicá en npm

Exportá una función installTuPlugin(ctx) y publicá. Los operadores lo instalan desde el dashboard.

Paso 1 — El conector

El conector habla con tu API. Implementa DaleConnectorAdapter con un execute() que rutea por acción.

import type {
  DaleConnectorAdapter,
  ConnectorCapability,
  ConnectorCallRequest,
  ConnectorCallResponse,
} from '@dale/core-types';

const BASE_URL = 'https://api.tu-servicio.com/v1';

export class MiConnector implements DaleConnectorAdapter {
  readonly capability: ConnectorCapability = {
    connectorId: 'mi-saas',
    supportedActions: ['listar', 'crear', 'cancelar'],
    requiresApproval: false,
  };

  async execute(request: ConnectorCallRequest): Promise<ConnectorCallResponse> {
    const token = request.resolvedCredential
      ? new TextDecoder().decode(request.resolvedCredential)
      : undefined;

    try {
      switch (request.action) {
        case 'listar': {
          const res = await fetch(`${BASE_URL}/items`, {
            headers: token ? { Authorization: `Bearer ${token}` } : {},
          });
          if (!res.ok) return { success: false, errorCode: 'api_error' };
          const data = await res.json();
          return { success: true, data: { items: data.items } };
        }

        case 'crear': {
          const res = await fetch(`${BASE_URL}/items`, {
            method: 'POST',
            headers: {
              'Content-Type': 'application/json',
              ...(token ? { Authorization: `Bearer ${token}` } : {}),
            },
            body: JSON.stringify(request.params),
          });
          if (!res.ok) return { success: false, errorCode: 'create_failed' };
          const created = await res.json();
          return { success: true, data: { id: created.id }, externalRef: created.id };
        }

        default:
          return { success: false, errorCode: 'action_not_supported' };
      }
    } catch (err) {
      return { success: false, errorCode: 'network_error',
        errorMessage: err instanceof Error ? err.message : 'Error de conexión' };
    }
  }
}
  • Credenciales llegan en request.resolvedCredential — decodealas con new TextDecoder().decode(bytes)
  • errorMessage nunca debe contener tokens ni secretos
  • Capturá excepciones de red — nunca hagas throw
  • externalRef debe ser el ID del recurso en tu sistema (para auditoría)

Paso 2 — Declarar parámetros

Con paramsSchema le decís a Dale qué datos necesita cada acción. Dale los extrae del mensaje automáticamente.

{
  id: 'crear-entidad',
  type: 'action',
  policy: 'confirm',
  connectorId: 'mi-saas',
  connectorAction: 'crear',
  paramsSchema: {
    name:    { type: 'string', required: true,  description: 'Nombre', example: 'Acme SA' },
    country: { type: 'string', required: true,  description: 'País', example: 'Argentina' },
    tax_id:  { type: 'string', required: false, description: 'CUIT/CUIL', example: '30-71234567-8' },
    plan:    { type: 'enum',   required: true,  description: 'Plan',
               enumValues: ['starter', 'pro', 'enterprise'], example: 'pro' },
  },
}

Tipos de parámetros

TipoDescripciónEjemplo
stringTexto libreNombre, email
numberValor numéricoMonto, cantidad
booleanSí o noActivo, confirmado
enumUno de un set fijoEstado, categoría, país

Paso 3 — El pack

El pack define el flujo conversacional: qué frases lo activan, qué pasos sigue, y cuáles necesitan aprobación.

import type { DalePackManifest, Graph } from '@dale/core-types';

const mainGraph: Graph = {
  id: 'mi-saas/crear-v1',
  version: '1.0',
  nodes: [
    { id: 'start', type: 'start', policy: 'auto' },
    {
      id: 'crear-entidad',
      type: 'action',
      policy: 'confirm',                 // pausa para aprobación
      label: 'Crear entidad en Mi SaaS',
      connectorId: 'mi-saas',
      connectorAction: 'crear',
      paramsSchema: {
        name:    { type: 'string', required: true,  description: 'Nombre', example: 'Acme SA' },
        country: { type: 'string', required: true,  description: 'País', example: 'Argentina' },
      },
    },
    { id: 'end', type: 'end', policy: 'auto' },
  ],
  edges: [
    { from: 'start', to: 'crear-entidad' },
    { from: 'crear-entidad', to: 'end' },
  ],
};

export const miPack: DalePackManifest = {
  id: 'mi-saas',
  name: 'Mi SaaS Pack',
  version: '1.0.0',
  intents: [
    { id: 'crear_entidad', keywords: ['crear entidad', 'nueva entidad'], graphId: 'mi-saas/crear-v1' },
  ],
  graphs: [mainGraph],
};

Política por nodo

PolicyQué pasaCuándo usar
autoDale ejecuta sin pararConsultas, búsquedas, lecturas
confirmDale pausa y pide aprobaciónCrear, modificar, pagar, eliminar

Paso 4 — La función de instalación

Exportá una función que registra todo. Dale la llama al instalar tu plugin.

import type { DalePluginContext, DalePluginInstaller } from '@dale/core-types';
import { MiConnector } from './connector';
import { miPack } from './pack';

export const installMiPlugin: DalePluginInstaller = (ctx: DalePluginContext) => {
  ctx.connectors.register(new MiConnector());
  ctx.packs.register(miPack);

  return {
    pluginId: 'mi-saas-plugin',
    name: 'Mi SaaS Plugin',
    version: '1.0.0',
    connectors: ['mi-saas'],
    packs: ['mi-saas'],
    docsUrl: 'https://docs.tu-servicio.com',
  };
};

Estructura del paquete

mi-saas-dale-plugin/
├── src/
│   ├── connector.ts      ← implementa DaleConnectorAdapter
│   ├── pack.ts           ← define Graph + PackManifest + paramsSchema
│   └── index.ts          ← exporta la función de instalación
├── tests/
│   ├── connector.test.ts
│   └── install.test.ts
├── package.json
└── tsconfig.json

Qué te da Dale sin costo adicional

Canal WhatsApp listo para usar
Extracción automática de parámetros (IA)
Slot-filling conversacional
Aprobaciones humanas (HITL)
Vault de credenciales encriptado
Ledger de auditoría inmutable
Idempotencia y deduplicación
Multi-workspace y multi-usuario
Dashboard de operador
Retry y manejo de errores

Reglas de seguridad

  • Las credenciales llegan en request.resolvedCredential — nunca las hardcodees
  • errorMessage nunca debe contener tokens, claves o secretos
  • Todas las acciones en supportedActions deben estar en el switch
  • Siempre incluí un caso default retornando action_not_supported
  • Capturá todas las excepciones de red — nunca hagas throw, retorná { success: false }
  • Todo nodo que modifica estado o mueve plata debe ser policy: "confirm"

¿Tenés una API?

Dale le da superpoderes a tu producto. Tus usuarios van a poder usarlo desde WhatsApp, con seguridad, aprobaciones y auditoría incluidas. Todo con un paquete npm.

Escribinos →