Argus

API reference

Authentication

All /api/* routes require an X-API-Key header, or a valid browser session (for same-origin UI calls — no header needed when calling from the browser while logged in).

CORS: Argus includes CORSMiddleware with allow_origins=["*"], so browser-side calls from other LAN hosts work without a proxy. Authentication is still enforced via X-API-Key on every request.

To get an API key:

  1. Sign in at http://localhost:8100
  2. Go to Account → click Create key, choose an environment and type a label → copy the key (shown once)

Interactive docs (requires a running instance): http://localhost:8100/docs

Discovery

These endpoints require no API key.

# Health — status, version, active provider, loaded models
curl http://localhost:8100/api/health

# Capabilities — detection types, supported formats, pagination limits, integration features
curl http://localhost:8100/api/capabilities

Call /api/capabilities before integrating so a client can adapt instead of hardcoding what's available.

Stats

GET /api/stats

Dashboard counts and storage summary in one round-trip.

curl -H "X-API-Key: argus_..." http://localhost:8100/api/stats
# → {"identities": 12, "face_identities": 8, "object_identities": 4,
#    "detections": 348, "face_detections": 210, "object_detections": 138,
#    "source_images": 95, "pending_review": 14,
#    "storage": "1.2 GB", "storage_free": "45.3 GB",
#    "storage_bytes": 1288490188, "storage_free_bytes": 48644997120}

Detect

Every detect endpoint accepts exactly one of: a file multipart upload, an image_url field, or an image_base64 field (raw base64 or a data:image/...;base64, URI). Zero or more than one is a 400.

Supported formats: JPEG, PNG, WEBP, BMP, GIF (first frame), TIFF, HEIC/HEIF, AVIF, MPO (first frame).

Detect faces

POST /api/detect/faces
curl -X POST \
  -H "X-API-Key: argus_..." \
  -F "file=@photo.jpg" \
  http://localhost:8100/api/detect/faces

Detect objects

POST /api/detect/objects
curl -X POST \
  -H "X-API-Key: argus_..." \
  -F "file=@photo.jpg" \
  http://localhost:8100/api/detect/objects

Detect all (faces + objects)

POST /api/detect/all
curl -X POST \
  -H "X-API-Key: argus_..." \
  -F "file=@photo.jpg" \
  http://localhost:8100/api/detect/all

Detect with an inline label

When label is provided, the highest-confidence face is confirmed as that person and enrolled immediately, bypassing the review queue. Any other faces are stored as pending.

curl -X POST \
  -H "X-API-Key: argus_..." \
  -H "Content-Type: application/json" \
  -d '{"image_url": "http://...", "label": "Noah"}' \
  http://localhost:8100/api/detect/faces

Re-detect without duplicates

Argus deduplicates source images by content hash, so re-detecting the same image reuses its source_image_id. Pass replace=true to clear prior detections of the type being run before writing new ones.

curl -X POST \
  -H "X-API-Key: argus_..." \
  -F "file=@photo.jpg" \
  -F "replace=true" \
  http://localhost:8100/api/detect/all

Bulk detection

Detect faces and/or objects across many images in a single call. Each image can be a URL, file upload, or base64. One bad image never fails the others.

POST /api/detect/bulk

Sync (waits for all results):

curl -X POST \
  -H "X-API-Key: argus_..." \
  -H "Content-Type: application/json" \
  -d '{"image_urls": ["http://cam1/snap.jpg", "http://cam2/snap.jpg"], "type": "faces"}' \
  http://localhost:8100/api/detect/bulk

Async (returns job id immediately, max 200 images per call):

curl -X POST \
  -H "X-API-Key: argus_..." \
  -H "Content-Type: application/json" \
  -d '{"image_urls": ["http://cam1/snap.jpg", "..."], "type": "all"}' \
  "http://localhost:8100/api/detect/bulk?async=true"
# → {"job_id": 7, "status": "pending", "total": 50}

Register a job.done webhook to be notified instead of polling.

Enroll

Add a reference face for a person. The image must contain exactly one face.

POST /api/faces/enroll
curl -X POST \
  -H "X-API-Key: argus_..." \
  -F "name=Noah" \
  -F "file=@noah.jpg" \
  http://localhost:8100/api/faces/enroll
# → {"identity_id": 3, "label": "Noah", "embedding_id": 17, "enrolled": true}

Enroll into an existing identity

Add an additional reference photo to an existing identity (by id).

POST /api/identities/{id}/enroll
curl -X POST \
  -H "X-API-Key: argus_..." \
  -F "file=@another_noah.jpg" \
  http://localhost:8100/api/identities/3/enroll

Enroll from an existing detection

Promote a stored detection's embedding into the reference set. The detection must already be assigned to an identity; it must be a face type with a stored embedding.

POST /api/detections/{id}/enroll
curl -X POST \
  -H "X-API-Key: argus_..." \
  http://localhost:8100/api/detections/42/enroll
# → {"detection_id": 42, "identity_id": 3, "embedding_id": 19, "enrolled": true}

Remove a detection's enrollment

Revoke a detection's reference enrollment without deleting the detection itself.

DELETE /api/detections/{id}/enroll
curl -X DELETE \
  -H "X-API-Key: argus_..." \
  http://localhost:8100/api/detections/42/enroll
# → {"detection_id": 42, "removed": 1}

Face embeddings

Enrolled face reference embeddings. A person's identity can have multiple embeddings — one per enrolled photo. Each embedding is tagged with the model that generated it and is only used for matching when that model is active.

List embeddings

GET /api/face-embeddings
curl -H "X-API-Key: argus_..." \
  "http://localhost:8100/api/face-embeddings?identity_id=3"
# → {"items": [{"id": 17, "identity_id": 3, "label": "Noah",
#               "model_id": 1, "model_name": "buffalo_l",
#               "detection_id": 42, "source_image_id": 7,
#               "created_at": "2026-01-10T08:00:00Z",
#               "crop_url": "/media/crops/abc.jpg"}]}

Optional query params: identity_id, model_id.

Get one embedding

GET /api/face-embeddings/{id}
curl -H "X-API-Key: argus_..." http://localhost:8100/api/face-embeddings/17

Delete an embedding

Removes a single reference embedding; does not delete the associated detection.

DELETE /api/face-embeddings/{id}
curl -X DELETE \
  -H "X-API-Key: argus_..." \
  http://localhost:8100/api/face-embeddings/17
# → {"deleted": 17}

Identify (1:N, read-only)

Detects faces and matches them against enrolled people without storing anything (no crops, detections, or review entries). Returns best match per face plus ranked suggestions.

POST /api/identify
curl -X POST \
  -H "X-API-Key: argus_..." \
  -F "file=@group.jpg" \
  http://localhost:8100/api/identify
# → {"threshold": 0.5, "faces": [
#      {"bbox": {...}, "confidence": 0.99, "identity_id": 2, "label": "Noah",
#       "similarity": 0.71, "suggestions": [...], "age": 9, "gender": "M", "pose": [...]}]}

Optional threshold (override) and top_n (suggestion count) via form field, JSON, or query param.

Test (read-only)

Runs the face and object engines and returns bounding boxes, counts, and for each face the best matching enrolled person. Stores nothing and enrolls nothing. Also available as a UI page at /test.

POST /api/test
curl -X POST \
  -H "X-API-Key: argus_..." \
  -F "file=@photo.jpg" \
  "http://localhost:8100/api/test?type=all"
# → {"faces": [{"bbox": {...}, "confidence": 0.95, "label": "Noah", "similarity": 0.87,
#               "identity_id": 2, "age": 30, "gender": "F", "pose": [...]}],
#    "objects": [{"bbox": {...}, "confidence": 0.9, "class_name": "person", "class_id": 0}],
#    "counts": {"faces": 1, "objects": 1},
#    "available": {"faces": true, "objects": true}}

?type=faces|objects|all (default all). An engine with no active model is skipped rather than erroring.

Batch test

Test many images in one call, still storing nothing. Per-image results; one bad image never fails the rest (max 100 per call).

POST /api/test/batch
curl -X POST \
  -H "X-API-Key: argus_..." \
  -F "type=all" -F "file=@a.jpg" -F "file=@b.jpg" \
  http://localhost:8100/api/test/batch
# → {"total": 2, "type": "all", "results": [
#      {"index": 0, "filename": "a.jpg", "faces": [...], "objects": [...], ...},
#      {"index": 1, "filename": "b.jpg", "error": "..."}]}

Verify (1:1)

Compares two images directly. Stores nothing.

POST /api/verify
curl -X POST \
  -H "X-API-Key: argus_..." \
  -F "file1=@a.jpg" -F "file2=@b.jpg" \
  http://localhost:8100/api/verify
# → {"similarity": 0.83, "match": true, "threshold": 0.5,
#    "face1": {"bbox": {...}, "confidence": 0.99, "age": 31, "gender": "F", "pose": [...]},
#    "face2": {...}}

Each image is one of file{1,2} / image{1,2}_url / image{1,2}_base64. Optional threshold override.

Facial attributes

Face detections include age, gender ("M"/"F"), and pose ([pitch, yaw, roll] in degrees) when the active model provides them — all three bundled packs (buffalo_l, buffalo_s, antelopev2) do. Any value the model doesn't produce comes back as null. These fields are API-only and not displayed in the UI.

Identities

An identity is a named person or object class. Every detection is either unidentified or assigned to an identity. Identities scoped to the caller's user and environment.

List

GET /api/identities
curl -H "X-API-Key: argus_..." \
  "http://localhost:8100/api/identities?type=face&limit=50"
# → {"items": [{"id": 3, "type": "face", "label": "Alice",
#               "external_ref": "person_alice", "cover_detection_id": 101,
#               "created_at": "2026-01-10T08:00:00Z"}],
#    "next_cursor": "Alice", "has_more": false}

Optional params: type (face | object), q (name search), external_ref (exact match), cursor, limit. Omit limit to get all identities unpaginated.

Summary (with counts and thumbnails)

GET /api/identities/summary
curl -H "X-API-Key: argus_..." \
  "http://localhost:8100/api/identities/summary?type=face"
# → {"items": [{"id": 3, "type": "face", "label": "Alice",
#               "external_ref": "person_alice", "cover_detection_id": 101,
#               "created_at": "...", "detection_count": 42,
#               "embedding_count": 5,
#               "thumbnail_url": "/media/crops/abc123.jpg"}],
#    "next_cursor": "Alice", "has_more": true, "total": 8}

Same filters as /api/identities. Used by the dashboard grid — includes counts and thumbnail URL per identity.

Get one

GET /api/identities/{id}
curl -H "X-API-Key: argus_..." http://localhost:8100/api/identities/3
# → {"id": 3, "type": "face", "label": "Alice", "external_ref": "person_alice",
#    "cover_detection_id": 101, "created_at": "...",
#    "detection_count": 42, "embedding_count": 5,
#    "pending_review_count": 2, "thumbnail_url": "/media/crops/abc123.jpg"}

Create

POST /api/identities
curl -X POST \
  -H "X-API-Key: argus_..." \
  -H "Content-Type: application/json" \
  -d '{"label": "Alice", "type": "face", "external_ref": "person_alice"}' \
  http://localhost:8100/api/identities
# → 201 {"id": 3, "type": "face", "label": "Alice", "external_ref": "person_alice"}

Returns 409 if a label + type identity already exists in this environment.

Rename

PUT /api/identities/{id}
curl -X PUT \
  -H "X-API-Key: argus_..." \
  -H "Content-Type: application/json" \
  -d '{"label": "Alice Smith"}' \
  http://localhost:8100/api/identities/3
# → {"id": 3, "label": "Alice Smith"}

Set external_ref

PUT /api/identities/{id}/external_ref
curl -X PUT \
  -H "X-API-Key: argus_..." \
  -H "Content-Type: application/json" \
  -d '{"external_ref": "my-app-person-7"}' \
  http://localhost:8100/api/identities/3/external_ref
# → {"id": 3, "external_ref": "my-app-person-7"}

Set cover photo

PUT /api/identities/{id}/cover
curl -X PUT \
  -H "X-API-Key: argus_..." \
  -H "Content-Type: application/json" \
  -d '{"detection_id": 101}' \
  http://localhost:8100/api/identities/3/cover
# → {"identity_id": 3, "cover_detection_id": 101}

The detection must belong to this identity.

Delete

Deletes the identity and all its detections, crops, and embeddings.

DELETE /api/identities/{id}
curl -X DELETE \
  -H "X-API-Key: argus_..." \
  http://localhost:8100/api/identities/3
# → 204 No Content

Bulk delete

DELETE /api/identities
curl -X DELETE \
  -H "X-API-Key: argus_..." \
  -H "Content-Type: application/json" \
  -d '{"identity_ids": [3, 5, 7]}' \
  http://localhost:8100/api/identities
# → {"deleted": 3}

Merge

Combine two identities when the same person was enrolled under different names. All detections and enrolled face references are moved to the target; the source is deleted.

POST /api/identities/{id}/merge
curl -X POST \
  -H "X-API-Key: argus_..." \
  -H "Content-Type: application/json" \
  -d '{"into": 5}' \
  http://localhost:8100/api/identities/12/merge
# → {"merged_into": 5, "deleted": 12}

Gallery

Cursor-paginated detection crops for an identity. Used by the identity gallery page.

GET /api/identities/{id}/gallery
curl -H "X-API-Key: argus_..." \
  "http://localhost:8100/api/identities/3/gallery?limit=30"
# → {"items": [{"detection_id": 101, "crop_url": "/media/crops/abc.jpg",
#               "source_image_id": 7, "detected_at": "...",
#               "confidence": 0.98, "review_status": "confirmed"}],
#    "next_cursor": "2026-01-15T10:30:00Z_101", "has_more": true}

Pagination: ?cursor=<detected_at>_<id>&limit=N. Optional sort: newest (default) | oldest.

Rejected detections

Detections that were rejected from this identity (for re-review or deletion).

GET /api/identities/{id}/rejected
curl -H "X-API-Key: argus_..." \
  http://localhost:8100/api/identities/3/rejected
# → {"items": [{"detection_id": 88, "crop_url": "...", ...}]}

Detections

Get one

GET /api/detections/{id}
curl -H "X-API-Key: argus_..." http://localhost:8100/api/detections/42
# → {"id": 42, "type": "face", "source_image_id": 7,
#    "bbox": {"x": 120, "y": 80, "w": 60, "h": 75}, "confidence": 0.98,
#    "identity_id": 3, "label": "Alice", "review_status": "confirmed",
#    "crop_url": "/media/crops/abc.jpg", "detected_at": "..."}

Relabel

Assign or correct a detection's identity. Works for both face and object detections. This is the single endpoint shared by all "fix this label" UI surfaces.

PUT /api/detections/{id}/label
# Relabel to a name (creates identity if it doesn't exist)
curl -X PUT \
  -H "X-API-Key: argus_..." \
  -H "Content-Type: application/json" \
  -d '{"label": "Sarah"}' \
  http://localhost:8100/api/detections/42/label

# Assign to an existing identity by id
curl -X PUT \
  -H "X-API-Key: argus_..." \
  -H "Content-Type: application/json" \
  -d '{"identity_id": 5}' \
  http://localhost:8100/api/detections/42/label

Batch relabel

Relabel many detections in one call. Per-item results; one bad item never fails the rest.

POST /api/detections/label
curl -X POST \
  -H "X-API-Key: argus_..." \
  -H "Content-Type: application/json" \
  -d '{"items": [{"detection_id": 1, "label": "park bench"},
                 {"detection_id": 2, "identity_id": 5}]}' \
  http://localhost:8100/api/detections/label
# → {"results": [{"detection_id": 1, "ok": true},
#                {"detection_id": 2, "ok": true}]}

Batch read

Current state of many detections in one round-trip. Unknown ids are simply absent from the response.

POST /api/detections/query
curl -X POST \
  -H "X-API-Key: argus_..." \
  -H "Content-Type: application/json" \
  -d '{"detection_ids": [1, 2, 3]}' \
  http://localhost:8100/api/detections/query
# → {"items": [{"id": 1, ...}, {"id": 2, ...}]}

Dismiss (remove from review without labeling)

Moves a detection out of the review queue without assigning an identity.

POST /api/detections/dismiss
curl -X POST \
  -H "X-API-Key: argus_..." \
  -H "Content-Type: application/json" \
  -d '{"detection_ids": [42, 43]}' \
  http://localhost:8100/api/detections/dismiss
# → {"dismissed": 2}

Delete a detection

DELETE /api/detections/{id}
curl -X DELETE \
  -H "X-API-Key: argus_..." \
  http://localhost:8100/api/detections/42
# → {"deleted": 42, "source_image_discarded": false}

If this was the last detection on its source image, the source image (and its file if no other row references it) is auto-discarded. source_image_discarded is true in that case.

Bulk delete detections

POST /api/detections/delete
curl -X POST \
  -H "X-API-Key: argus_..." \
  -H "Content-Type: application/json" \
  -d '{"detection_ids": [40, 41, 42]}' \
  http://localhost:8100/api/detections/delete
# → {"deleted": 3, "source_images_discarded": 1}

Unknown (unidentified face detections)

Paginated list of face detections with no identity assigned.

GET /api/detections/unknown
curl -H "X-API-Key: argus_..." \
  "http://localhost:8100/api/detections/unknown?limit=30"
# → {"items": [...], "next_cursor": "...", "has_more": true}

Review queue

The review queue holds face detections that matched an enrolled person but fell below the auto-confirm threshold, or that have no match at all. See Concepts for threshold details.

List (pending review)

GET /api/review
curl -H "X-API-Key: argus_..." \
  "http://localhost:8100/api/review?limit=30"
# → {"items": [{"detection_id": 303, "crop_url": "...",
#               "source_image_id": 10, "source_image_url": "...",
#               "confidence": 0.8514,
#               "bbox": {"x": 90, "y": 60, "w": 55, "h": 70},
#               "detected_at": "...",
#               "current_identity": null,
#               "suggested_matches": [
#                 {"identity_id": 3, "label": "Alice", "similarity": 0.7823}]}],
#    "next_cursor": "0.8514_303", "has_more": false}

Pagination: ?cursor=<confidence>_<id>&limit=N. Items are sorted by confidence descending. Optional has_suggestion=true to show only items with at least one ranked match.

Count

GET /api/review/count
curl -H "X-API-Key: argus_..." http://localhost:8100/api/review/count
# → {"count": 14}

Optional has_suggestion=true to count only items with a suggested match.

Confirm

Mark a detection as confirmed, accepting the current or a new identity assignment.

POST /api/review/{id}/confirm
curl -X POST \
  -H "X-API-Key: argus_..." \
  -H "Content-Type: application/json" \
  -d '{"identity_id": 3}' \
  http://localhost:8100/api/review/303/confirm
# → {"detection_id": 303, "review_status": "confirmed", "identity_id": 3, "enrolled": true}

Human confirmations always enroll the embedding unconditionally, regardless of detection quality.

Unassign

Remove the current identity assignment without deleting the detection — returns it to the unidentified pool.

POST /api/review/{id}/unassign
curl -X POST \
  -H "X-API-Key: argus_..." \
  http://localhost:8100/api/review/303/unassign
# → {"detection_id": 303, "review_status": "pending"}

Reject

Mark a detection as rejected from its current identity (removes assignment, flags as rejected).

POST /api/review/{id}/reject
curl -X POST \
  -H "X-API-Key: argus_..." \
  http://localhost:8100/api/review/303/reject
# → {"detection_id": 303, "review_status": "rejected"}

Restore

Move a rejected detection back to pending review.

POST /api/review/{id}/restore
curl -X POST \
  -H "X-API-Key: argus_..." \
  http://localhost:8100/api/review/303/restore
# → {"detection_id": 303, "review_status": "pending"}

Reassign

Assign a detection to a different identity (or create a new one by name).

POST /api/review/{id}/reassign
curl -X POST \
  -H "X-API-Key: argus_..." \
  -H "Content-Type: application/json" \
  -d '{"identity_id": 5}' \
  http://localhost:8100/api/review/303/reassign
# → {"detection_id": 303, "review_status": "confirmed", "identity_id": 5}

Bulk review actions

POST /api/review/bulk
curl -X POST \
  -H "X-API-Key: argus_..." \
  -H "Content-Type: application/json" \
  -d '{"detection_ids": [303, 304, 305], "action": "confirm", "identity_id": 3}' \
  http://localhost:8100/api/review/bulk
# → {"processed": 3, "failed": 0}

action is one of: confirm, reject, unassign, restore, reassign. identity_id is required for confirm and reassign.

Mismatches

Confirmed face detections whose embedding scores poorly against their current identity's representative — likely mislabels. Sorted worst-first.

GET /api/review/mismatches
curl -H "X-API-Key: argus_..." \
  "http://localhost:8100/api/review/mismatches?threshold=0.5"
# → {"items": [{"detection_id": 42, "crop_url": "...",
#               "source_image_id": 7, "confidence": 0.91,
#               "bbox": {...}, "detected_at": "...",
#               "current_identity": {"identity_id": 3, "label": "Alice"},
#               "similarity": 0.31}],
#    "count": 1, "threshold": 0.5}

Optional threshold override (default: the active face.match_threshold setting).

Dismiss a mismatch

POST /api/review/mismatches/{id}/dismiss
curl -X POST \
  -H "X-API-Key: argus_..." \
  http://localhost:8100/api/review/mismatches/42/dismiss
# → {"detection_id": 42, "mismatch_reviewed": true}

Bulk dismiss mismatches

POST /api/review/mismatches/dismiss
curl -X POST \
  -H "X-API-Key: argus_..." \
  -H "Content-Type: application/json" \
  -d '{"detection_ids": [42, 43, 44]}' \
  http://localhost:8100/api/review/mismatches/dismiss
# → {"dismissed": 3}

Clusters (Suggested people)

Unsupervised groupings of unidentified face detections. See Concepts for how clustering works.

List clusters

GET /api/clusters
curl -H "X-API-Key: argus_..." \
  "http://localhost:8100/api/clusters?threshold=0.5"
# → {"clusters": [{"cluster_id": "cluster_001",
#                  "size": 12,
#                  "items": [{"detection_id": 55, "crop_url": "...",
#                             "confidence": 0.97, "detected_at": "..."},
#                            ...]}],
#    "total_unclustered": 4, "threshold": 0.5}

Optional threshold (default: face.cluster_threshold setting), limit.

Count

GET /api/clusters/count
curl -H "X-API-Key: argus_..." http://localhost:8100/api/clusters/count
# → {"count": 7, "threshold": 0.5}

Jobs

Async operations (bulk detection, bulk reprocess) run as jobs. Poll for status or register a job.done webhook.

List jobs

GET /api/jobs
curl -H "X-API-Key: argus_..." http://localhost:8100/api/jobs
# → {"items": [{"id": 7, "type": "bulk_detect", "status": "done",
#               "total": 50, "done": 50, "failed": 0,
#               "created_at": "...", "finished_at": "..."}]}

Get one job

GET /api/jobs/{id}
curl -H "X-API-Key: argus_..." http://localhost:8100/api/jobs/7
# → {"id": 7, "type": "bulk_detect", "status": "running",
#    "total": 50, "done": 23, "failed": 1,
#    "created_at": "...", "finished_at": null}

status is one of: pending · running · done · failed.

Delete a job

Remove a completed job record. Does not cancel a running job.

DELETE /api/jobs/{id}
curl -X DELETE \
  -H "X-API-Key: argus_..." \
  http://localhost:8100/api/jobs/7
# → 204 No Content

Images

List

GET /api/images

See Image filtering for the full query parameter reference.

curl -H "X-API-Key: argus_..." \
  "http://localhost:8100/api/images?type=face&limit=30"
# → {"items": [{"id": 7, "external_ref": "img_abc123",
#               "file_path": "abc456.jpg", "width": 1920, "height": 1080,
#               "uploaded_at": "...", "detection_count": 3,
#               "source_image_url": "/media/sources/abc456.jpg"}],
#    "next_cursor": "...", "has_more": true}

Get faces for an image

All face detections for a source image, including bboxes, labels, embeddings, and attributes.

GET /api/images/{id}/faces
curl -H "X-API-Key: argus_..." \
  http://localhost:8100/api/images/7/faces
# → {"source_image_id": 7, "external_ref": "img_abc123",
#    "width": 1920, "height": 1080, "uploaded_at": "...",
#    "source_image_url": "/media/sources/abc456.jpg",
#    "scene_tags": [],
#    "faces": [{"detection_id": 101,
#               "bbox": {"x": 120, "y": 80, "w": 60, "h": 75},
#               "confidence": 0.98, "identity_id": 3, "label": "Alice",
#               "crop_url": "/media/crops/abc123.jpg",
#               "review_status": "confirmed", "embedding_source": "aligned",
#               "age": 32, "gender": "F", "pose": [1.2, -0.3, 0.1]}]}

Create a manual detection

Add a hand-drawn bounding box to an existing source image. Use this when the automatic detector missed a face or object you want to tag.

POST /api/images/{id}/detections
curl -X POST \
  -H "X-API-Key: argus_..." \
  -H "Content-Type: application/json" \
  -d '{"type": "face", "bbox": {"x": 120, "y": 80, "w": 60, "h": 75},
       "label": "Alice"}' \
  http://localhost:8100/api/images/7/detections
# → {"detection_id": 210, "identity_id": 3, "label": "Alice",
#    "crop_url": "/media/crops/manual_xyz.jpg", "is_manual": true}

Reprocess

Re-run detection on a previously stored image using the currently active models. Useful after switching to a better model.

POST /api/images/{id}/reprocess
# Re-detect all (keeps existing)
curl -X POST \
  -H "X-API-Key: argus_..." \
  "http://localhost:8100/api/images/42/reprocess?type=all"

# Replace existing face detections
curl -X POST \
  -H "X-API-Key: argus_..." \
  "http://localhost:8100/api/images/42/reprocess?type=faces&replace=true"

# Async
curl -X POST \
  -H "X-API-Key: argus_..." \
  "http://localhost:8100/api/images/42/reprocess?type=all&replace=true&async=true"
# → {"job_id": 8, "status": "pending"}

Bulk reprocess

Re-run detection on a set of source images, using the currently active models.

POST /api/images/reprocess
curl -X POST \
  -H "X-API-Key: argus_..." \
  -H "Content-Type: application/json" \
  -d '{"source_image_ids": [7, 8, 9], "type": "all", "replace": true}' \
  "http://localhost:8100/api/images/reprocess?async=true"
# → {"job_id": 9, "status": "pending", "total": 3}

Delete an image

Deletes the source image row, all its detections, and all crops. The source file is only deleted from disk if no other source image row references the same content hash.

DELETE /api/images/{id}
curl -X DELETE \
  -H "X-API-Key: argus_..." \
  http://localhost:8100/api/images/42
# → {"source_image_id": 42, "detections_deleted": 5, "crops_removed": 5}

Image filtering

Query the source image list with filters. All params are optional and combinable.

ParamTypeDescription
identity_idint (repeatable)Images containing this identity (AND across multiple)
typeface | objectOnly images with detections of this type
external_refstringExact match on the caller's own id
since / untilISO timestampUpload date range
no_detectionsboolImages with zero detections
no_tagged_facesboolImages where no face has been identified
no_cropsboolImages with no stored crop files
has_manual_detectionsboolImages with at least one manually drawn detection
sortstringnewest | oldest | most_detections | fewest_detections
cursor / limitstring / intCursor pagination
# Images containing identity 5
curl -H "X-API-Key: argus_..." \
  "http://localhost:8100/api/images?identity_id=5"

# Face-detection images from a date range
curl -H "X-API-Key: argus_..." \
  "http://localhost:8100/api/images?type=face&since=2025-01-01T00:00:00&until=2025-12-31T23:59:59"

Companion endpoints: GET /api/images/count returns the matching total; GET /api/images/ids returns all matching IDs (no pagination, for select-all operations).

Models

Manage face and object detection models. Models can be downloaded, activated, and hot-swapped without restarting. All model management is also available via the Models page in the UI.

# List all models
curl -H "X-API-Key: argus_..." http://localhost:8100/api/models

# Get one model
curl -H "X-API-Key: argus_..." http://localhost:8100/api/models/1

# Download a model (returns job_id)
curl -X POST \
  -H "X-API-Key: argus_..." \
  http://localhost:8100/api/models/1/download

# Activate a model (hot-swaps in-process, no restart needed)
curl -X PUT \
  -H "X-API-Key: argus_..." \
  http://localhost:8100/api/models/1/activate

Activating a model replaces the running engine live. In-flight detection calls are not interrupted — a lock ensures they complete against the old model before the swap.

Settings

All settings are live — changes take effect immediately. See the Settings reference for the full list of keys and defaults.

# Get a setting
curl -H "X-API-Key: argus_..." \
  http://localhost:8100/api/settings/face.match_threshold
# → {"key": "face.match_threshold", "value": 0.5}

# Update a setting
curl -X PUT \
  -H "X-API-Key: argus_..." \
  -H "Content-Type: application/json" \
  -d '{"value": 0.6}' \
  http://localhost:8100/api/settings/face.match_threshold

# List all settings
curl -H "X-API-Key: argus_..." http://localhost:8100/api/settings

Webhooks

HTTP callbacks fired when events occur. Per-environment, filterable by event type. Manage from the UI at Account → Webhooks.

Supported events: detection.created · detection.labeled · detection.deleted · identity.created · identity.updated · identity.deleted · identity.merged · job.done

# Register
curl -X POST \
  -H "X-API-Key: argus_..." \
  -H "Content-Type: application/json" \
  -d '{"url": "https://my-server.local/hooks/argus", "events": ["job.done"],
       "label": "job alerts", "secret": "mysecret"}' \
  http://localhost:8100/api/webhooks

# List
curl -H "X-API-Key: argus_..." http://localhost:8100/api/webhooks

# Disable temporarily
curl -X PUT \
  -H "X-API-Key: argus_..." \
  -H "Content-Type: application/json" \
  -d '{"is_active": false}' \
  http://localhost:8100/api/webhooks/1

# Test ping — returns {ok, status_code, duration_ms, error}
curl -X POST \
  -H "X-API-Key: argus_..." \
  http://localhost:8100/api/webhooks/1/test

# Delivery history (last 50, newest first)
curl -H "X-API-Key: argus_..." http://localhost:8100/api/webhooks/1/deliveries

When a secret is set, each request carries an X-Argus-Signature: sha256=<hmac> header computed over the JSON body. Verify it on your server to confirm the call is from Argus.

Identity search

GET /api/search

Search enrolled identities by name using FTS5 trigram matching — handles partial names, case-insensitive, near-misses.

curl -H "X-API-Key: argus_..." \
  "http://localhost:8100/api/search?q=alice"

# Faces only, up to 20 results
curl -H "X-API-Key: argus_..." \
  "http://localhost:8100/api/search?q=john&type=face&limit=20"

Export and import

Export recognition data (identities, embeddings, detections, images) and import into another instance. Imports merge by identity name — existing identities receive additional detections and embeddings rather than being duplicated.

POST /api/export
POST /api/import
# Export selected identities
curl -X POST \
  -H "X-API-Key: argus_..." \
  -H "Content-Type: application/json" \
  -d '{"identity_ids": [1, 2, 3]}' \
  http://localhost:8100/api/export \
  --output argus_export.zip

# Import into another instance
curl -X POST \
  -H "X-API-Key: argus_..." \
  -F "file=@argus_export.zip" \
  http://localhost:8100/api/import

Also available via Account page in the UI.