Overview

All recognition endpoints live under /api/v1/ and require:

Authorization: Bearer vf_test_<your-secret>

Test keys use the vf_test_ prefix; production keys use vf_live_. The plain secret is shown once when you create a key.

Responses use a consistent envelope:

{"success": true, "data": { ... }}
{"success": false, "error": {"code": "...", "message": "..."}}

Image uploads use multipart/form-data with a JPEG or PNG file in the image field.

Default match threshold: 0.4 cosine similarity (tunable per verify/identify request).

Rate limits apply per API key. See error codes for 429 responses.

1. Register

Fastest path: open /register/, create an account, and sign in.

Your personal organization is created automatically. Note its ID from the dashboard or the register API response.

curl (session API)

Session POST requests need a CSRF token. Fetch one from the login page first:

BASE="https://verifai.iqtbots.ai"
CSRF=$(curl -s -c /tmp/verifai.cookies "$BASE/login/" | grep -o 'csrfmiddlewaretoken" value="[^"]*"' | cut -d'"' -f4)

curl -s -b /tmp/verifai.cookies -c /tmp/verifai.cookies \
  -H "X-CSRFToken: $CSRF" -H "Content-Type: application/json" \
  -X POST "$BASE/api/v1/auth/register/" \
  -d '{
    "email": "dev@example.com",
    "password": "securepass123",
    "password_confirm": "securepass123",
    "first_name": "Alex"
  }'

Save data.personal_organization.id from the response as ORG_ID.

2. Create API key

Dashboard: go to your organization → Create API key. Copy the secret immediately.

curl (session API)

ORG_ID="<your-organization-uuid>"

curl -s -b /tmp/verifai.cookies \
  -H "X-CSRFToken: $CSRF" -H "Content-Type: application/json" \
  -X POST "$BASE/api/v1/dashboard/organizations/$ORG_ID/api-keys/" \
  -d '{"name": "My app (dev)", "environment": "test"}'

Save data.secret as API_KEY. Confirm it works:

curl -s -H "Authorization: Bearer $API_KEY" "$BASE/api/v1/auth/verify/"

3. Create a collection

Collections are tenant-scoped galleries that group enrolled faces.

curl -s -H "Authorization: Bearer $API_KEY" -H "Content-Type: application/json" \
  -X POST "$BASE/api/v1/collections/" \
  -d '{"name": "Employees", "description": "Staff access control"}'

Save data.collection.id as COLLECTION_ID.

4. Enroll a face

Upload a clear front-facing photo. Use your own external_id (e.g. employee number) to reference the person later.

curl -s -H "Authorization: Bearer $API_KEY" \
  -X POST "$BASE/api/v1/collections/$COLLECTION_ID/persons/" \
  -F "external_id=employee_4821" \
  -F "display_name=Alex Morgan" \
  -F 'metadata={"department":"Engineering"}' \
  -F "image=@/path/to/face.jpg"

On success you receive the person record plus enrollment metadata (model, confidence, bounding box).

5. Verify (1:1)

Compare a new photo against one enrolled person. This is the primary MVP flow for login and check-in.

curl -s -H "Authorization: Bearer $API_KEY" \
  -X POST "$BASE/api/v1/verify/" \
  -F "collection_id=$COLLECTION_ID" \
  -F "external_id=employee_4821" \
  -F "threshold=0.4" \
  -F "image=@/path/to/probe.jpg"

Example success payload:

{
  "success": true,
  "data": {
    "matched": true,
    "similarity": 0.91,
    "threshold": 0.4,
    "person": { "id": "...", "external_id": "employee_4821", ... },
    "probe": { "confidence": 0.88, "bbox": [x1, y1, x2, y2] }
  }
}

6. Identify (1:N) (small galleries)

Search an entire collection for the best matches above the threshold. MVP uses a linear O(n) scan — suitable for modest watchlists (default max 500 enrolled faces). For login and check-in when you know the user, use verify (1:1) instead. Large-scale 1:N (thousands of faces) needs a vector index (planned); oversized collections return gallery_too_large.

curl -s -H "Authorization: Bearer $API_KEY" \
  -X POST "$BASE/api/v1/identify/" \
  -F "collection_id=$COLLECTION_ID" \
  -F "threshold=0.4" \
  -F "max_results=5" \
  -F "image=@/path/to/probe.jpg"

Responses include gallery_size and search_method: "linear_scan".

Error codes

Recognition endpoints return structured errors in the error.code field. Auth failures use DRF's detail field.

HTTP Code When
401Invalid or revoked API key ({"detail": "Invalid or revoked API key."})
403Missing API key on a protected endpoint
429rate_limit_exceededPer-minute burst limit exceeded for this API key
429daily_quota_exceededDaily request cap reached (resets at UTC midnight)
400validation_errorInvalid JSON body or serializer validation
400missing_imageNo image file in multipart request
400missing_external_idEnroll without external_id
400missing_collection_idVerify/identify without collection_id
400missing_person_referenceVerify without person_id or external_id
400invalid_metadatametadata is not valid JSON object
400invalid_imageFile is not a decodable JPEG/PNG
400invalid_thresholdThreshold is not a number
400invalid_max_resultsmax_results is not a positive integer
404person_not_foundPerson ID or external_id not in collection
404not_enrolledPerson exists but has no enrolled face
422image_quality_failedEnroll with strict_quality=true and quality checks failed
422no_face_detectedValid image but no face found
422gallery_too_largeIdentify on a collection above the configured gallery cap — use verify or split collections
500face_processing_errorInsightFace pipeline failure