Skip to main content
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

  1. Go to Mission Control > Settings > Webhooks.
  2. Click Create Webhook.
  3. Enter your Endpoint URL (must be HTTPS).
  4. Select the Events you want to subscribe to (or choose “All events”).
  5. Optionally provide a Secret for signature verification (recommended).
  6. 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

EventTrigger
export.completedAn export finishes processing and is ready for download.
project.status_changedA project’s status changes (e.g., from “In Progress” to “Review”).
task.submittedAn annotator submits a task for review.
task.approvedA reviewer approves a submitted task.
dataset.createdA new dataset is created in the workspace.

Payload Format

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:
AttemptDelay
1st retry1 minute
2nd retry5 minutes
3rd retry30 minutes
4th retry2 hours
5th retry12 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:
  1. Use a tunnel service like ngrok to expose a local server:
    ngrok http 5000
    
    Copy the HTTPS URL and use it as your webhook endpoint in Mission Control.
  2. 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.
  3. Check the Delivery Log in Mission Control to inspect request payloads, response codes, and timing for every delivery attempt.