Получайте результаты задач по HTTP callback вместо polling.
Обзор
При использовании режима callback APIXO отправляет POST-запрос на указанный URL при завершении задачи. Это убирает overhead от polling и даёт немедленные уведомления — удобно для продакшен-приложений с высокой нагрузкой.
Настройка
Create a webhook endpoint
Ваш эндпоинт должен принимать POST-запросы, отвечать HTTP 200 в течение 30 секунд и быть публично доступным по HTTPS.Если эндпоинт не отвечает HTTP 200 в течение 30 секунд, APIXO повторит доставку до 3 раз с увеличивающимися задержками.
Express.js
FastAPI
Next.js
const express = require('express');
const app = express();
app.use(express.json());
app.post('/webhook/apixo', (req, res) => {
const { taskId, state, resultJson, failCode, failMsg } = req.body.data;
if (state === 'success') {
const urls = JSON.parse(resultJson).resultUrls;
console.log('Generated:', urls);
} else if (state === 'failed') {
console.error(`Task ${taskId} failed: ${failCode} - ${failMsg}`);
}
res.status(200).send('OK');
});
app.listen(3000);
from fastapi import FastAPI, Request
import json
app = FastAPI()
@app.post('/webhook/apixo')
async def handle_webhook(request: Request):
body = await request.json()
data = body['data']
if data['state'] == 'success':
urls = json.loads(data['resultJson'])['resultUrls']
print(f"Generated: {urls}")
elif data['state'] == 'failed':
print(f"Task {data['taskId']} failed: {data['failCode']} - {data['failMsg']}")
return {'status': 'ok'}
// app/api/webhook/apixo/route.ts
import { NextRequest, NextResponse } from 'next/server';
export async function POST(request: NextRequest) {
const body = await request.json();
const { taskId, state, resultJson, failCode, failMsg } = body.data;
if (state === 'success') {
const urls = JSON.parse(resultJson).resultUrls;
console.log('Generated:', urls);
} else if (state === 'failed') {
console.error(`Task ${taskId} failed: ${failCode} - ${failMsg}`);
}
return NextResponse.json({ status: 'ok' });
}
Submit a task with callback
Включите request_type: "callback" и свой callback_url в запрос:curl -X POST https://api.apixo.ai/api/v1/generateTask/nano-banana \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"request_type": "callback",
"callback_url": "https://your-domain.com/webhook/apixo",
"input": {
"mode": "text-to-image",
"prompt": "A beautiful landscape"
}
}'
const response = await fetch('https://api.apixo.ai/api/v1/generateTask/nano-banana', {
method: 'POST',
headers: {
'Authorization': 'Bearer YOUR_API_KEY',
'Content-Type': 'application/json',
},
body: JSON.stringify({
request_type: 'callback',
callback_url: 'https://your-domain.com/webhook/apixo',
input: {
mode: 'text-to-image',
prompt: 'A beautiful landscape',
},
}),
});
response = requests.post(
'https://api.apixo.ai/api/v1/generateTask/nano-banana',
headers={
'Authorization': 'Bearer YOUR_API_KEY',
'Content-Type': 'application/json',
},
json={
'request_type': 'callback',
'callback_url': 'https://your-domain.com/webhook/apixo',
'input': {
'mode': 'text-to-image',
'prompt': 'A beautiful landscape',
},
}
)
Webhook Payload
Success
{
"code": 200,
"message": "success",
"data": {
"taskId": "task_abc123xyz",
"state": "success",
"resultJson": "{\"resultUrls\":[\"https://cdn.apixo.ai/output/abc.jpg\"]}",
"costTime": 12500,
"createTime": 1704067200000,
"completeTime": 1704067212500
}
}
Failure
{
"code": 200,
"message": "success",
"data": {
"taskId": "task_abc123xyz",
"state": "failed",
"failCode": "CONTENT_VIOLATION",
"failMsg": "Content violates usage policy",
"createTime": 1704067200000,
"completeTime": 1704067205000
}
}
Поля payload
Уникальный идентификатор задачи.
Итоговое состояние: success или failed.
JSON-строка с массивом resultUrls. Только при успехе.
Время обработки в миллисекундах.
Код ошибки. Только при ошибке.
Читаемое сообщение об ошибке. Только при ошибке.
Политика повторных попыток
Если webhook-эндпоинт не отвечает HTTP 200:
| Попытка | Задержка |
|---|
| 1-я повторная | 30 секунд |
| 2-я повторная | 2 минуты |
| 3-я повторная | 10 минут |
После 3 неудачных попыток webhook не повторяется. Статус задачи по-прежнему можно получить через эндпоинт Статус задачи.
Рекомендации по безопасности
Идемпотентность
Webhook может доставляться несколько раз. Используйте taskId для дедупликации и предотвращения повторной обработки одного и того же результата.
const processedTasks = new Set();
app.post('/webhook/apixo', (req, res) => {
const { taskId } = req.body.data;
if (processedTasks.has(taskId)) {
return res.status(200).send('Already processed');
}
processedTasks.add(taskId);
// Process the task...
res.status(200).send('OK');
});
Только HTTPS
Всегда используйте HTTPS для webhook-эндпоинта, чтобы данные передавались зашифрованно.
Тестирование webhooks
Используйте ngrok для доступа к локальному серверу при разработке:
ngrok http 3000
# Возвращает: https://abc123.ngrok.io — используйте как callback_url
При использовании режима callback статус задачи по-прежнему можно запрашивать через API, что удобно для отладки.