Sim proporciona una API externa completa para consultar registros de ejecución de flujos de trabajo y configurar webhooks para notificaciones en tiempo real cuando los flujos de trabajo se completan.
Autenticación
Todas las solicitudes a la API requieren una clave de API pasada en el encabezado x-api-key:
curl -H "x-api-key: YOUR_API_KEY" \
https://sim.ai/api/v1/logs?workspaceId=YOUR_WORKSPACE_IDPuedes generar claves de API desde la configuración de usuario en el panel de control de Sim.
API de registros
Todas las respuestas de la API incluyen información sobre tus límites de ejecución de flujos de trabajo y su uso:
"limits": {
"workflowExecutionRateLimit": {
"sync": {
"requestsPerMinute": 60, // Sustained rate limit per minute
"maxBurst": 120, // Maximum burst capacity
"remaining": 118, // Current tokens available (up to maxBurst)
"resetAt": "..." // When tokens next refill
},
"async": {
"requestsPerMinute": 200, // Sustained rate limit per minute
"maxBurst": 400, // Maximum burst capacity
"remaining": 398, // Current tokens available
"resetAt": "..." // When tokens next refill
}
},
"usage": {
"currentPeriodCost": 1.234, // Current billing period usage in USD
"limit": 10, // Usage limit in USD
"plan": "pro", // Current subscription plan
"isExceeded": false // Whether limit is exceeded
}
}Nota: Los límites de tasa utilizan un algoritmo de cubo de tokens. remaining puede exceder requestsPerMinute hasta maxBurst cuando no has usado tu asignación completa recientemente, permitiendo tráfico en ráfagas. Los límites de tasa en el cuerpo de la respuesta son para ejecuciones de flujo de trabajo. Los límites de tasa para llamar a este punto final de la API están en los encabezados de respuesta (X-RateLimit-*).
Consultar registros
Consulta los registros de ejecución de flujos de trabajo con amplias opciones de filtrado.
GET /api/v1/logsParámetros requeridos:
workspaceId- Tu ID de espacio de trabajo
Filtros opcionales:
workflowIds- IDs de flujos de trabajo separados por comasfolderIds- IDs de carpetas separados por comastriggers- Tipos de disparadores separados por comas:api,webhook,schedule,manual,chatlevel- Filtrar por nivel:info,errorstartDate- Marca de tiempo ISO para el inicio del rango de fechasendDate- Marca de tiempo ISO para el fin del rango de fechasexecutionId- Coincidencia exacta de ID de ejecuciónminDurationMs- Duración mínima de ejecución en milisegundosmaxDurationMs- Duración máxima de ejecución en milisegundosminCost- Costo mínimo de ejecuciónmaxCost- Costo máximo de ejecuciónmodel- Filtrar por modelo de IA utilizado
Paginación:
limit- Resultados por página (predeterminado: 100)cursor- Cursor para la siguiente páginaorder- Orden de clasificación:desc,asc(predeterminado: desc)
Nivel de detalle:
details- Nivel de detalle de la respuesta:basic,full(predeterminado: básico)includeTraceSpans- Incluir intervalos de seguimiento (predeterminado: falso)includeFinalOutput- Incluir salida final (predeterminado: falso)
{
"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": {
"requestsPerMinute": 60,
"maxBurst": 120,
"remaining": 118,
"resetAt": "2025-01-01T12:35:56.789Z"
},
"async": {
"requestsPerMinute": 200,
"maxBurst": 400,
"remaining": 398,
"resetAt": "2025-01-01T12:35:56.789Z"
}
},
"usage": {
"currentPeriodCost": 1.234,
"limit": 10,
"plan": "pro",
"isExceeded": false
}
}
}Obtener detalles del registro
Recupera información detallada sobre una entrada de registro 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": {
"requestsPerMinute": 60,
"maxBurst": 120,
"remaining": 118,
"resetAt": "2025-01-01T12:35:56.789Z"
},
"async": {
"requestsPerMinute": 200,
"maxBurst": 400,
"remaining": 398,
"resetAt": "2025-01-01T12:35:56.789Z"
}
},
"usage": {
"currentPeriodCost": 1.234,
"limit": 10,
"plan": "pro",
"isExceeded": false
}
}
}
}Obtener detalles de ejecución
Recupera detalles de ejecución incluyendo la instantánea del estado del flujo de trabajo.
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": {...}
}
}Notificaciones
Recibe notificaciones en tiempo real cuando se completan las ejecuciones de flujos de trabajo a través de webhook, correo electrónico o Slack. Las notificaciones se configuran a nivel de espacio de trabajo desde la página de Registros.
Configuración
Configura las notificaciones desde la página de Registros haciendo clic en el botón de menú y seleccionando "Configurar notificaciones".
Canales de notificación:
- Webhook: Envía solicitudes HTTP POST a tu punto de conexión
- Correo electrónico: Recibe notificaciones por correo con detalles de la ejecución
- Slack: Publica mensajes en un canal de Slack
Selección de flujos de trabajo:
- Selecciona flujos de trabajo específicos para monitorear
- O elige "Todos los flujos de trabajo" para incluir los flujos actuales y futuros
Opciones de filtrado:
levelFilter: Niveles de registro a recibir (info,error)triggerFilter: Tipos de disparadores a recibir (api,webhook,schedule,manual,chat)
Datos opcionales:
includeFinalOutput: Incluir la salida final del flujo de trabajoincludeTraceSpans: Incluir trazas detalladas de la ejecuciónincludeRateLimits: Incluir información de límites de tasa (límites sincrónicos/asincrónicos y restantes)includeUsageData: Incluir uso y límites del período de facturación
Reglas de alerta
En lugar de recibir notificaciones por cada ejecución, configura reglas de alerta para ser notificado solo cuando se detecten problemas:
Fallos consecutivos
- Alerta después de X ejecuciones fallidas consecutivas (por ejemplo, 3 fallos seguidos)
- Se reinicia cuando una ejecución tiene éxito
Tasa de fallos
- Alerta cuando la tasa de fallos supera el X% durante las últimas Y horas
- Requiere un mínimo de 5 ejecuciones en la ventana de tiempo
- Solo se activa después de que haya transcurrido la ventana de tiempo completa
Umbral de latencia
- Alerta cuando cualquier ejecución tarda más de X segundos
- Útil para detectar flujos de trabajo lentos o bloqueados
Pico de latencia
- Alerta cuando la ejecución es X% más lenta que el promedio
- Compara con la duración promedio durante la ventana de tiempo configurada
- Requiere un mínimo de 5 ejecuciones para establecer una línea base
Umbral de costo
- Alerta cuando una sola ejecución cuesta más de $X
- Útil para detectar llamadas costosas a LLM
Sin actividad
- Alerta cuando no ocurren ejecuciones dentro de X horas
- Útil para monitorear flujos de trabajo programados que deberían ejecutarse regularmente
Recuento de errores
- Alerta cuando el recuento de errores excede X dentro de una ventana de tiempo
- Rastrea errores totales, no consecutivos
Todos los tipos de alertas incluyen un período de enfriamiento de 1 hora para evitar el spam de notificaciones.
Configuración de webhook
Para webhooks, hay opciones adicionales disponibles:
url: La URL de tu endpoint webhooksecret: Secreto opcional para verificación de firma HMAC
Estructura de carga útil
Cuando se completa la ejecución de un flujo de trabajo, Sim envía la siguiente carga útil (vía webhook POST, correo electrónico o 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"
}
}Encabezados de webhook
Cada solicitud de webhook incluye estos encabezados (solo canal webhook):
sim-event: Tipo de evento (siempreworkflow.execution.completed)sim-timestamp: Marca de tiempo Unix en milisegundossim-delivery-id: ID único de entrega para idempotenciasim-signature: Firma HMAC-SHA256 para verificación (si se configura un secreto)Idempotency-Key: Igual que el ID de entrega para detección de duplicados
Verificación de firma
Si configuras un secreto de webhook, verifica la firma para asegurar que el webhook proviene de Sim:
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 reintentos
Las entregas de webhook fallidas se reintentan con retroceso exponencial y fluctuación:
- Máximo de intentos: 5
- Retrasos de reintento: 5 segundos, 15 segundos, 1 minuto, 3 minutos, 10 minutos
- Fluctuación: Hasta un 10% de retraso adicional para prevenir el efecto de manada
- Solo las respuestas HTTP 5xx y 429 activan reintentos
- Las entregas agotan el tiempo después de 30 segundos
Las entregas de webhook se procesan de forma asíncrona y no afectan el rendimiento de ejecución del flujo de trabajo.
Mejores prácticas
-
Estrategia de sondeo: Cuando consultes registros, utiliza paginación basada en cursores con
order=ascystartDatepara obtener nuevos registros de manera eficiente. -
Seguridad de webhook: Siempre configura un secreto de webhook y verifica las firmas para asegurar que las solicitudes provienen de Sim.
-
Idempotencia: Utiliza la cabecera
Idempotency-Keypara detectar y manejar entregas duplicadas de webhook. -
Privacidad: Por defecto,
finalOutputytraceSpansestán excluidos de las respuestas. Habilítalos solo si necesitas los datos y comprendes las implicaciones de privacidad. -
Limitación de tasa: Implementa retroceso exponencial cuando recibas respuestas 429. Verifica la cabecera
Retry-Afterpara conocer el tiempo de espera recomendado.
Limitación de tasa
La API utiliza un algoritmo de cubo de tokens para limitar la tasa, proporcionando un uso justo mientras permite tráfico en ráfagas:
| Plan | Solicitudes/Minuto | Capacidad de ráfaga |
|---|---|---|
| Free | 10 | 20 |
| Pro | 30 | 60 |
| Team | 60 | 120 |
| Enterprise | 120 | 240 |
Cómo funciona:
- Los tokens se recargan a una tasa de
requestsPerMinute - Puedes acumular hasta
maxBursttokens cuando estás inactivo - Cada solicitud consume 1 token
- La capacidad de ráfaga permite manejar picos de tráfico
La información del límite de tasa se incluye en los encabezados de respuesta:
X-RateLimit-Limit: Solicitudes por minuto (tasa de recarga)X-RateLimit-Remaining: Tokens disponibles actualmenteX-RateLimit-Reset: Marca de tiempo ISO cuando los tokens se recargan nuevamente
Ejemplo: Sondeo para nuevos registros
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://sim.ai/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);Ejemplo: Procesamiento de 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');
});