🔔 Guardlink AI API

REST API Documentation — Image Analysis Endpoint

POST /gdai/vendor_images_event_raw

Submit image frames directly for AI crime-detection analysis. The caller provides a user token together with dealer group / site / zone identifiers; missing user-group, site, and camera rows are created automatically before analysis begins. The request is processed asynchronously and returns immediately with a job ID.

Images: Exactly 4, 6, or 8 image files must be submitted per request. Supported formats: .jpg, .jpeg, .png, .bmp, .webp.

Authentication: Pass the API token as the token form field or as an Authorization: Bearer <token> header.

Rate limit: Minimum 30 seconds between requests per group_id + site_id + zone_id/(per camera) combination.

Content-Type: multipart/form-data

Request Parameters

Parameter Type Required Description
images file[] Required Image files to analyse — exactly 4, 6, or 8 files per request.
token string Required API authentication token. Can also be supplied as Authorization: Bearer <token> header.
group_id string Required Dealer group ID (also used as the dealer ID) — uniquely identifies your organisation.
site_id string Required Vendor dealer site ID — identifies the physical location.
zone_id string Required Vendor dealer zone / camera ID within the site.
site_category string Required Site category — must match one of the values listed in the Accepted site_category Values section below (case-insensitive).
vendor_event_id string Required Your system's original event identifier — stored with the alarm event for end-to-end tracing back to the source event.
site_address string Conditional Physical address of the site (e.g. 123 Main St, New York, NY 10001). Used for automatic timezone resolution. Required if timestamp is not provided.
timestamp string Conditional Local site time in 24-hour format: YYYY-MM-DD HH:MM or YYYY-MM-DD HH:MM:SS. When provided, bypasses address-based timezone lookup. Required if site_address is not provided.
group_name string Optional Human-readable name for your group — defaults to group_<group_id> if omitted.
site_name string Optional Human-readable name for the site — defaults to site_<site_id> if omitted.
zone_name string Optional Human-readable zone / camera label — defaults to zone_<zone_id> if omitted.
detection_sensitive_level integer Optional Detection Sensitivity Level (integer). Controls how strictly person and vehicle detections are filtered before AI analysis. Select the setting based on whether the priority is No Trespassing detection or detailed behavioral analysis.

0 — High Sensitivity (Recommended for No Trespassing)
All per-frame quality filters are skipped to maximise detection sensitivity. If any person or vehicle is detected, the system immediately returns crime_rate: "Maybe" (sends all events as alarm signals based on positive detection of Human/Vehicle target(s)) without running AI inference. This mode prioritises identifying any potential presence in restricted areas and is best suited for No Trespassing applications where early detection is more important than behavioural analysis.

1 — Medium Sensitivity (Content-Focused Analysis)
All per-frame quality filters are skipped, but AI analysis still runs normally. This mode places greater emphasis on the visible video content while relying on less AI-driven inference and interpretation. Recommended when the objective is to analyse what is clearly observable in the footage while minimising assumptions beyond the detected content.

2 — Full AI Inference (Default / Highest Accuracy)
Full filtering mode. All quality filters are applied and the AI performs its complete inference process. This provides the highest accuracy for understanding and classifying observed human actions, behaviours, and events within the video. Best suited for detailed incident analysis and behavioural interpretation. Not recommended for No Trespassing categories, as filtering requirements may reduce sensitivity to initial detections compared to Mode 0.

Accepted site_category Values

Use one of the following values exactly as shown (case-insensitive).

car_dealership car_wash construction gaming_slots gas_station hotel jewelry logistics_warehouse office other residence restaurant_bar retail storage

Request Examples

cURL — Option A: site_address (timezone resolved automatically)
curl -X POST "https://aiguardlink.com/gdai/vendor_images_event_raw" \ -F "token=YOUR_API_TOKEN" \ -F "group_id=your_group_id" \ -F "site_id=your_site_id" \ -F "zone_id=your_zone_id" \ -F "vendor_event_id=your_vendor_event_id" \ -F "site_address=123 Main St, Chicago, IL 60601" \ -F "site_category=retail" \ -F "group_name=My Group" \ -F "site_name=Chicago-BMW Dealer" \ -F "zone_name=Front Door" \ -F "detection_sensitive_level=2" \ -F "images=@frame1.jpg" \ -F "images=@frame2.jpg" \ -F "images=@frame3.jpg" \ -F "images=@frame4.jpg" \ -F "images=@frame5.jpg" \ -F "images=@frame6.jpg" \ -F "images=@frame7.jpg" \ -F "images=@frame8.jpg" # Option B: timestamp (bypasses address-based timezone lookup) curl -X POST "https://aiguardlink.com/gdai/vendor_images_event_raw" \ -F "token=YOUR_API_TOKEN" \ -F "group_id=your_group_id" \ -F "site_id=your_site_id" \ -F "zone_id=your_zone_id" \ -F "vendor_event_id=your_vendor_event_id" \ -F "timestamp=2024-01-15 14:30:00" \ -F "site_category=retail" \ -F "group_name=My Group" \ -F "site_name=Chicago-BMW Dealer" \ -F "zone_name=Front Door" \ -F "detection_sensitive_level=2" \ -F "images=@frame1.jpg" \ -F "images=@frame2.jpg" \ -F "images=@frame3.jpg" \ -F "images=@frame4.jpg" \ -F "images=@frame5.jpg" \ -F "images=@frame6.jpg" \ -F "images=@frame7.jpg" \ -F "images=@frame8.jpg"
Python Example
import requests ENDPOINT = "https://aiguardlink.com/gdai/vendor_images_event_raw" TOKEN = "YOUR_API_TOKEN" image_paths = [f"frame{i}.jpg" for i in range(1, 9)] # exactly 8 frames # Option A — site_address (timezone resolved automatically) files = [("images", (p, open(p, "rb"), "image/jpeg")) for p in image_paths] data = { "token": TOKEN, "group_id": "your_group_id", # also used as dealer ID "site_id": "your_site_id", "zone_id": "your_zone_id", "vendor_event_id": "your_vendor_event_id", "site_address": "123 Main St, Chicago, IL 60601", "site_category": "retail", "group_name": "My Group", "site_name": "Chicago-BMW Dealer", "zone_name": "Front Door", "detection_sensitive_level": 2, # 0=high (Maybe if detected, no AI), 1=medium (no filters, AI runs), 2=normal/default (full filters + AI) } resp = requests.post(ENDPOINT, files=files, data=data) print(resp.json()) # {"status": "accepted", "job_id": "...", ...} # Option B — timestamp (bypasses address-based timezone lookup) files = [("images", (p, open(p, "rb"), "image/jpeg")) for p in image_paths] data_ts = {**data} del data_ts["site_address"] data_ts["timestamp"] = "2024-01-15 14:30:00" # YYYY-MM-DD HH:MM or YYYY-MM-DD HH:MM:SS resp = requests.post(ENDPOINT, files=files, data=data_ts) print(resp.json())
JavaScript (browser fetch)
const ENDPOINT = "https://aiguardlink.com/gdai/vendor_images_event_raw"; // imageFiles — array of exactly 8 File objects (e.g. from an <input type="file">) async function submitFrames(imageFiles, vendorEventId) { const form = new FormData(); form.append("token", "YOUR_API_TOKEN"); form.append("group_id", "your_group_id"); // also used as dealer ID form.append("site_id", "your_site_id"); form.append("zone_id", "your_zone_id"); form.append("vendor_event_id", vendorEventId); // required — for tracing form.append("site_address", "123 Main St, Chicago, IL 60601"); // or use timestamp form.append("site_category", "retail"); form.append("group_name", "My Group"); form.append("site_name", "Chicago-BMW Dealer"); form.append("zone_name", "Front Door"); form.append("detection_sensitive_level", "2"); // 0=high (Maybe, no AI), 1=medium (no filters, AI runs), 2=normal/default imageFiles.forEach(f => form.append("images", f)); const resp = await fetch(ENDPOINT, { method: "POST", body: form }); const data = await resp.json(); if (!resp.ok) { console.error("API error:", data.message); return null; } return data; // data.job_id — results appear in All Activities }

Response

202 Accepted Job queued successfully — results appear in All Activities once processed
{ "status": "accepted", "message": "Handle images analysis job scheduled", "job_id": "raw_user42_g001_site01_zone01_3f8a...", "total_files": 8, "total_frames": 8, "total_file_size": 819200, "code": 202 }
400 Bad Request Invalid parameters, wrong image count, unsupported file type, or invalid site_category
{ "status": "error", "message": "Missing required parameter(s): vendor_event_id", "code": 400 }
401 Unauthorized Missing or invalid token
{ "status": "error", "message": "Invalid or expired token", "code": 401 }
503 Service Unavailable GPU inference queue is full — retry after a short delay
{ "status": "error", "message": "Server busy — try again shortly", "code": 503 }
Rate Limit — 30 seconds between requests
The API enforces a minimum 30-second cooldown per group_id + site_id + zone_id / (per camera) combination. Requests sent before the cooldown expires will be rejected.
Alarm Events: When the AI detects suspicious activity or a possible crime, an alarm event is automatically stored in your account and visible under All Activities. The vendor_event_id you supply is saved alongside the event so you can correlate GuardLink AI results back to your own event records.

GET /api/events/export

Fetch a single alarm event by its job_id and return it in a standardised JSON format for external integration. When media_type=0 (default), the response includes lightweight per-frame detection box JSON — frame filenames and bounding box coordinates for every detected category — without transferring any image data.

Authentication: Pass the API token as Authorization: Bearer <token> header or as a ?token= query parameter. The token determines which account's events can be accessed — you can only retrieve events that belong to your account.

Rate limit: The same token + job_id combination is blocked for 10 minutes after the first successful call. Repeated requests within that window return 429.

Request Parameters

Parameter Type Required Description
job_id string Required The job ID returned when the event was submitted (e.g. raw_user42_g001_site01_zone01_3f8a…).
token string Conditional API authentication token. Can also be supplied as Authorization: Bearer <token> header. One of the two is required.
media_type integer Optional Controls what is returned in the media field. Default: 0.

0 — Per-frame box JSON: frame filenames and detection bounding boxes for all categories (person, vehicle, weapon), with no image data transferred.

Any value other than 0 requires admin authority and will be rejected with 403 Forbidden.

Request Examples

cURL — per-frame box JSON (default)
curl "https://aiguardlink.com/api/events/export?job_id=raw_user42_g001_site01_zone01_3f8a" \ -H "Authorization: Bearer YOUR_API_TOKEN" # Token as query param curl "https://aiguardlink.com/api/events/export?job_id=raw_user42_g001_site01_zone01_3f8a&token=YOUR_API_TOKEN"
Python Example
import requests ENDPOINT = "https://aiguardlink.com/api/events/export" TOKEN = "YOUR_API_TOKEN" JOB_ID = "raw_user42_g001_site01_zone01_3f8a" resp = requests.get(ENDPOINT, params={"job_id": JOB_ID}, headers={"Authorization": f"Bearer {TOKEN}"}) data = resp.json() print(data["server"]["ai_decision"]) # e.g. "Maybe" print(data["vendor"]["camera_name"]) # Iterate per-frame box data for frame in data["media"]["frames"]: print(frame["name"]) # "frame_00.jpg" print(frame["box_file"]) # "frame_00_box.json" print(frame["boxes"]) # {"person": [[x1,y1,x2,y2,conf],...], "vehicle": [...]}
JavaScript (browser fetch)
const ENDPOINT = "https://aiguardlink.com/api/events/export"; async function fetchEvent(jobId) { const url = new URL(ENDPOINT); url.searchParams.set("job_id", jobId); const resp = await fetch(url, { headers: { "Authorization": "Bearer YOUR_API_TOKEN" } }); const data = await resp.json(); if (!data.success) { console.error("Error:", data.error); return null; } console.log("AI decision:", data.server.ai_decision); // Per-frame box data — no image bytes transferred data.media?.frames.forEach(frame => { console.log(frame.name, frame.box_file, frame.boxes); }); return data; } fetchEvent("raw_user42_g001_site01_zone01_3f8a");

Response

Every response — success or error — returns the same top-level shape:

{ "success": 1, // 1 = success, 0 = error "job_id": "...", // echoed back from request (null on auth errors) "error": null, // human-readable error string, or null on full success "vendor": { ... }, // vendor / camera metadata (null on error) "server": { ... }, // AI analysis results (null on error) "media": { ... } // per-frame box JSON (null on error) }
200 OK Event found — full metadata and optional media returned
{ "success": 1, "job_id": "raw_user42_g001_site01_zone01_3f8a", "error": null, "vendor": { "vendor_time": "2024-01-15 14:30:00", "vendor_event_id": "EVT-001", "dealer_group_id": "G001", "dealer_site_id": "S001", "dealer_zone_id": "Z001", "group_name": "My Group", "site_name": "Chicago-BMW Dealer", "camera_name": "Front Door" }, "server": { "crime_rate": 1, "has_motion": true, "has_person": true, "has_vehicle": false, "ai_analysis_called": true, "ai_analysis_time": 3.21, "ai_engine": "P-VL", "ai_decision_method": "C1", "ai_decision_time": "2024-01-15 14:30:05", "ai_description": "A person is seen walking near the entrance after hours...", "ai_decision": "Maybe", "ai_decision_indicators": ["person detected", "after hours"] }, "media": { "type": "boxes", "frames": [ { "name": "frame_00.jpg", "box_file": "frame_00_box.json", "boxes": { "person": [[36.4, 100.1, 55.2, 159.4, 0.696]], "vehicle": [[528.0, 155.3, 703.3, 298.1, 0.961], [222.2, 90.4, 467.5, 224.0, 0.945]], "weapon": [] } }, { "name": "frame_01.jpg", "box_file": "frame_01_box.json", "boxes": { "person": [[40.1, 102.1, 61.6, 173.1, 0.833]], "vehicle": [[527.6, 155.3, 703.3, 298.1, 0.962]], "weapon": [] } } ] } }
200 OK Partial success — event returned but manifest missing; media.frames[].boxes will be empty objects
{ "success": 1, "job_id": "raw_user42_g001_site01_zone01_3f8a", "error": "frames_atlas_manifest.json not found; boxes unavailable", "vendor": { ... }, "server": { ... }, "media": { "type": "boxes", "frames": [ {"name": "frame_00.jpg", "box_file": "frame_00_box.json", "boxes": {}}, ... ] } }
403 Forbidden Non-zero media_type requires admin authority
{ "success": 0, "job_id": "raw_user42_g001_site01_zone01_3f8a", "error": "Admin authority required for media_type != 0", "vendor": null, "server": null, "media": null }
401 Unauthorized Missing or invalid token
{ "success": 0, "job_id": null, "error": "Authorization: Bearer token or ?token= is required", "vendor": null, "server": null, "media": null }
404 Not Found No event with the given job_id in your account
{ "success": 0, "job_id": "raw_user42_g001_site01_zone01_3f8a", "error": "No event found for job_id='raw_user42_g001_site01_zone01_3f8a'", "vendor": null, "server": null, "media": null }
429 Too Many Requests Same token + job_id already requested within the last 10 minutes
{ "success": 0, "job_id": null, "error": "Already requested within 10 minutes", "vendor": null, "server": null, "media": null }

Response Fields

Field Type Description
vendor
vendor_timestring Local site time at which the event was recorded.
vendor_event_idstring The original event ID you supplied when submitting the event.
dealer_group_idstring Dealer group identifier.
dealer_site_idstring Dealer site identifier.
dealer_zone_idstring Dealer zone / camera identifier.
group_namestring Human-readable group name.
site_namestring Human-readable site name.
camera_namestring Camera label within the site.
server
crime_rateinteger 0 = No, 1 = Maybe, 2 = Yes.
has_motionboolean Motion was detected in the frame sequence.
has_personboolean AI detected at least one person.
has_vehicleboolean AI detected at least one vehicle.
ai_analysis_calledboolean Whether AI was invoked for this event.
ai_analysis_timefloat Time in seconds the AI inference took.
ai_enginestring AI model used.
ai_decision_methodstring Decision routing: Local, C1, C2, C21, Cbr.
ai_decision_timestring Timestamp when the AI classification completed.
ai_descriptionstring Scene description generated by AI.
ai_decisionstring Final classification: No, Maybe, or Yes.
ai_decision_indicatorsarray List of factors that influenced the AI decision.
media (media_type=0)
typestring Always "boxes".
framesobject[] One entry per frame (up to 60), in manifest order.
frames[].namestring Frame filename, e.g. "frame_00.jpg".
frames[].box_filestring Corresponding box file name, e.g. "frame_00_box.json".
frames[].boxesobject Detection boxes keyed by category ("person", "vehicle", "weapon"). Each value is an array of boxes for that frame: [[x1, y1, x2, y2, confidence], …]. Coordinates are in the frame's pixel space. Empty array when no detections for that category. Empty object when frames_atlas_manifest.json is unavailable.
Rate Limit — 10 minutes per token + job_id
After a successful export call, the same token + job_id combination is blocked for 10 minutes at the gateway level. Save the response — repeated calls within that window will receive a 429 response without hitting the backend.