AACFlow предоставляет комплексный внешний API для запросов логов выполнения рабочих процессов и настройки вебхуков для получения уведомлений в реальном времени при завершении рабочих процессов.
Аутентификация
Все запросы к API требуют ключ API, передаваемый в заголовке x-api-key:
curl -H "x-api-key: YOUR_API_KEY" \
https://aacflow.io/api/v1/logs?workspaceId=YOUR_WORKSPACE_IDВы можете сгенерировать ключи API на платформе AACFlow, перейдя в Настройки, затем в Ключи AACFlow и нажав Создать.
API логов
Все ответы API включают информацию о ваших лимитах выполнения рабочих процессов и использовании:
"limits": {
"workflowExecutionRateLimit": {
"sync": {
"requestsPerMinute": 150, // Устойчивый лимит запросов в минуту
"maxBurst": 300, // Максимальная емкость для всплесков
"remaining": 298, // Текущие доступные токены (до maxBurst)
"resetAt": "..." // Когда токены пополнятся в следующий раз
},
"async": {
"requestsPerMinute": 1000, // Устойчивый лимит запросов в минуту
"maxBurst": 2000, // Максимальная емкость для всплесков
"remaining": 1998, // Текущие доступные токены
"resetAt": "..." // Когда токены пополнятся в следующий раз
}
},
"usage": {
"currentPeriodCost": 1.234, // Использование в текущем биллинговом периоде в USD
"limit": 10, // Лимит использования в USD
"plan": "pro", // Текущий тарифный план
"isExceeded": false // Превышен ли лимит
}
}Примечание: Лимиты скорости используют алгоритм токен-бакета. remaining может превышать requestsPerMinute до maxBurst, когда вы не использовали полный лимит недавно, что позволяет обрабатывать всплески трафика. Лимиты скорости в теле ответа относятся к выполнению рабочих процессов. Лимиты скорости для вызова этого конечного API находятся в заголовках ответа (X-RateLimit-*).
Запрос логов
Запрашивайте логи выполнения рабочих процессов с расширенными опциями фильтрации.
GET /api/v1/logsОбязательные параметры:
workspaceId- ID вашего рабочего пространства
Опциональные фильтры:
workflowIds- ID рабочих процессов через запятуюfolderIds- ID папок через запятуюtriggers- Типы триггеров через запятую:api,webhook,schedule,manual,chatlevel- Фильтр по уровню:info,errorstartDate- Временная метка ISO для начала диапазона датendDate- Временная метка ISO для конца диапазона датexecutionId- Точное совпадение ID выполненияminDurationMs- Минимальная длительность выполнения в миллисекундахmaxDurationMs- Максимальная длительность выполнения в миллисекундахminCost- Минимальная стоимость выполненияmaxCost- Максимальная стоимость выполненияmodel- Фильтр по используемой AI-модели
Пагинация:
limit- Результатов на страницу (по умолчанию: 100)cursor- Курсор для следующей страницыorder- Порядок сортировки:desc,asc(по умолчанию: desc)
Уровень детализации:
details- Уровень детализации ответа:basic,full(по умолчанию: basic)includeTraceSpans- Включать трассировочные спаны (по умолчанию: false)includeFinalOutput- Включать финальный вывод (по умолчанию: 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": {
"requestsPerMinute": 150,
"maxBurst": 300,
"remaining": 298,
"resetAt": "2025-01-01T12:35:56.789Z"
},
"async": {
"requestsPerMinute": 1000,
"maxBurst": 2000,
"remaining": 1998,
"resetAt": "2025-01-01T12:35:56.789Z"
}
},
"usage": {
"currentPeriodCost": 1.234,
"limit": 10,
"plan": "pro",
"isExceeded": false
}
}
}Получение деталей лога
Получите подробную информацию о конкретной записи лога.
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": "Мой рабочий процесс",
"description": "Обработка данных клиентов"
},
"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": 150,
"maxBurst": 300,
"remaining": 298,
"resetAt": "2025-01-01T12:35:56.789Z"
},
"async": {
"requestsPerMinute": 1000,
"maxBurst": 2000,
"remaining": 1998,
"resetAt": "2025-01-01T12:35:56.789Z"
}
},
"usage": {
"currentPeriodCost": 1.234,
"limit": 10,
"plan": "pro",
"isExceeded": false
}
}
}
}Получение деталей выполнения
Получите детали выполнения, включая снимок состояния рабочего процесса.
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": {...}
}
}Уведомления
Получайте уведомления в реальном времени при завершении выполнения рабочих процессов через вебхук, email или Slack. Уведомления настраиваются на уровне рабочего пространства на странице Логов.
Конфигурация
Настройте уведомления на странице Логов, нажав кнопку меню и выбрав "Настроить уведомления".
Каналы уведомлений:
- Вебхук: Отправка HTTP POST запросов на ваш конечный URL
- Email: Получение email-уведомлений с деталями выполнения
- Slack: Отправка сообщений в канал Slack
Выбор рабочих процессов:
- Выберите конкретные рабочие процессы для мониторинга
- Или выберите "Все рабочие процессы" для включения текущих и будущих рабочих процессов
Опции фильтрации:
levelFilter: Уровни логов для получения (info,error)triggerFilter: Типы триггеров для получения (api,webhook,schedule,manual,chat)
Опциональные данные:
includeFinalOutput: Включать финальный вывод рабочего процессаincludeTraceSpans: Включать детальные трассировочные спаны выполненияincludeRateLimits: Включать информацию о лимитах скорости (синхронные/асинхронные лимиты и оставшиеся)includeUsageData: Включать данные об использовании и лимитах биллингового периода
Правила оповещений
Вместо получения уведомлений о каждом выполнении настройте правила оповещений, чтобы получать уведомления только при обнаружении проблем:
Последовательные сбои
- Оповещение после X последовательных неудачных выполнений (например, 3 сбоя подряд)
- Сбрасывается при успешном выполнении
Процент сбоев
- Оповещение, когда процент сбоев превышает X% за последние Y часов
- Требуется минимум 5 выполнений в окне
- Срабатывает только после полного истечения временного окна
Порог задержки
- Оповещение, когда любое выполнение занимает больше X секунд
- Полезно для обнаружения медленных или зависших рабочих процессов
Скачок задержки
- Оповещение, когда выполнение на X% медленнее среднего
- Сравнивается со средней длительностью за настроенное временное окно
- Требуется минимум 5 выполнений для установления базовой линии
Порог стоимости
- Оповещение, когда одно выполнение стоит больше $X
- Полезно для обнаружения дорогих вызовов LLM
Отсутствие активности
- Оповещение, когда не происходит выполнений в течение X часов
- Полезно для мониторинга запланированных рабочих процессов, которые должны выполняться регулярно
Количество ошибок
- Оповещение, когда количество ошибок превышает X в пределах временного окна
- Отслеживает общее количество ошибок, не последовательных
Все типы оповещений включают 1-часовой период охлаждения для предотвращения спама уведомлениями.
Конфигурация вебхука
Для вебхуков доступны дополнительные опции:
url: URL вашего конечного вебхукаsecret: Опциональный секрет для проверки подписи HMAC
Структура полезной нагрузки
Когда выполнение рабочего процесса завершается, AACFlow отправляет следующую полезную нагрузку (через POST вебхука, email или 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": {...}, // Только если includeFinalOutput=true
"traceSpans": [...], // Только если includeTraceSpans=true
"rateLimits": {...}, // Только если includeRateLimits=true
"usage": {...} // Только если includeUsageData=true
},
"links": {
"log": "/v1/logs/log_abc123",
"execution": "/v1/logs/executions/exec_def456"
}
}Заголовки вебхука
Каждый запрос вебхука включает эти заголовки (только для канала вебхука):
aacflow-event: Тип события (всегдаworkflow.execution.completed)aacflow-timestamp: Временная метка Unix в миллисекундахaacflow-delivery-id: Уникальный ID доставки для идемпотентностиaacflow-signature: Подпись HMAC-SHA256 для проверки (если настроен секрет)Idempotency-Key: То же, что и ID доставки для обнаружения дубликатов
Проверка подписи
Если вы настроили секрет вебхука, проверьте подпись, чтобы убедиться, что вебхук от AACFlow:
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;
}
// В вашем обработчике вебхука
app.post('/webhook', (req, res) => {
const signature = req.headers['aacflow-signature'];
const body = JSON.stringify(req.body);
if (!verifyWebhookSignature(body, signature, process.env.WEBHOOK_SECRET)) {
return res.status(401).send('Invalid signature');
}
// Обработать вебхук...
});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)
# В вашем обработчике вебхука
@app.route('/webhook', methods=['POST'])
def webhook():
signature = request.headers.get('aacflow-signature')
body = json.dumps(request.json)
if not verify_webhook_signature(body, signature, os.environ['WEBHOOK_SECRET']):
return 'Invalid signature', 401
# Обработать вебхук...Политика повторных попыток
Неудачные доставки вебхуков повторяются с экспоненциальной задержкой и джиттером:
- Максимальное количество попыток: 5
- Задержки повторных попыток: 5 секунд, 15 секунд, 1 минута, 3 минуты, 10 минут
- Джиттер: До 10% дополнительной задержки для предотвращения "стадного эффекта"
- Только HTTP ответы 5xx и 429 запускают повторные попытки
- Доставки таймаутят через 30 секунд
Доставки вебхуков обрабатываются асинхронно и не влияют на производительность выполнения рабочих процессов.
Лучшие практики
-
Стратегия опроса: При опросе логов используйте пагинацию на основе курсора с
order=ascиstartDateдля эффективного получения новых логов. -
Безопасность вебхуков: Всегда настраивайте секрет вебхука и проверяйте подписи, чтобы убедиться, что запросы от AACFlow.
-
Идемпотентность: Используйте заголовок
Idempotency-Keyдля обнаружения и обработки дублирующихся доставок вебхуков. -
Конфиденциальность: По умолчанию
finalOutputиtraceSpansисключены из ответов. Включайте их только если вам нужны эти данные и вы понимаете последствия для конфиденциальности. -
Лимитирование скорости: Реализуйте экспоненциальную задержку при получении ответов 429. Проверяйте заголовок
Retry-Afterдля рекомендуемого времени ожидания.
Лимитирование скорости
API использует алгоритм токен-бакета для лимитирования скорости, обеспечивая справедливое использование при разрешении всплесков трафика:
| Тариф | Запросов/Минуту | Емкость для всплесков |
|---|---|---|
| Бесплатный | 30 | 60 |
| Pro | 100 | 200 |
| Team | 200 | 400 |
| Enterprise | 500 | 1000 |
Как это работает:
- Токены пополняются со скоростью
requestsPerMinute - Вы можете накапливать до
maxBurstтокенов при простое - Каждый запрос потребляет 1 токен
- Емкость для всплесков позволяет обрабатывать пики трафика
Информация о лимитах скорости включена в заголовки ответа:
X-RateLimit-Limit: Запросов в минуту (скорость пополнения)X-RateLimit-Remaining: Текущие доступные токеныX-RateLimit-Reset: Временная метка ISO, когда токены пополнятся в следующий раз
Пример: Опрос новых логов
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://aacflow.io/api/v1/logs?${params}`,
{
headers: {
'x-api-key': 'YOUR_API_KEY'
}
}
);
if (response.ok) {
const data = await response.json();
// Обработать новые логи
for (const log of data.data) {
console.log(`Новое выполнение: ${log.executionId}`);
}
// Обновить курсор для следующего опроса
if (data.nextCursor) {
cursor = data.nextCursor;
}
}
}
// Опрашивать каждые 30 секунд
setInterval(pollLogs, 30000);Пример: Обработка вебхуков
import express from 'express';
import crypto from 'crypto';
const app = express();
app.use(express.json());
app.post('/aacflow-webhook', (req, res) => {
// Проверить подпись
const signature = req.headers['aacflow-signature'];
const body = JSON.stringify(req.body);
if (!verifyWebhookSignature(body, signature, process.env.WEBHOOK_SECRET)) {
return res.status(401).send('Invalid signature');
}
// Проверить временную метку для предотвращения атак повторного воспроизведения
const timestamp = parseInt(req.headers['aacflow-timestamp']);
const fiveMinutesAgo = Date.now() - (5 * 60 * 1000);
if (timestamp < fiveMinutesAgo) {
return res.status(401).send('Timestamp too old');
}
// Обработать вебхук
const event = req.body;
switch (event.type) {
case 'workflow.execution.completed':
const { workflowId, executionId, status, cost } = event.data;
if (status === 'error') {
console.error(`Рабочий процесс ${workflowId} завершился с ошибкой: ${executionId}`);
// Обработать ошибку...
} else {
console.log(`Рабочий процесс ${workflowId} завершен: ${executionId}`);
console.log(`Стоимость: $${cost.total}`);
// Обработать успешное выполнение...
}
break;
}
// Вернуть 200 для подтверждения получения
res.status(200).send('OK');
});
app.listen(3000, () => {
console.log('Вебхук-сервер слушает на порту 3000');
});
