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:
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"
}'
Webhook URLs must use HTTPS. Private or internal URLs (localhost, private IPs) are rejected for security.
Webhook payload
When a generation completes successfully, we send a POST request to your URL with these headers and body:
| Header | Value |
|---|
Content-Type | application/json |
X-Webhook-Source | artificial-studio |
X-Media-Id | The generation ID |
Body
{
"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
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');
});
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
Return a 200 quickly. Your endpoint should respond within 5 seconds. Process the webhook data asynchronously if needed.
- 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