> ## Documentation Index
> Fetch the complete documentation index at: https://docs.triglit.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Guia de Integração

> Exemplos práticos de como integrar o Triglit no seu produto

Este guia mostra exemplos práticos de como integrar o Triglit no seu produto.

## Caso de Uso: Processamento de Pedidos

Vamos criar um workflow que processa pedidos quando são criados.

### 1. Criar o Workflow

<CodeGroup>
  ```javascript JavaScript theme={null}
  import Triglit from 'triglit';

  async function createOrderWorkflow() {
    const client = new Triglit({ apiKey: process.env.TRIGLIT_SECRET_KEY });
    
    const workflow = await client.workflows.create({
      name: 'Processar Pedido',
      description: 'Valida e processa pedidos de clientes'
    });
    
    return workflow;
  }
  ```

  ```python Python theme={null}
  import requests
  import os

  def create_order_workflow():
      headers = {
          'X-API-Key': os.getenv('TRIGLIT_SECRET_KEY'),
          'Content-Type': 'application/json'
      }
      
      data = {
          'name': 'Processar Pedido',
          'description': 'Valida e processa pedidos de clientes'
      }
      
      response = requests.post(
          'https://api.triglit.com/v1/gateway/workflows',
          headers=headers,
          json=data
      )
      
      return response.json()
  ```
</CodeGroup>

### 2. Criar Versão do Workflow

<CodeGroup>
  ```javascript JavaScript theme={null}
  import Triglit from 'triglit';

  async function createWorkflowVersion(workflowId) {
    const client = new Triglit({ apiKey: process.env.TRIGLIT_SECRET_KEY });
    
    const version = await client.workflows.versions.create({
      workflowId,
      nodes: [
        {
          id: 'validate',
          type: 'condition',
          config: {
            condition: 'input.amount > 0 && input.items.length > 0',
            trueBranch: 'process',
            falseBranch: 'reject'
          }
        },
        {
          id: 'process',
          type: 'transform',
          config: {
            transformType: 'expression',
            expression: '{ ...input, status: "processed", processedAt: new Date().toISOString() }'
          }
        },
        {
          id: 'reject',
          type: 'transform',
          config: {
            transformType: 'expression',
            expression: '{ ...input, status: "rejected", reason: "Invalid order" }'
          }
        }
      ],
      edges: [
        { source: 'validate', target: 'process' },
        { source: 'validate', target: 'reject' }
      ]
    });
    
    return version;
  }
  ```
</CodeGroup>

### 3. Publicar Versão

```javascript theme={null}
import Triglit from 'triglit';

async function publishWorkflowVersion(versionId) {
  const client = new Triglit({ apiKey: process.env.TRIGLIT_SECRET_KEY });
  const result = await client.workflows.versions.publish(versionId);
  return result;
}
```

### 4. Criar Trigger Webhook

```javascript theme={null}
import Triglit from 'triglit';

async function createWebhookTrigger(workflowVersionId) {
  const client = new Triglit({ apiKey: process.env.TRIGLIT_SECRET_KEY });
  const trigger = await client.triggers.create({
    workflowVersionId: workflowVersionId,
    type: 'webhook',
    isActive: true
  });
  return trigger;
}
```

### 5. Integrar no Seu Sistema

O webhook trigger funciona como um **trigger de evento**: quando um evento acontece no seu sistema (ex: novo pedido criado), você chama o webhook do Triglit para iniciar o workflow.

**Opção 1: Por ID do Trigger**

Quando você conhece o ID do trigger:

```javascript theme={null}
import Triglit from 'triglit';

// No seu backend, quando um pedido é criado (evento do seu sistema)
async function onOrderCreated(order) {
  const trigger = await getTrigger('orders'); // Busque o trigger do banco
  const client = new Triglit({ apiKey: process.env.TRIGLIT_SECRET_KEY });
  
  // Chama o webhook do Triglit quando o evento acontece
  await client.triggers.triggerWebhook(trigger.id, {
    eventData: {
		orderId: order.id,
		amount: order.amount,
		items: order.items,
		customerId: order.customerId
	}
  });
}
```

**Opção 2: Por Evento (Recomendado)**

Quando você usa eventos nos triggers, pode iniciar workflows sem precisar conhecer IDs:

```javascript theme={null}
import Triglit from 'triglit';

// No seu backend, quando um pedido é criado (evento do seu sistema)
async function onOrderCreated(order) {
  const client = new Triglit({ apiKey: process.env.TRIGLIT_SECRET_KEY });
  
  // Inicia todos os triggers webhook do evento "order.created"
  // Não precisa conhecer IDs de triggers!
  const result = await client.triggers.triggerByEvent({
    event: 'order.created',
    subTenantId: order.subTenantId, // Opcional: filtra por sub-tenant
    eventData: {
      orderId: order.id,
      amount: order.amount,
      items: order.items,
      customerId: order.customerId
    }
  });
  
  console.log(`Iniciados ${result.total} workflows para o pedido ${order.id}`);
}
```

**Vantagens da Opção 2:**

* ✅ Não precisa armazenar IDs de triggers no seu banco
* ✅ Inicia múltiplos workflows automaticamente se houver vários triggers para o mesmo evento
* ✅ Mais simples de manter e escalar
* ✅ Filtra automaticamente por sub-tenant quando necessário

**Opção 3: Endpoint de Ingestion (Recomendado para CRMs e Sistemas de Mensagens)**

O endpoint de ingestion é ideal para casos onde você precisa gerenciar conversas ou interações que podem ter múltiplas mensagens para a mesma entidade (ex: contato, conversa, usuário). Ele automaticamente decide entre retomar execuções pausadas ou iniciar novas, simplificando muito a integração:

```javascript theme={null}
import Triglit from 'triglit';

// No seu backend, quando uma mensagem é recebida
async function onMessageReceived(message) {
  const client = new Triglit({ apiKey: process.env.TRIGLIT_SECRET_KEY });
  
  // O endpoint de ingestion automaticamente:
  // 1. Retoma execuções pausadas para o mesmo entityId e evento (se houver)
  // 2. Inicia novas execuções se não houver pausadas
  const result = await client.triggers.ingest({
    event: 'message.received',
    eventData: {
      entityId: message.conversationId, // ID da conversa/contato
      content: message.content,
      senderId: message.senderId,
      timestamp: message.timestamp
    },
    subTenantId: message.subTenantId, // Opcional
    // Opções opcionais de retomada:
    resumeOptions: {
      resumeAll: true, // Por padrão retoma todas as execuções pausadas
      // runIds: ['run_123'], // Ou especifique IDs específicos
      // workflowVersionIds: ['wfv_456'] // Ou apenas workflows específicos
    }
  });
  
  // Resultado mostra o que foi feito
  console.log(`Retomadas: ${result.resumed.length}`);
  console.log(`Iniciadas: ${result.triggered.length}`);
  console.log(`Ignoradas: ${result.skipped.length}`);
  
  // Exemplo de resposta:
  // {
  //   resumed: [
  //     {
  //       runId: 'run_abc123',
  //       workflowVersionId: 'wfv_xyz789',
  //       entityId: 'conversation_456'
  //     }
  //   ],
  //   triggered: [],
  //   skipped: []
  // }
}
```

**Quando usar o endpoint de ingestion:**

* ✅ CRMs baseados em mensagens (WhatsApp, Telegram, etc.)
* ✅ Sistemas de chat em tempo real
* ✅ Workflows que pausam esperando input do usuário
* ✅ Casos onde múltiplas mensagens do mesmo entityId devem continuar a mesma execução

**Exemplo completo: CRM de Mensagens**

```javascript theme={null}
import Triglit from 'triglit';
import express from 'express';

const app = express();
app.use(express.json());

const client = new Triglit({ apiKey: process.env.TRIGLIT_SECRET_KEY });

// Endpoint do seu CRM para receber mensagens
app.post('/crm/messages', async (req, res) => {
  const { conversationId, content, senderId, metadata } = req.body;
  
  try {
    // Usar endpoint de ingestion - ele decide automaticamente o que fazer
    const result = await client.triggers.ingest({
      event: 'message.received',
      eventData: {
        entityId: conversationId, // ID da conversa (usado para agrupar mensagens)
        content,
        senderId,
        metadata,
        timestamp: new Date().toISOString()
      }
    });
    
    // Se retomou execuções, a mensagem foi enviada para continuar workflows pausados
    if (result.resumed.length > 0) {
      console.log(`Mensagem processada: ${result.resumed.length} execução(ões) retomada(s)`);
    }
    
    // Se iniciou novas execuções, novos workflows foram iniciados
    if (result.triggered.length > 0) {
      console.log(`Novos workflows iniciados: ${result.triggered.length}`);
    }
    
    // Execuções ignoradas (ex: expiradas) aparecem em skipped
    if (result.skipped.length > 0) {
      console.log(`Execuções ignoradas: ${result.skipped.length}`);
      result.skipped.forEach(skip => {
        console.log(`  - ${skip.reason}: ${skip.runId || 'N/A'}`);
      });
    }
    
    res.json({
      success: true,
      resumed: result.resumed.length,
      triggered: result.triggered.length,
      skipped: result.skipped.length
    });
    
  } catch (error) {
    console.error('Erro ao processar mensagem:', error);
    res.status(500).json({
      success: false,
      error: error.message
    });
  }
});

app.listen(3000);
```

**Controlando quais execuções retomar:**

```javascript theme={null}
// Retomar apenas execuções específicas
const result = await client.triggers.ingest({
  event: 'message.received',
  eventData: { entityId: 'conversation_123', content: 'Olá' },
  resumeOptions: {
    resumeAll: false,
    runIds: ['run_abc123', 'run_def456'] // Apenas estes IDs
  }
});

// Retomar apenas de workflows específicos
const result = await client.triggers.ingest({
  event: 'message.received',
  eventData: { entityId: 'conversation_123', content: 'Olá' },
  resumeOptions: {
    workflowVersionIds: ['wfv_xyz789'] // Apenas deste workflow
  }
});

// Não retomar nenhuma (sempre iniciar nova)
const result = await client.triggers.ingest({
  event: 'message.received',
  eventData: { entityId: 'conversation_123', content: 'Olá' },
  resumeOptions: {
    resumeAll: false // Não retoma nenhuma, sempre inicia nova
  }
});
```

**Fluxo típico de um workflow com input:**

1. **Primeira mensagem** → Trigger `message.received` → Workflow inicia → Custom Node envia mensagem → Input Node pausa esperando resposta
2. **Segunda mensagem** → Endpoint de ingestion detecta execução pausada → Retoma automaticamente com a nova mensagem → Workflow continua
3. **Terceira mensagem** → Se ainda houver execução pausada, retoma novamente; caso contrário, inicia nova execução

<Tip>
  O endpoint de ingestion elimina a necessidade de gerenciar estado local de execuções pausadas. O Triglit gerencia tudo internamente, simplificando muito a integração.
</Tip>

## Caso de Uso: Notificações Agendadas

Vamos criar um workflow que envia notificações diárias.

### 1. Workflow com Schedule Trigger

```javascript theme={null}
import Triglit from 'triglit';

async function createNotificationWorkflow() {
  const client = new Triglit({ apiKey: process.env.TRIGLIT_SECRET_KEY });
  
  // Criar workflow
  const workflow = await client.workflows.create({
    name: 'Notificações Diárias',
    description: 'Envia notificações diárias para usuários'
  });

  // Criar versão
  const version = await client.workflows.versions.create({
    workflowId: workflow.id,
    nodes: [
      {
        id: 'fetch-users',
        type: 'custom',
        config: {
          nodeId: 'custom-fetch-users',
          endpoint: 'https://api.seudominio.com/triglit/custom-nodes',
          method: 'POST',
          params: {
            action: 'fetch-active-users'
          }
        }
      },
      {
        id: 'send-notifications',
        type: 'custom',
        config: {
          nodeId: 'custom-send-notifications',
          endpoint: 'https://api.seudominio.com/triglit/custom-nodes',
          method: 'POST',
          params: {
            action: 'send-notifications'
          }
        }
      }
    ],
    edges: [
      { source: 'fetch-users', target: 'send-notifications' }
    ]
  });

  // Publicar versão
  await client.workflows.versions.publish(version.id);

  // Criar trigger schedule
  const trigger = await client.triggers.create({
    workflowVersionId: version.id,
    type: 'schedule',
    config: {
      cron: '0 9 * * *', // Diariamente às 9h
      timezone: 'America/Sao_Paulo'
    },
    isActive: true
  });

  return { workflow, version, trigger };
}
```

## Cliente Reutilizável

Use o SDK oficial do Triglit para facilitar a integração:

<CodeGroup>
  ```javascript JavaScript theme={null}
  import Triglit from 'triglit';

  // Inicializar o cliente uma vez e reutilizar
  const client = new Triglit({ apiKey: process.env.TRIGLIT_SECRET_KEY });

  // Workflows
  const workflow = await client.workflows.create({ name: 'Meu Workflow' });
  const workflows = await client.workflows.list();

  // Workflow Versions
  const version = await client.workflows.versions.create({
    workflowId: 'workflow_id',
    nodes: [],
    edges: []
  });
  await client.workflows.versions.publish(version.id);

  // Triggers
  const trigger = await client.triggers.create({
    workflowVersionId: 'version_id',
    type: 'webhook',
    isActive: true
  });
  const triggers = await client.triggers.list();
  ```

  ```python Python theme={null}
  import requests
  from typing import Optional, Dict, Any

  class TriglitClient:
      def __init__(self, api_key: str):
          self.api_key = api_key
          self.base_url = 'https://api.triglit.com/v1/gateway'
          self.headers = {
              'X-API-Key': api_key,
              'Content-Type': 'application/json'
          }

      def _request(self, method: str, endpoint: str, data: Optional[Dict] = None) -> Dict[str, Any]:
          url = f'{self.base_url}{endpoint}'
          response = requests.request(
              method=method,
              url=url,
              headers=self.headers,
              json=data
          )
          response.raise_for_status()
          return response.json()

      def create_workflow(self, data: Dict[str, Any]) -> Dict[str, Any]:
          return self._request('POST', '/workflows', data)

      def get_workflows(self, params: Optional[Dict] = None) -> Dict[str, Any]:
          query = '&'.join([f'{k}={v}' for k, v in (params or {}).items()])
          endpoint = f'/workflows?{query}' if query else '/workflows'
          return self._request('GET', endpoint)

      def create_workflow_version(self, data: Dict[str, Any]) -> Dict[str, Any]:
          return self._request('POST', '/workflow-versions', data)

      def publish_workflow_version(self, version_id: str) -> Dict[str, Any]:
          return self._request('POST', f'/workflow-versions/{version_id}/publish')

      def create_trigger(self, data: Dict[str, Any]) -> Dict[str, Any]:
          return self._request('POST', '/triggers', data)

  # Uso
  client = TriglitClient(os.getenv('TRIGLIT_SECRET_KEY'))
  workflow = client.create_workflow({'name': 'Meu Workflow'})
  ```
</CodeGroup>

## Tratamento de Erros

Sempre trate erros adequadamente:

```javascript theme={null}
import Triglit from 'triglit';

const client = new Triglit({ apiKey: process.env.TRIGLIT_SECRET_KEY });

async function createWorkflowSafely(data) {
  try {
    const workflow = await client.workflows.create(data);
    return { success: true, data: workflow };
  } catch (error) {
    if (error.statusCode === 429) {
      // Rate limit - retry com backoff
      await sleep(5000);
      return createWorkflowSafely(data);
    }
    
    if (error.statusCode === 401) {
      // Chave inválida
      throw new Error('API key inválida. Verifique suas credenciais.');
    }
    
    return { success: false, error: error.message };
  }
}
```

## Boas Práticas

<AccordionGroup>
  <Accordion title="Variáveis de Ambiente">
    Nunca hardcode chaves de API. Use variáveis de ambiente.
  </Accordion>

  <Accordion title="SDK Oficial">
    Use o SDK oficial do Triglit (`npm install triglit`) para evitar duplicação de código e facilitar a integração.
  </Accordion>

  <Accordion title="Tratamento de Erros">
    Sempre trate erros e implemente retry com backoff exponencial.
  </Accordion>

  <Accordion title="Idempotência">
    Use idempotency keys para operações críticas.
  </Accordion>

  <Accordion title="Monitoramento">
    Monitore chamadas à API e configure alertas para erros.
  </Accordion>
</AccordionGroup>

<Tip>
  Para integrações complexas, considere criar uma camada de abstração que encapsula a lógica de workflows do Triglit.
</Tip>
