/APIXO Docs

Polling vs Webhooks

Choose the right approach for receiving task results

Polling vs Webhooks

APIXO offers two ways to receive task results: polling (async mode) and webhooks (callback mode). This guide helps you choose the right approach and implement it effectively.

Quick Comparison

AspectPolling (Async)Webhooks (Callback)
SetupSimpleRequires public endpoint
Real-timeNear real-timeInstant
API CallsMultiple per taskOne per task
Best ForDevelopment, client appsProduction servers
InfrastructureNoneHTTPS endpoint

When to Use Polling

Choose polling when:

  • Building client-side applications
  • Prototyping or testing
  • You don't have a public server
  • Processing low volume of tasks

Basic Polling Implementation

async function pollForResult(model, taskId, apiKey) {
  const interval = 3000; // 3 seconds
  const maxAttempts = 60;
  
  for (let i = 0; i < maxAttempts; i++) {
    const response = await fetch(
      `https://api.apixo.ai/api/v1/statusTask/${model}?taskId=${taskId}`,
      { headers: { 'Authorization': `Bearer ${apiKey}` } }
    );
    
    const { data } = await response.json();
    
    if (data.state === 'success') {
      return JSON.parse(data.resultJson).resultUrls;
    }
    if (data.state === 'failed') {
      throw new Error(data.failMsg);
    }
    
    await new Promise(r => setTimeout(r, interval));
  }
  
  throw new Error('Timeout');
}

Exponential Backoff

For better efficiency, use exponential backoff:

async function pollWithBackoff(model, taskId, apiKey) {
  let interval = 3000; // Start at 3s
  const maxInterval = 30000; // Max 30s
  const maxTime = 300000; // 5 min timeout
  let elapsed = 0;
  
  while (elapsed < maxTime) {
    const response = await fetch(
      `https://api.apixo.ai/api/v1/statusTask/${model}?taskId=${taskId}`,
      { headers: { 'Authorization': `Bearer ${apiKey}` } }
    );
    
    const { data } = await response.json();
    
    if (data.state === 'success') {
      return JSON.parse(data.resultJson).resultUrls;
    }
    if (data.state === 'failed') {
      throw new Error(data.failMsg);
    }
    
    await new Promise(r => setTimeout(r, interval));
    elapsed += interval;
    interval = Math.min(interval * 1.5, maxInterval);
  }
  
  throw new Error('Timeout');
}
Model TypeInitial WaitPoll IntervalMax Wait
Image (fast)5s3s2 min
Image (quality)10s5s3 min
Video60s15s10 min
Audio30s10s5 min

When to Use Webhooks

Choose webhooks when:

  • Running a production server
  • Processing high volume of tasks
  • Need real-time notifications
  • Want to minimize API calls

Webhook Setup

1. Create an endpoint:

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);
    // Process your images/videos
  } else if (state === 'failed') {
    console.error(`Task ${taskId} failed: ${failCode}`);
  }
  
  res.status(200).send('OK');
});
 
app.listen(3000);

2. Submit task with callback:

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',
    },
  }),
});

Webhook Requirements

  • Must be publicly accessible via HTTPS
  • Must respond with HTTP 200 within 30 seconds
  • Should handle duplicate deliveries (use taskId for idempotency)

Retry Policy

If your webhook fails:

AttemptDelay
1st retry30 seconds
2nd retry2 minutes
3rd retry10 minutes

After 3 failed attempts, the webhook is abandoned. You can still query via the status endpoint.

Hybrid Approach

For maximum reliability, combine both approaches:

class TaskManager {
  constructor(apiKey) {
    this.apiKey = apiKey;
    this.pendingTasks = new Map();
  }
  
  async submit(model, input, callbackUrl = null) {
    const response = await fetch(
      `https://api.apixo.ai/api/v1/generateTask/${model}`,
      {
        method: 'POST',
        headers: {
          'Authorization': `Bearer ${this.apiKey}`,
          'Content-Type': 'application/json',
        },
        body: JSON.stringify({
          request_type: callbackUrl ? 'callback' : 'async',
          callback_url: callbackUrl,
          input,
        }),
      }
    );
    
    const { data } = await response.json();
    
    if (!callbackUrl) {
      // Fallback to polling if no webhook
      return this.poll(model, data.taskId);
    }
    
    // Track task for webhook
    this.pendingTasks.set(data.taskId, { model, status: 'pending' });
    return data.taskId;
  }
  
  handleWebhook(body) {
    const { taskId, state, resultJson, failMsg } = body.data;
    
    if (state === 'success') {
      this.pendingTasks.delete(taskId);
      return JSON.parse(resultJson).resultUrls;
    }
    
    if (state === 'failed') {
      this.pendingTasks.delete(taskId);
      throw new Error(failMsg);
    }
  }
  
  async poll(model, taskId) {
    // Fallback polling implementation
    return pollWithBackoff(model, taskId, this.apiKey);
  }
}

Local Development with ngrok

For testing webhooks locally:

# Install ngrok
npm install -g ngrok
 
# Start your local server
node server.js  # runs on port 3000
 
# Tunnel to local server
ngrok http 3000
# Returns: https://abc123.ngrok.io
 
# Use ngrok URL as callback_url

Summary

ScenarioRecommendation
Development / TestingPolling
Client-side appPolling
Production backendWebhooks
High volumeWebhooks
Maximum reliabilityHybrid (webhooks + polling fallback)

Start with polling for simplicity, then migrate to webhooks as your application scales.

On this page