API externa
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_ID
Puedes 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": {
"limit": 60, // Max sync workflow executions per minute
"remaining": 58, // Remaining sync workflow executions
"resetAt": "..." // When the window resets
},
"async": {
"limit": 60, // Max async workflow executions per minute
"remaining": 59, // Remaining async workflow executions
"resetAt": "..." // When the window resets
}
},
"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 en el cuerpo de la respuesta son para ejecuciones de flujos de trabajo. Los lÃmites de tasa para llamar a este endpoint 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/logs
Pará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
,chat
level
- Filtrar por nivel:info
,error
startDate
- 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": {
"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
}
}
}
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": {
"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
}
}
}
}
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": {...}
}
}
Suscripciones a webhooks
Recibe notificaciones en tiempo real cuando se completan las ejecuciones de flujos de trabajo. Los webhooks se configuran a través de la interfaz de usuario de Sim en el editor de flujos de trabajo.
Configuración
Los webhooks pueden configurarse para cada flujo de trabajo a través de la interfaz de usuario del editor de flujos de trabajo. Haz clic en el icono de webhook en la barra de control para configurar tus suscripciones a webhooks.
Opciones de configuración disponibles:
url
: URL del punto final de tu webhooksecret
: Secreto opcional para verificación de firma HMACincludeFinalOutput
: Incluir la salida final del flujo de trabajo en la carga útilincludeTraceSpans
: Incluir intervalos de seguimiento de ejecución detalladosincludeRateLimits
: Incluir información del lÃmite de tasa del propietario del flujo de trabajoincludeUsageData
: Incluir datos de uso y facturación del propietario del flujo de trabajolevelFilter
: Array de niveles de registro a recibir (info
,error
)triggerFilter
: Array de tipos de disparadores a recibir (api
,webhook
,schedule
,manual
,chat
)active
: Habilitar/deshabilitar la suscripción al webhook
Carga útil del webhook
Cuando se completa la ejecución de un flujo de trabajo, Sim envÃa una solicitud POST a tu URL de webhook:
{
"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"
}
}
Cabeceras de webhook
Cada solicitud de webhook incluye estas cabeceras:
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 de espera después de 30 segundos
Las entregas de webhook se procesan de forma asÃncrona y no afectan al rendimiento de ejecución del flujo de trabajo.
Mejores prácticas
-
Estrategia de sondeo: Al sondear registros, utiliza paginación basada en cursor con
order=asc
ystartDate
para 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-Key
para detectar y manejar entregas duplicadas de webhook. -
Privacidad: Por defecto,
finalOutput
ytraceSpans
está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. Consulta la cabecera
Retry-After
para conocer el tiempo de espera recomendado.
Limitación de tasa
La API implementa limitación de tasa para garantizar un uso justo:
- Plan gratuito: 10 solicitudes por minuto
- Plan Pro: 30 solicitudes por minuto
- Plan Team: 60 solicitudes por minuto
- Plan Enterprise: LÃmites personalizados
La información del lÃmite de tasa se incluye en los encabezados de respuesta:
X-RateLimit-Limit
: Máximo de solicitudes por ventanaX-RateLimit-Remaining
: Solicitudes restantes en la ventana actualX-RateLimit-Reset
: Marca de tiempo ISO cuando se reinicia la ventana
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');
});