Skip to content

Webhooks

Gaard webhooks let you receive classification results as an HTTP POST to your own endpoint as soon as processing is finished.

For integrators, the main idea is simple:

  • your system sends a video to Gaard
  • Gaard classifies it asynchronously
  • when the final result is available, Gaard posts the result JSON to your webhook URL
Processing Pipeline POST /api/classify Webhook POST (JSON) Your system Your webhook endpoint Your queue, incident system, or business workflow Gaard API Classification pipeline Result stored

Gaard currently sends one webhook event type: the final classification result.

The webhook payload uses the same JSON shape as the result returned by:

  • GET /api/result/{id}
  • POST /api/classify?sync=true

That means you can usually reuse the same parser for both polling and webhook-based integrations.

  1. Your application submits a video to POST /api/classify.
  2. Gaard accepts the job and processes it asynchronously.
  3. After classification is completed and the result is persisted, Gaard sends an HTTP POST request to each webhook configured for the flow.
  4. Your endpoint receives the result payload and can trigger downstream actions such as incident creation, alarm enrichment, or archival.

In the Gaard application:

  1. Open the integrations section. Platform integrations
  2. Create a new Webhook integration.
  3. Select the flow that should trigger the webhook.
  4. Enter the destination URL of your receiver.
  5. Save the integration.
  6. Submit a test classification and verify that your endpoint receives the payload.

If you need to send the same result to multiple systems, create multiple webhook integrations.

Gaard sends:

  • Method: POST
  • Header: Content-Type: application/json
  • Body: classification result JSON

Gaard does not currently add custom authentication headers or a signature header. If your receiver requires authentication, protect it at your edge, for example with a secret URL path, a reverse proxy, or another mechanism you control.

Classify WebHook payload
{
"id": "6662f5c1f897618de43f0bbd",
"status": {
"classify": "done",
"video": "done"
},
"parent_id": "000000000000000000000000",
"camera_id": "134188-VI08",
"analyse_id": 3373550353,
"tenant": "tenant",
"duration": 2968236,
"duration_seconds": 2,
"model": "noname",
"version": "2.0.16123",
"error_code": 0,
"error_msg": "",
"risk": "intrusion",
"labels": ["intrusion", "person"],
"result": "classified",
"scores": {
"flag": 0.049,
"plant": 0.03,
"web": 0.009,
"NOTHING": 0.0005,
"intrusion": 0.973,
"person": 0.973,
"rain": 0.002,
"spider": 0.007,
"text": 0.0006,
"wind": 0.021,
"animal": 0.035,
"other": 0.028,
"vehicule": 0.101
},
"video": {
"videoname": "video.mov",
"filename": "video.mov",
"filesize": 786800,
"specs": {
"height": 320,
"original.width": 640,
"duration": 4.217772,
"fps": 3.08,
"nframes": 13,
"original.fps": 3,
"original.height": 360,
"original.nframes": 12,
"width": 568
}
},
"metadata": {
"camera_id": "VI08",
"site_id": 134188
},
"created_at": "2024-05-14T16:13:37.156+02:00",
"started_at": "2024-05-14T16:13:37.156+02:00"
}
FieldTypeNotes
idstringStable classification identifier. Use it as your primary correlation key.
statusobjectFinal processing state for classification and video annotation.
camera_idstringCamera identifier derived from metadata.
analyse_idintOriginal analysis identifier when provided by the sender.
tenantstringGaard tenant that produced the result.
riskstringHigh-level outcome such as safe, danger, or intrusion.
labelsstring[]Labels derived from the score set.
resultstringRaw engine result string such as classified.
scoresobjectPer-label confidence scores.
videoobjectVideo file name, size, and technical specs.
metadataobjectOriginal metadata submitted with the classification request.
created_atstringWhen the classification task was created.
started_atstringWhen processing started.

For the full field reference, see Response structure and Classification result.

Webhook delivery is tied to classification completion.

  • Gaard does not send the webhook when the job is merely accepted.
  • Gaard sends the webhook after the classification result is stored and post-processing is complete.
  • In practice, webhook timing is usually very close to the moment the result becomes available from GET /api/result/{id}.

There is no separate webhook queue or scheduled batch window. End-to-end webhook latency is therefore:

Σ(t) = classify + post-processing + network

Gaard does not currently publish a fixed webhook latency SLA, because classification duration depends on the video, model, runtime load, and network distance to your receiver.

Webhook delivery is currently best effort.

  • Gaard sends one HTTP POST per configured webhook endpoint.
  • Gaard does not currently implement automatic retries.
  • Gaard does not currently treat non-2xx HTTP responses as retryable delivery failures.

Because of that, your receiver should:

  • accept the request quickly
  • return a response immediately after basic validation
  • move heavier work to an internal queue or background worker
  • store the payload id so your processing is idempotent

To make your integration robust:

  • Accept application/json requests.
  • Validate that id, tenant, and the fields you depend on are present.
  • Use the payload id as your deduplication key.
  • Treat error_code != 0 as a completed result with an error, not as a transport failure.
  • Keep your webhook endpoint fast and asynchronous.
  • Log the full payload during your initial rollout so you can confirm which metadata fields are present in your environment.

Your endpoint can return a minimal success response such as:

HTTP/1.1 200 OK
Content-Type: application/json
{"ok":true}

Use webhooks when:

  • you want near-real-time downstream processing
  • you already operate an HTTP service that can receive callbacks
  • you want to avoid repeated polling for result availability

Use polling with GET /api/result/{id} when:

  • inbound HTTP callbacks are not possible in your environment
  • you need explicit control over fetch timing
  • you want a simpler first integration before moving to event-driven delivery