Skip to main content

Webhooks

Receive real-time HTTP notifications when events occur in your Lucitra project. Webhooks eliminate the need to poll for validation status and integrate directly with Slack and Microsoft Teams.

Events

Fired when a validation run begins processing.
{
  "event": "validation.started",
  "run_id": "run_3fa85f64",
  "dataset_id": "ds_7kx9m2",
  "validation_type": "full",
  "timestamp": "2026-03-06T12:10:00Z"
}
Fired when a validation run finishes successfully and a report is available.
{
  "event": "validation.completed",
  "run_id": "run_3fa85f64",
  "dataset_id": "ds_7kx9m2",
  "report_id": "rpt_8abc1234",
  "overall_score": 82,
  "timestamp": "2026-03-06T12:15:00Z"
}
Fired when a validation run encounters an error.
{
  "event": "validation.failed",
  "run_id": "run_3fa85f64",
  "dataset_id": "ds_7kx9m2",
  "error": "Unsupported annotation schema in scene_042",
  "timestamp": "2026-03-06T12:12:00Z"
}
Fired when a dataset upload completes and the file is processed.
{
  "event": "dataset.uploaded",
  "dataset_id": "ds_7kx9m2",
  "name": "warehouse-v3",
  "format": "coco",
  "scene_count": 5000,
  "timestamp": "2026-03-06T12:05:00Z"
}
Fired when a report is generated and ready for download (including PDF export).
{
  "event": "report.ready",
  "report_id": "rpt_8abc1234",
  "run_id": "run_3fa85f64",
  "overall_score": 82,
  "timestamp": "2026-03-06T12:15:05Z"
}

Register a Webhook

curl -X POST https://api.lucitra.io/v1/webhooks \
  -H "Authorization: Bearer luci_your_api_key" \
  -H "Content-Type: application/json" \
  -d '{
    "url": "https://example.com/webhooks/lucitra",
    "events": ["validation.completed", "validation.failed"],
    "secret": null,
    "format": null
  }'
url
string
required
The HTTPS endpoint that will receive webhook deliveries.
events
array
required
List of event types to subscribe to. See the events section above for all options.
secret
string
HMAC signing secret. If omitted, Lucitra auto-generates one prefixed with whsec_. The secret is only returned in the creation response.
format
string
Message format. Set to "slack" for Slack-compatible payloads, "teams" for Microsoft Teams Adaptive Cards, or null for raw JSON.
{
  "id": "wh_9def5678",
  "secret": "whsec_abc123def456"
}
id
string
required
Webhook identifier for management operations.
secret
string
required
HMAC-SHA256 signing secret. Shown only once at creation time. Store it securely.
The secret value is only returned when you create the webhook. Store it immediately in a secure location like a secrets manager. There is no way to retrieve it later.

Format Options

Standard JSON payload sent to your endpoint. Parse and handle it in your application code.
{
  "event": "validation.completed",
  "run_id": "run_3fa85f64",
  "report_id": "rpt_8abc1234",
  "overall_score": 82,
  "timestamp": "2026-03-06T12:15:00Z"
}

List Webhooks

curl "https://api.lucitra.io/v1/webhooks" \
  -H "Authorization: Bearer luci_your_api_key"

Delete a Webhook

curl -X DELETE "https://api.lucitra.io/v1/webhooks/wh_9def5678" \
  -H "Authorization: Bearer luci_your_api_key"

Delivery History

Inspect past delivery attempts for debugging failed webhooks.
curl "https://api.lucitra.io/v1/webhooks/wh_9def5678/deliveries?limit=20&offset=0" \
  -H "Authorization: Bearer luci_your_api_key"
limit
integer
default:"20"
Maximum number of delivery records to return.
offset
integer
default:"0"
Number of records to skip for pagination.

Test a Webhook

Send a test event to verify your endpoint is reachable and responding correctly.
curl -X POST "https://api.lucitra.io/v1/webhooks/wh_9def5678/test" \
  -H "Authorization: Bearer luci_your_api_key"
{
  "success": true,
  "http_status": 200,
  "duration_ms": 142,
  "error": null
}
success
boolean
required
Whether the test delivery received a 2xx response.
http_status
integer
required
HTTP status code returned by your endpoint.
duration_ms
integer
required
Round-trip time in milliseconds.
error
string
Error message if the delivery failed. Null on success.

Signature Verification

Every webhook delivery includes an X-Lucitra-Signature header containing an HMAC-SHA256 signature of the request body. Always verify this signature to ensure the payload was sent by Lucitra and has not been tampered with. The header format is:
X-Lucitra-Signature: sha256=<hex-encoded-hmac>

Verification Example

import hmac
import hashlib

def verify_webhook(payload_bytes: bytes, signature_header: str, secret: str) -> bool:
    """Verify that a webhook payload was signed by Lucitra.

    Args:
        payload_bytes: The raw request body as bytes.
        signature_header: The value of the X-Lucitra-Signature header.
        secret: Your webhook signing secret (whsec_...).

    Returns:
        True if the signature is valid.
    """
    if not signature_header.startswith("sha256="):
        return False

    expected_sig = signature_header.removeprefix("sha256=")
    computed_sig = hmac.new(
        secret.encode("utf-8"),
        payload_bytes,
        hashlib.sha256,
    ).hexdigest()

    return hmac.compare_digest(computed_sig, expected_sig)


# Usage in a Flask handler
from flask import Flask, request, abort

app = Flask(__name__)
WEBHOOK_SECRET = "whsec_abc123def456"

@app.route("/webhooks/lucitra", methods=["POST"])
def handle_webhook():
    signature = request.headers.get("X-Lucitra-Signature", "")
    if not verify_webhook(request.data, signature, WEBHOOK_SECRET):
        abort(401, "Invalid signature")

    event = request.get_json()
    print(f"Received event: {event['event']}")
    return "", 200
Always use hmac.compare_digest (or equivalent constant-time comparison) instead of == to prevent timing attacks against the signature.
If you rotate your webhook secret, create a new webhook with the new secret and delete the old one. There is no update endpoint for secrets because they are only stored as hashed values.