ZippyVendas fornece uma API externa abrangente para consultar registros de execução de workflows e configurar webhooks para notificações em tempo real quando workflows são completados.
Autenticação
Todas as requisições de API requerem uma chave de API passada no header x-api-key:
curl -H "x-api-key: YOUR_API_KEY" \
https://zippyvendas.com/api/v1/logs?workspaceId=YOUR_WORKSPACE_IDVocê pode gerar chaves de API nas suas configurações de usuário no dashboard do ZippyVendas.
API de Logs
Todas as respostas da API incluem informações sobre seus limites de execução de workflow e uso:
"limits": {
"workflowExecutionRateLimit": {
"sync": {
"limit": 60, // Max de execuções de workflow sincronos por minuto
"remaining": 58, // Execuções de workflow síncronos restantes
"resetAt": "..." // Quando a janela é resetada
},
"async": {
"limit": 60, // Max de execuções de workflow assincronos por minuto
"remaining": 59, // Execuções de workflow assincronos restantes
"resetAt": "..." // Quando a janela é resetada
}
},
"usage": {
"currentPeriodCost": 1.234, // Uso do período de faturamento atual em USD
"limit": 10, // Limite de uso em USD
"plan": "pro", // Plano de assinatura atual
"isExceeded": false // Se o limite foi excedido
}
}Nota: Os limites de taxa no corpo da resposta são para execuções de workflow. Os limites de taxa para chamar este endpoint de API estão nos headers da resposta (X-RateLimit-*).
Consultar Logs
Consulte registros de execução de workflows com opções extensivas de filtros.
GET /api/v1/logsParâmetros Obrigatórios:
workspaceId- Seu ID de workspace
Filtros Opcionais:
workflowIds- IDs de workflow separados por vírgulafolderIds- IDs de pasta separados por vírgulatriggers- Tipos de trigger separados por vírgula:api,webhook,schedule,manual,chatlevel- Filtrar por nível:info,errorstartDate- Timestamp ISO para início do intervalo de datasendDate- Timestamp ISO para fim do intervalo de datasexecutionId- Correspondência exata de ID de execuçãominDurationMs- Duração mínima de execução em milissegundosmaxDurationMs- Duração máxima de execução em milissegundosminCost- Custo mínimo de execuçãomaxCost- Custo máximo de execuçãomodel- Filtrar por modelo de IA usado
Paginação:
limit- Resultados por página (padrão: 100)cursor- Cursor para próxima páginaorder- Ordem de classificação:desc,asc(padrão: desc)
Nível de Detalhe:
details- Nível de detalhe da resposta:basic,full(padrão: basic)includeTraceSpans- Incluir trace spans (padrão: false)includeFinalOutput- Incluir saída final (padrão: false)
{
"data": [
{
"id": "log_abc123",
"workflowId": "wf_xyz789",
"executionId": "exec_def456",
"level": "info",
"trigger": "api",
"startedAt": "2025-01-01T12:34:56.789Z",
"endedAt": "2025-01-01T12:34:57.123Z",
"totalDurationMs": 334,
"cost": {
"total": 0.00234
},
"files": null
}
],
"nextCursor": "eyJzIjoiMjAyNS0wMS0wMVQxMjozNDo1Ni43ODlaIiwiaWQiOiJsb2dfYWJjMTIzIn0",
"limits": {
"workflowExecutionRateLimit": {
"sync": {
"limit": 60,
"remaining": 58,
"resetAt": "2025-01-01T12:35:56.789Z"
},
"async": {
"limit": 60,
"remaining": 59,
"resetAt": "2025-01-01T12:35:56.789Z"
}
},
"usage": {
"currentPeriodCost": 1.234,
"limit": 10,
"plan": "pro",
"isExceeded": false
}
}
}Obter Detalhes de Log
Recupere informações detalhadas sobre uma entrada de log específica.
GET /api/v1/logs/{id}{
"data": {
"id": "log_abc123",
"workflowId": "wf_xyz789",
"executionId": "exec_def456",
"level": "info",
"trigger": "api",
"startedAt": "2025-01-01T12:34:56.789Z",
"endedAt": "2025-01-01T12:34:57.123Z",
"totalDurationMs": 334,
"workflow": {
"id": "wf_xyz789",
"name": "My Workflow",
"description": "Process customer data"
},
"executionData": {
"traceSpans": [...],
"finalOutput": {...}
},
"cost": {
"total": 0.00234,
"tokens": {
"prompt": 123,
"completion": 456,
"total": 579
},
"models": {
"gpt-4o": {
"input": 0.001,
"output": 0.00134,
"total": 0.00234,
"tokens": {
"prompt": 123,
"completion": 456,
"total": 579
}
}
}
},
"limits": {
"workflowExecutionRateLimit": {
"sync": {
"limit": 60,
"remaining": 58,
"resetAt": "2025-01-01T12:35:56.789Z"
},
"async": {
"limit": 60,
"remaining": 59,
"resetAt": "2025-01-01T12:35:56.789Z"
}
},
"usage": {
"currentPeriodCost": 1.234,
"limit": 10,
"plan": "pro",
"isExceeded": false
}
}
}
}Obter Detalhes de Execução
Recupere detalhes de execução, incluindo um snapshot do estado do workflow.
GET /api/v1/logs/executions/{executionId}{
"executionId": "exec_def456",
"workflowId": "wf_xyz789",
"workflowState": {
"blocks": {...},
"edges": [...],
"loops": {...},
"parallels": {...}
},
"executionMetadata": {
"trigger": "api",
"startedAt": "2025-01-01T12:34:56.789Z",
"endedAt": "2025-01-01T12:34:57.123Z",
"totalDurationMs": 334,
"cost": {...}
}
}Notificações
Receba notificações em tempo real quando execuções de workflow são completadas via webhook, e-mail ou Slack. As notificações são configuradas no nível do workspace a partir da página de Logs.
Configuração
Configure notificações a partir da página de Logs clicando no botão de menu e selecionando "Configurar Notificações".
Canais de Notificação:
- Webhook: Enviar requisições HTTP POST para seu endpoint
- E-mail: Receber notificações por e-mail com detalhes de execução
- Slack: Postar mensagens em um canal Slack
Seleção de Workflow:
- Selecionar workflows específicos para monitorar
- Ou escolher "Todos os Workflows" para incluir workflows atuais e futuros
Opções de Filtro:
levelFilter: Níveis de log a receber (info,error)triggerFilter: Tipos de trigger a receber (api,webhook,schedule,manual,chat)
Dados Opcionais:
includeFinalOutput: Incluir a saída final do workflowincludeTraceSpans: Incluir trace spans detalhados de execuçãoincludeRateLimits: Incluir informações de limite de taxa (limites síncronos/assincronos e restantes)includeUsageData: Incluir uso do período de faturamento e limites
Regras de Alerta
Em vez de receber notificações para cada execução, configure regras de alerta para ser notificado apenas quando problemas são detectados:
Falhas Consecutivas
- Alerta após X execuções falhadas consecutivas (ex: 3 falhas seguidas)
- Reseta quando uma execução sucede
Taxa de Falha
- Alerta quando a taxa de falha excede X% nas últimas Y horas
- Requer mínimo de 5 execuções na janela
- Só dispara após a janela de tempo completa ter transcorrido
Limite de Latência
- Alerta quando qualquer execução leva mais de X segundos
- Útil para detectar workflows lentos ou travados
Pico de Latência
- Alerta quando execução é X% mais lenta que a média
- Compara contra a duração média durante a janela de tempo configurada
- Requer mínimo de 5 execuções para estabelecer baseline
Limite de Custo
- Alerta quando uma execução única custa mais de $X
- Útil para detectar chamadas de LLM caras
Sem Atividade
- Alerta quando nenhuma execução ocorre em X horas
- Útil para monitorar workflows agendados que devem rodar regularmente
Contagem de Erros
- Alerta quando contagem de erros excede X dentro de uma janela de tempo
- Rastreia erros totais, não consecutivos
Todos os tipos de alerta incluem um cooldown de 1 hora para prevenir spam de notificações.
Configuração de Webhook
Para webhooks, opções adicionais estão disponíveis:
url: URL do seu endpoint de webhooksecret: Secret opcional para verificação de assinatura HMAC
Estrutura de Payload
Quando uma execução de workflow é completada, ZippyVendas envia o seguinte payload (via webhook POST, e-mail ou Slack):
{
"id": "evt_123",
"type": "workflow.execution.completed",
"timestamp": 1735925767890,
"data": {
"workflowId": "wf_xyz789",
"executionId": "exec_def456",
"status": "success",
"level": "info",
"trigger": "api",
"startedAt": "2025-01-01T12:34:56.789Z",
"endedAt": "2025-01-01T12:34:57.123Z",
"totalDurationMs": 334,
"cost": {
"total": 0.00234,
"tokens": {
"prompt": 123,
"completion": 456,
"total": 579
},
"models": {
"gpt-4o": {
"input": 0.001,
"output": 0.00134,
"total": 0.00234,
"tokens": {
"prompt": 123,
"completion": 456,
"total": 579
}
}
}
},
"files": null,
"finalOutput": {...}, // Only if includeFinalOutput=true
"traceSpans": [...], // Only if includeTraceSpans=true
"rateLimits": {...}, // Only if includeRateLimits=true
"usage": {...} // Only if includeUsageData=true
},
"links": {
"log": "/v1/logs/log_abc123",
"execution": "/v1/logs/executions/exec_def456"
}
}Headers de Webhook
Cada requisição de webhook inclui estes headers (apenas para canal webhook):
sim-event: Tipo de evento (sempreworkflow.execution.completed)sim-timestamp: Timestamp Unix em milissegundossim-delivery-id: ID de entrega único para idempotênciasim-signature: Assinatura HMAC-SHA256 para verificação (se secret configurado)Idempotency-Key: Igual ao ID de entrega para detecção de duplicatas
Verificação de Assinatura
Se você configurar um secret de webhook, verifique a assinatura para garantir que o webhook é do ZippyVendas:
import crypto from 'crypto';
function verifyWebhookSignature(body, signature, secret) {
const [timestampPart, signaturePart] = signature.split(',');
const timestamp = timestampPart.replace('t=', '');
const expectedSignature = signaturePart.replace('v1=', '');
const signatureBase = `${timestamp}.${body}`;
const hmac = crypto.createHmac('sha256', secret);
hmac.update(signatureBase);
const computedSignature = hmac.digest('hex');
return computedSignature === expectedSignature;
}
// In your webhook handler
app.post('/webhook', (req, res) => {
const signature = req.headers['sim-signature'];
const body = JSON.stringify(req.body);
if (!verifyWebhookSignature(body, signature, process.env.WEBHOOK_SECRET)) {
return res.status(401).send('Invalid signature');
}
// Process the webhook...
});import hmac
import hashlib
import json
def verify_webhook_signature(body: str, signature: str, secret: str) -> bool:
timestamp_part, signature_part = signature.split(',')
timestamp = timestamp_part.replace('t=', '')
expected_signature = signature_part.replace('v1=', '')
signature_base = f"{timestamp}.{body}"
computed_signature = hmac.new(
secret.encode(),
signature_base.encode(),
hashlib.sha256
).hexdigest()
return hmac.compare_digest(computed_signature, expected_signature)
# In your webhook handler
@app.route('/webhook', methods=['POST'])
def webhook():
signature = request.headers.get('sim-signature')
body = json.dumps(request.json)
if not verify_webhook_signature(body, signature, os.environ['WEBHOOK_SECRET']):
return 'Invalid signature', 401
# Process the webhook...Política de Retry
Entregas de webhook falhadas são retentadas com backoff exponencial e jitter:
- Máximo de tentativas: 5
- Atrasos de retry: 5 segundos, 15 segundos, 1 minuto, 3 minutos, 10 minutos
- Jitter: Até 10% de atraso adicional para prevenir thundering herd
- Apenas respostas HTTP 5xx e 429 disparam retries
- Entregas expiram após 30 segundos
Entregas de webhook são processadas assincronamente e não afetam o desempenho de execução do workflow.
Melhores Práticas
-
Estratégia de Polling: Ao fazer polling para logs, use paginação baseada em cursor com
order=ascestartDatepara buscar novos logs eficientemente. -
Segurança de Webhook: Sempre configure um secret de webhook e verifique assinaturas para garantir que requisições são do ZippyVendas.
-
Idempotência: Use o header
Idempotency-Keypara detectar e lidar com entregas duplicadas de webhook. -
Privacidade: Por padrão,
finalOutputetraceSpanssão excluídos das respostas. Apenas habilite estes se você precisa dos dados e entende as implicações de privacidade. -
Rate Limiting: Implemente backoff exponencial quando você receber respostas 429. Verifique o header
Retry-Afterpara o tempo de espera recomendado.
Limite de Taxa
A API implementa limite de taxa para garantir uso justo:
- Plano Free: 10 requisições por minuto
- Plano Pro: 30 requisições por minuto
- Plano Team: 60 requisições por minuto
- Plano Enterprise: Limites customizados
Informações de limite de taxa estão incluídas nos headers de resposta:
X-RateLimit-Limit: Máximo de requisições por janelaX-RateLimit-Remaining: Requisições restantes na janela atualX-RateLimit-Reset: Timestamp ISO quando a janela reseta
Exemplo: Polling para Novos Logs
let cursor = null;
const workspaceId = 'YOUR_WORKSPACE_ID';
const startDate = new Date().toISOString();
async function pollLogs() {
const params = new URLSearchParams({
workspaceId,
startDate,
order: 'asc',
limit: '100'
});
if (cursor) {
params.append('cursor', cursor);
}
const response = await fetch(
`https://zippyvendas.com/api/v1/logs?${params}`,
{
headers: {
'x-api-key': 'YOUR_API_KEY'
}
}
);
if (response.ok) {
const data = await response.json();
// Process new logs
for (const log of data.data) {
console.log(`New execution: ${log.executionId}`);
}
// Update cursor for next poll
if (data.nextCursor) {
cursor = data.nextCursor;
}
}
}
// Poll every 30 seconds
setInterval(pollLogs, 30000);Exemplo: Processando Webhooks
import express from 'express';
import crypto from 'crypto';
const app = express();
app.use(express.json());
app.post('/sim-webhook', (req, res) => {
// Verify signature
const signature = req.headers['sim-signature'];
const body = JSON.stringify(req.body);
if (!verifyWebhookSignature(body, signature, process.env.WEBHOOK_SECRET)) {
return res.status(401).send('Invalid signature');
}
// Check timestamp to prevent replay attacks
const timestamp = parseInt(req.headers['sim-timestamp']);
const fiveMinutesAgo = Date.now() - (5 * 60 * 1000);
if (timestamp < fiveMinutesAgo) {
return res.status(401).send('Timestamp too old');
}
// Process the webhook
const event = req.body;
switch (event.type) {
case 'workflow.execution.completed':
const { workflowId, executionId, status, cost } = event.data;
if (status === 'error') {
console.error(`Workflow ${workflowId} failed: ${executionId}`);
// Handle error...
} else {
console.log(`Workflow ${workflowId} completed: ${executionId}`);
console.log(`Cost: $${cost.total}`);
// Process successful execution...
}
break;
}
// Return 200 to acknowledge receipt
res.status(200).send('OK');
});
app.listen(3000, () => {
console.log('Webhook server listening on port 3000');
});