> ## Documentation Index
> Fetch the complete documentation index at: https://apixo.ai/docs/llms.txt
> Use this file to discover all available pages before exploring further.

# Polling vs Webhooks

> Choose the right approach for receiving task results

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

| Aspect             | Polling (Async)          | Webhooks (Callback)      |
| ------------------ | ------------------------ | ------------------------ |
| **Setup**          | Simple                   | Requires public endpoint |
| **Real-time**      | Near real-time           | Instant                  |
| **API Calls**      | Multiple per task        | One per task             |
| **Best For**       | Development, client apps | Production servers       |
| **Infrastructure** | None                     | HTTPS 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

```javascript theme={null}
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:

```javascript theme={null}
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');
}
```

### Recommended Intervals by Model Type

| Model Type      | Initial Wait | Poll Interval | Max Wait |
| --------------- | ------------ | ------------- | -------- |
| Image (fast)    | 5s           | 3s            | 2 min    |
| Image (quality) | 10s          | 5s            | 3 min    |
| Video           | 60s          | 15s           | 10 min   |
| Audio           | 30s          | 10s           | 5 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:**

<Tabs>
  <Tab title="Express.js">
    ```javascript theme={null}
    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);
    ```
  </Tab>

  <Tab title="FastAPI">
    ```python theme={null}
    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']}")
        
        return {'status': 'ok'}
    ```
  </Tab>

  <Tab title="Next.js">
    ```typescript theme={null}
    // 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 } = 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}`);
      }
      
      return NextResponse.json({ status: 'ok' });
    }
    ```
  </Tab>
</Tabs>

**2. Submit task with callback:**

```javascript theme={null}
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:

| 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 via the status endpoint.

## Hybrid Approach

For maximum reliability, combine both approaches:

```javascript theme={null}
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:

```bash theme={null}
# 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

| Scenario              | Recommendation                       |
| --------------------- | ------------------------------------ |
| Development / Testing | Polling                              |
| Client-side app       | Polling                              |
| Production backend    | Webhooks                             |
| High volume           | Webhooks                             |
| Maximum reliability   | Hybrid (webhooks + polling fallback) |

<Info>
  Start with polling for simplicity, then migrate to webhooks as your application scales.
</Info>
