Coming Soon — The webhook delivery system is under active development. The event types, payload formats, and management UI documented below describe the planned feature. We’ll update this page when webhooks are available.
Webhooks let you build event-driven integrations with Avala. Instead of polling the API for changes, register an endpoint and Avala will send an HTTP POST request to it whenever a relevant event occurs — an export finishes, a task is submitted for review, a project changes status, and more.
Setting Up Webhooks
- Go to Mission Control > Settings > Webhooks.
- Click Create Webhook.
- Enter your Endpoint URL (must be HTTPS).
- Select the Events you want to subscribe to (or choose “All events”).
- Optionally provide a Secret for signature verification (recommended).
- Click Save.
Avala will send a test ping to your endpoint. If it responds with a 2xx status code, the webhook is activated.
Webhook Events
| Event | Trigger |
|---|
export.completed | An export finishes processing and is ready for download. |
project.status_changed | A project’s status changes (e.g., from “In Progress” to “Review”). |
task.submitted | An annotator submits a task for review. |
task.approved | A reviewer approves a submitted task. |
dataset.created | A new dataset is created in the workspace. |
Every webhook delivery is a JSON POST request with the following structure:
{
"event": "export.completed",
"timestamp": "2026-02-21T14:30:00Z",
"data": {
"id": "exp_abc123",
"dataset_id": "ds_xyz789",
"format": "coco",
"status": "completed",
"download_url": "https://server.avala.ai/api/v1/exports/exp_abc123/download"
}
}
The data object varies by event type and contains the relevant resource fields. All timestamps are in UTC (ISO 8601).
Event-Specific Payloads
project.status_changed
{
"event": "project.status_changed",
"timestamp": "2026-02-21T15:00:00Z",
"data": {
"id": "proj_def456",
"name": "Pedestrian Detection Q1",
"previous_status": "in_progress",
"new_status": "review",
"changed_by": "user_ghi789"
}
}
task.submitted
{
"event": "task.submitted",
"timestamp": "2026-02-21T15:10:00Z",
"data": {
"id": "task_jkl012",
"project_id": "proj_def456",
"asset_id": "asset_mno345",
"submitted_by": "user_pqr678"
}
}
Verifying Webhook Signatures
If you provided a secret when creating the webhook, Avala includes an HMAC-SHA256 signature in the X-Avala-Signature header. Use it to verify that the request genuinely came from Avala.
The signature is computed over the raw request body:
HMAC-SHA256(secret, raw_body)
Verification Example (Python)
import hmac
import hashlib
def verify_signature(payload: bytes, signature: str, secret: str) -> bool:
expected = hmac.new(
secret.encode("utf-8"),
payload,
hashlib.sha256
).hexdigest()
return hmac.compare_digest(expected, signature)
Always verify the signature before processing a webhook payload. Without
verification, an attacker could send forged requests to your endpoint.
Retry Policy
If your endpoint does not respond with a 2xx status code, Avala retries the delivery with exponential backoff:
| Attempt | Delay |
|---|
| 1st retry | 1 minute |
| 2nd retry | 5 minutes |
| 3rd retry | 30 minutes |
| 4th retry | 2 hours |
| 5th retry | 12 hours |
After 5 failed retries, the delivery is marked as failed. You can view failed deliveries and manually re-trigger them in Mission Control > Settings > Webhooks > Delivery Log.
If an endpoint fails consistently for 7 consecutive days, Avala will automatically disable the webhook and send a notification to workspace admins.
Example Webhook Handler
A minimal Flask application that receives and verifies Avala webhooks:
import hmac
import hashlib
from flask import Flask, request, jsonify
app = Flask(__name__)
WEBHOOK_SECRET = "your-webhook-secret"
@app.route("/webhooks/avala", methods=["POST"])
def handle_webhook():
# Verify signature
signature = request.headers.get("X-Avala-Signature", "")
expected = hmac.new(
WEBHOOK_SECRET.encode("utf-8"),
request.data,
hashlib.sha256
).hexdigest()
if not hmac.compare_digest(expected, signature):
return jsonify({"error": "Invalid signature"}), 401
# Parse the event
event = request.json
event_type = event.get("event")
if event_type == "export.completed":
download_url = event["data"]["download_url"]
print(f"Export ready: {download_url}")
# Download the export, trigger a training pipeline, etc.
elif event_type == "task.submitted":
task_id = event["data"]["id"]
print(f"Task submitted: {task_id}")
# Notify reviewers, update a dashboard, etc.
elif event_type == "project.status_changed":
project_name = event["data"]["name"]
new_status = event["data"]["new_status"]
print(f"Project '{project_name}' moved to {new_status}")
return jsonify({"received": True}), 200
if __name__ == "__main__":
app.run(port=5000)
Testing Webhooks
During development you can test webhooks without deploying a public endpoint:
-
Use a tunnel service like ngrok to expose a local server:
Copy the HTTPS URL and use it as your webhook endpoint in Mission Control.
-
Send a test ping from Mission Control. Go to Settings > Webhooks, select your webhook, and click Send Test Ping. The test ping sends a
ping event you can use to verify connectivity.
-
Check the Delivery Log in Mission Control to inspect request payloads, response codes, and timing for every delivery attempt.