Receive task results via HTTP callbacks instead of polling.
Overview
When using callback mode, APIXO sends a POST request to your specified URL when a task completes. This eliminates polling overhead and provides immediate notifications — ideal for high-volume production applications.
Setup
Create a webhook endpoint
Your endpoint must accept POST requests, respond with HTTP 200 within 30 seconds, and be publicly accessible via HTTPS.If your endpoint does not respond with HTTP 200 within 30 seconds, APIXO will retry delivery up to 3 times with increasing delays.
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
Include request_type: "callback" and your callback_url in the request: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 Fields
Final task state: success or failed.
JSON string containing resultUrls array. Only present on success.
Processing time in milliseconds.
Error code. Only present on failure.
Human-readable error message. Only present on failure.
Retry Policy
If your webhook endpoint fails to respond with HTTP 200:
| Attempt | Delay |
|---|
| 1st retry | 30 seconds |
| 2nd retry | 2 minutes |
| 3rd retry | 10 minutes |
After 3 failed attempts, the webhook is abandoned. You can still query task status via the Status Task endpoint.
Security Recommendations
Implement Idempotency
Webhooks may be delivered more than once. Use taskId to deduplicate and prevent processing the same result twice.
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');
});
Use HTTPS Only
Always use HTTPS for your webhook endpoint to ensure data is encrypted in transit.
Testing Webhooks
Use ngrok to expose your local server during development:
ngrok http 3000
# Returns: https://abc123.ngrok.io — use this as your callback_url
You can still query task status via the API even when using callback mode, which is useful for debugging.