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

# Webhooks

> Receive real-time notifications when generations complete instead of polling.

Webhooks deliver generation results to your server in real-time. Instead of polling `GET /api/generations/:id` repeatedly, you receive a single `POST` request when the generation is done.

## Polling vs. webhooks

| | Polling | Webhooks |
| - | - | - |
| **Setup** | No setup needed | Requires a public HTTPS endpoint |
| **Latency** | Depends on poll interval | Near-instant notification |
| **Efficiency** | Many requests per generation | One request per generation |
| **Best for** | Quick scripts, testing | Production applications |

## How to use webhooks

Add a `webhook` URL to your `/api/run` request:

```bash theme={null}
curl -X POST https://api.artificialstudio.ai/api/run \
  -H "Content-Type: application/json" \
  -H "Authorization: YOUR_API_KEY" \
  -d '{
    "tool": "create-image",
    "input": {
      "prompt": "A mountain landscape at dawn"
    },
    "webhook": "https://your-server.com/webhook"
  }'
```

<Warning>Webhook URLs must use HTTPS. Private or internal URLs (localhost, private IPs) are rejected for security.</Warning>

## Webhook payload

When a generation completes successfully, we send a `POST` request to your URL with these headers and body:

### Headers

| Header | Value |
| - | - |
| `Content-Type` | `application/json` |
| `X-Webhook-Source` | `artificial-studio` |
| `X-Media-Id` | The generation ID |

### Body

```json theme={null}
{
  "id": "507f1f77bcf86cd799439011",
  "status": "success",
  "tool": "create-image",
  "type": "image",
  "output": "https://files.artificialstudio.ai/generations/abc123.png",
  "thumbnail": "https://files.artificialstudio.ai/thumbnails/abc123.jpg",
  "createdAt": "2024-01-15T10:30:00.000Z"
}
```

| Field | Type | Description |
| - | - | - |
| `id` | string | Generation identifier |
| `status` | string | Always `success` (webhooks are only sent on success) |
| `tool` | string | Tool used |
| `type` | string | `image`, `video`, `audio`, `text`, or `object` |
| `output` | string | URL to the generated media |
| `thumbnail` | string \| null | Thumbnail URL (null for audio) |
| `createdAt` | string | ISO 8601 timestamp |

## Example handlers

<CodeGroup>
  ```javascript Express theme={null}
  app.post('/webhook', express.json(), (req, res) => {
    const { id, output, tool, type } = req.body;

    console.log(`Generation ${id} completed: ${output}`);
    // Save to database, notify user, etc.

    res.status(200).send('OK');
  });
  ```

  ```python Flask theme={null}
  from flask import Flask, request

  app = Flask(__name__)

  @app.route('/webhook', methods=['POST'])
  def webhook():
      data = request.json

      print(f"Generation {data['id']} completed: {data['output']}")
      # Save to database, notify user, etc.

      return 'OK', 200
  ```

  ```javascript Next.js theme={null}
  export async function POST(request) {
    const data = await request.json();

    console.log(`Generation ${data.id} completed: ${data.output}`);
    // Save to database, notify user, etc.

    return new Response('OK', { status: 200 });
  }
  ```
</CodeGroup>

## Retries

If your endpoint does not return a `200` status, we retry with exponential backoff:

| Retry | Delay |
| - | - |
| 1 | 5 seconds |
| 2 | 15 seconds |
| 3 | 1 minute |
| 4 | 5 minutes |
| 5 | 15 minutes |
| 6 | 1 hour |
| 7 | 6 hours |
| 8 | 12 hours |
| 9 | 24 hours |

After 9 failed retries, the webhook is marked as failed.

## Best practices

<Note>
  **Return a 200 quickly.** Your endpoint should respond within 5 seconds. Process the webhook data asynchronously if needed.
</Note>

* **Handle duplicates** — Retries may deliver the same webhook twice. Use the `id` field to deduplicate.
* **Validate the payload** — Check that the data matches expected formats before processing.
* **Log everything** — Keep logs of received webhooks for debugging.

## Requirements

Your webhook endpoint must:

* Be **publicly accessible** (no localhost or private IPs)
* Use **HTTPS**
* Accept **POST** requests with a JSON body
* Return **200** to acknowledge receipt


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.