# Face Matching API

Advanced biometric identification with 1:1 verification and 1:n search capabilities.

## Base URL

```
https://api.zaits.net/v1/face-matching
```

## Authentication

All requests require your API key in the Authorization header:

```http
Authorization: Bearer YOUR_API_KEY
```

## Tenant Isolation

{% hint style="success" %}
**Multi-Tenant Security:** All face embeddings are **automatically isolated per Zaits customer**. Your data is completely separate from other customers - searches and matches only occur within your own data.

* **Your API key** identifies you as the tenant (owner)
* **subject\_id** identifies users in YOUR application (not Zaits users)
* Data isolation is enforced at the database level for maximum security
  {% endhint %}

### How It Works

```
Zaits Customer A (API Key: acme_key_123)
├─ Subject: "EMP-001" → John Smith
├─ Subject: "EMP-002" → Jane Doe
└─ Subject: "EMP-003" → Bob Johnson

Zaits Customer B (API Key: beta_key_456)
├─ Subject: "CUST-A" → Alice Williams
├─ Subject: "CUST-B" → Charlie Brown
└─ Subject: "CUST-C" → Diana Prince

- Customer A can NEVER access Customer B's data
- Each customer has their own isolated face database
```

***

## Enroll Face

Register a face in the database for future 1:n identification.

### Endpoint

```http
POST /v1/face-matching/enroll
```

### Parameters

| Parameter           | Type   | Required | Description                                                 |
| ------------------- | ------ | -------- | ----------------------------------------------------------- |
| `image`             | file   | Yes      | Face image to enroll                                        |
| `subject_id`        | string | Yes      | Your app's user identifier (employee ID, customer ID, etc.) |
| `quality_score`     | number | No       | Image quality score (0-1)                                   |
| `liveness_score`    | number | No       | Liveness detection score (0-1)                              |
| `enrollment_source` | string | No       | Source of enrollment (e.g., "registration", "manual")       |
| `metadata`          | object | No       | Custom metadata (employee info, department, etc.)           |

{% hint style="info" %}
**Understanding subject\_id:**

* `subject_id` is **YOUR application's user identifier** (not a Zaits user ID)
* Examples: employee ID (`"EMP-001"`), customer number (`"CUST-456"`), badge number (`"B-8472"`)
* Each Zaits customer has **their own isolated namespace** - your data never mixes with other customers
* Use `metadata` to store additional user information (name, department, etc.)
  {% endhint %}

### Request Examples

{% tabs %}
{% tab title="cURL" %}

```bash
curl -X POST https://api.zaits.net/v1/face-matching/enroll \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -F "subject_id=EMP-001" \
  -F "image=@employee_photo.jpg" \
  -F "quality_score=0.95" \
  -F "liveness_score=0.88" \
  -F "enrollment_source=hr_registration" \
  -F 'metadata={"name":"John Smith","department":"Engineering","badge":"B-8472"}'
```

{% endtab %}

{% tab title="JavaScript" %}

```javascript
const formData = new FormData();
formData.append("subject_id", "EMP-001"); // Your employee ID
formData.append("image", employeePhoto);
formData.append("quality_score", "0.95");
formData.append("liveness_score", "0.88");
formData.append("enrollment_source", "hr_registration");
formData.append(
  "metadata",
  JSON.stringify({
    name: "John Smith",
    department: "Engineering",
    badge: "B-8472",
    hire_date: "2024-01-15",
  })
);

const response = await fetch("https://api.zaits.net/v1/face-matching/enroll", {
  method: "POST",
  headers: {
    Authorization: "Bearer YOUR_API_KEY",
  },
  body: formData,
});

const result = await response.json();
```

{% endtab %}

{% tab title="Python" %}

```python
import requests

files = {'image': open('employee_photo.jpg', 'rb')}
data = {
    'subject_id': 'EMP-001',  # Your employee ID
    'quality_score': 0.95,
    'liveness_score': 0.88,
    'enrollment_source': 'hr_registration',
    'metadata': '{"name":"John Smith","department":"Engineering","badge":"B-8472"}'
}

response = requests.post(
    'https://api.zaits.net/v1/face-matching/enroll',
    headers={'Authorization': 'Bearer YOUR_API_KEY'},
    files=files,
    data=data
)

result = response.json()
```

{% endtab %}
{% endtabs %}

### Response

```json
{
  "success": true,
  "embeddingId": "550e8400-e29b-41d4-a716-446655440000",
  "subjectId": "EMP-001",
  "embeddingDimension": 512,
  "processing_time": 0.85
}
```

**Response Fields:**

* `embeddingId` - Unique ID for this face embedding
* `subjectId` - Your app's user identifier that was enrolled
* `embeddingDimension` - Vector dimensions (always 512 for ArcFace)
* `processing_time` - Time taken to process in seconds

***

## Search Faces (1:n Matching)

Find matching faces in the enrolled database.

### Endpoint

```http
POST /v1/face-matching/search
```

### Parameters

| Parameter   | Type   | Required | Description                              |
| ----------- | ------ | -------- | ---------------------------------------- |
| `image`     | file   | Yes      | Face image to search for                 |
| `threshold` | number | No       | Similarity threshold (0-1, default: 0.6) |
| `limit`     | number | No       | Maximum results to return (default: 10)  |

### Request Example

{% tabs %}
{% tab title="cURL" %}

```bash
curl -X POST https://api.zaits.net/v1/face-matching/search \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -F "image=@unknown_face.jpg" \
  -F "threshold=0.7" \
  -F "limit=5"
```

{% endtab %}

{% tab title="JavaScript" %}

```javascript
const formData = new FormData();
formData.append("image", file);
formData.append("threshold", "0.7");
formData.append("limit", "5");

const response = await fetch("https://api.zaits.net/v1/face-matching/search", {
  method: "POST",
  headers: {
    Authorization: "Bearer YOUR_API_KEY",
  },
  body: formData,
});

const result = await response.json();

// Process matches
if (result.matchCount > 0) {
  const topMatch = result.matches[0];
  console.log(`Match found: ${topMatch.user_name}`);
  console.log(`Confidence: ${(topMatch.similarity * 100).toFixed(1)}%`);
  console.log(`Email: ${topMatch.user_email}`);
}
```

{% endtab %}

{% tab title="Python" %}

```python
import requests

files = {'image': open('unknown_face.jpg', 'rb')}
data = {
    'threshold': 0.7,
    'limit': 5
}

response = requests.post(
    'https://api.zaits.net/v1/face-matching/search',
    headers={'Authorization': 'Bearer YOUR_API_KEY'},
    files=files,
    data=data
)

result = response.json()

if result['matchCount'] > 0:
    top_match = result['matches'][0]
    print(f"Match found: {top_match['user_name']}")
    print(f"Confidence: {top_match['similarity'] * 100:.1f}%")
```

{% endtab %}
{% endtabs %}

### Response

```json
{
  "success": true,
  "matches": [
    {
      "id": "embedding-id",
      "subject_id": "EMP-001",
      "similarity": 0.8523,
      "quality_score": 0.95,
      "liveness_score": 0.88,
      "enrollment_source": "registration",
      "metadata": {
        "name": "John Smith",
        "department": "Engineering",
        "badge": "B-8472",
        "label": "Employee Badge",
        "location": "HR Office"
      },
      "created_at": "2025-01-11T10:00:00Z"
    }
  ],
  "matchCount": 1,
  "thresholdUsed": 0.7,
  "processing_time": 1.23
}
```

**Response Fields:**

* `subject_id` - Your app's user identifier (e.g., employee ID, customer number)
* `similarity` - Match confidence score (0-1), higher is better
* `quality_score` - Original enrollment image quality (0-1)
* `liveness_score` - Liveness detection score from enrollment (0-1)
* `enrollment_source` - Where this face was enrolled (e.g., "registration", "testing")
* `metadata` - Custom data you stored during enrollment (name, department, etc.)
* `created_at` - When this face was enrolled

***

## Verify Face (1:1 Matching)

Verify if a face matches a specific subject's enrolled faces.

### Endpoint

```http
POST /v1/face-matching/verify/:subjectId
```

### Parameters

| Parameter   | Type   | Required | Description                                   |
| ----------- | ------ | -------- | --------------------------------------------- |
| `subjectId` | string | Yes      | Subject ID to verify against (path parameter) |
| `image`     | file   | Yes      | Face image to verify                          |
| `threshold` | number | No       | Similarity threshold (default: 0.6)           |

{% hint style="info" %}
**Subject ID in Verification:**

* Use the same `subject_id` that was used during enrollment
* Example: If you enrolled "EMP-001", verify against "EMP-001"
* The verification is automatically scoped to your tenant (API key)
  {% endhint %}

### Request Example

{% tabs %}
{% tab title="cURL" %}

```bash
curl -X POST https://api.zaits.net/v1/face-matching/verify/EMP-001 \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -F "image=@verification_selfie.jpg" \
  -F "threshold=0.7"
```

{% endtab %}

{% tab title="JavaScript" %}

```javascript
const subjectId = "EMP-001"; // Your app's user identifier
const formData = new FormData();
formData.append("image", file);
formData.append("threshold", "0.7");

const response = await fetch(
  `https://api.zaits.net/v1/face-matching/verify/${subjectId}`,
  {
    method: "POST",
    headers: {
      Authorization: "Bearer YOUR_API_KEY",
    },
    body: formData,
  }
);

const result = await response.json();

if (result.verified) {
  console.log("Access granted!");
} else {
  console.log("Access denied");
}
```

{% endtab %}

{% tab title="Python" %}

```python
import requests

subject_id = 'EMP-001'  # Your app's user identifier
files = {'image': open('verification_selfie.jpg', 'rb')}
data = {'threshold': 0.7}

response = requests.post(
    f'https://api.zaits.net/v1/face-matching/verify/{subject_id}',
    headers={'Authorization': 'Bearer YOUR_API_KEY'},
    files=files,
    data=data
)

result = response.json()
print(f"Verified: {result['verified']}")
print(f"Similarity: {result['similarity']:.4f}")
```

{% endtab %}
{% endtabs %}

### Response

```json
{
  "success": true,
  "verified": true,
  "similarity": 0.8523,
  "threshold": 0.7,
  "embeddingId": "embedding-id-used",
  "enrollmentSource": "registration",
  "processing_time": 0.95
}
```

***

## Get Tenant Embeddings

Retrieve all enrolled face embeddings for your tenant (all subjects enrolled under your API key).

### Endpoint

```http
GET /v1/face-matching/embeddings
```

### Query Parameters

| Parameter     | Type    | Required | Description                                   |
| ------------- | ------- | -------- | --------------------------------------------- |
| `active_only` | boolean | No       | Only return active embeddings (default: true) |
| `subject_id`  | string  | No       | Filter embeddings for a specific subject ID   |

### Request Examples

{% tabs %}
{% tab title="All Embeddings" %}

```bash
curl -X GET 'https://api.zaits.net/v1/face-matching/embeddings?active_only=true' \
  -H "Authorization: Bearer YOUR_API_KEY"
```

{% endtab %}

{% tab title="Specific Subject" %}

```bash
curl -X GET 'https://api.zaits.net/v1/face-matching/embeddings?subject_id=EMP-001' \
  -H "Authorization: Bearer YOUR_API_KEY"
```

{% endtab %}
{% endtabs %}

### Response

```json
{
  "success": true,
  "embeddings": [
    {
      "id": "embedding-id",
      "subject_id": "EMP-001",
      "quality_score": 0.95,
      "liveness_score": 0.88,
      "enrollment_source": "registration",
      "created_at": "2025-01-11T10:00:00Z",
      "verification_count": 15,
      "last_verified_at": "2025-01-11T14:30:00Z"
    }
  ],
  "count": 1
}
```

**Response Fields:**

* `subject_id` - Your app's user identifier for this embedding
* `quality_score` - Image quality score (0-1)
* `liveness_score` - Liveness detection score (0-1)
* `enrollment_source` - Source of enrollment
* `verification_count` - Number of successful verifications
* `last_verified_at` - Timestamp of last successful verification

***

## Delete Embeddings

Delete face embeddings for your tenant.

### Delete Specific Embedding

```http
DELETE /v1/face-matching/embeddings/:embeddingId
```

### Delete All Embeddings for Tenant

```http
DELETE /v1/face-matching/embeddings
```

### Delete All Embeddings for Specific Subject

```http
DELETE /v1/face-matching/embeddings?subject_id=:subjectId
```

### Request Examples

{% tabs %}
{% tab title="Delete Specific" %}

```bash
curl -X DELETE https://api.zaits.net/v1/face-matching/embeddings/embedding-id \
  -H "Authorization: Bearer YOUR_API_KEY"
```

{% endtab %}

{% tab title="Delete All" %}

```bash
# Delete ALL embeddings for your tenant
curl -X DELETE https://api.zaits.net/v1/face-matching/embeddings \
  -H "Authorization: Bearer YOUR_API_KEY"
```

{% endtab %}

{% tab title="Delete by Subject" %}

```bash
# Delete all embeddings for a specific subject
curl -X DELETE 'https://api.zaits.net/v1/face-matching/embeddings?subject_id=EMP-001' \
  -H "Authorization: Bearer YOUR_API_KEY"
```

{% endtab %}
{% endtabs %}

### Response

```json
{
  "success": true,
  "message": "Face embedding deleted successfully"
}
```

***

## Similarity Thresholds

Choose the appropriate threshold based on your security requirements:

| Threshold     | Use Case                         | Security Level | Description                    |
| ------------- | -------------------------------- | -------------- | ------------------------------ |
| **0.4 - 0.5** | High security (banking, medical) | Very strict    | May reject some valid matches  |
| **0.6**       | **Recommended**                  | Balanced       | Good accuracy/security balance |
| **0.7 - 0.8** | Low security (social apps)       | Permissive     | May allow some false matches   |

### Threshold Recommendations

```javascript
// Banking/Financial Services
const BANKING_THRESHOLD = 0.4;

// Corporate Access Control
const ACCESS_CONTROL_THRESHOLD = 0.6;

// Social/Consumer Apps
const SOCIAL_THRESHOLD = 0.75;
```

***

## Use Cases

### 1. Employee Access Control

```javascript
// Enroll employee during registration
const formData = new FormData();
formData.append("subject_id", "EMP-12345"); // Employee ID from your system
formData.append("image", employeePhoto);
formData.append(
  "metadata",
  JSON.stringify({
    name: "John Smith",
    department: "Engineering",
    label: "Employee Badge",
    location: "Building A - Security",
    notes: "Access level: Standard",
  })
);

const enrollResult = await fetch(
  "https://api.zaits.net/v1/face-matching/enroll",
  {
    method: "POST",
    headers: { Authorization: "Bearer YOUR_API_KEY" },
    body: formData,
  }
);

// Verify at entrance using 1:n search
const searchData = new FormData();
searchData.append("image", cameraImage);
searchData.append("threshold", "0.7");
searchData.append("limit", "1");

const searchResult = await fetch(
  "https://api.zaits.net/v1/face-matching/search",
  {
    method: "POST",
    headers: { Authorization: "Bearer YOUR_API_KEY" },
    body: searchData,
  }
).then((r) => r.json());

if (searchResult.matchCount > 0) {
  const employee = searchResult.matches[0];
  grantAccess(employee.subject_id); // Use subject_id (EMP-12345)
  console.log(`Welcome, ${employee.metadata?.name || employee.subject_id}!`);
}
```

### 2. Customer Identification

```javascript
// Enroll customer during first visit
const formData = new FormData();
formData.append("subject_id", "CUST-789"); // Customer ID from your system
formData.append("image", customerPhoto);
formData.append(
  "metadata",
  JSON.stringify({
    name: "Jane Doe",
    membership: "Gold",
    joined: "2024-01-15",
  })
);

await fetch("https://api.zaits.net/v1/face-matching/enroll", {
  method: "POST",
  headers: { Authorization: "Bearer YOUR_API_KEY" },
  body: formData,
});

// Search for returning customer
const searchData = new FormData();
searchData.append("image", customerPhoto);
searchData.append("threshold", "0.65");
searchData.append("limit", "5");

const result = await fetch("https://api.zaits.net/v1/face-matching/search", {
  method: "POST",
  headers: { Authorization: "Bearer YOUR_API_KEY" },
  body: searchData,
}).then((r) => r.json());

if (result.matchCount > 0) {
  const customer = result.matches[0];
  console.log(`Welcome back, ${customer.metadata?.name}!`);
  loadLoyaltyInfo(customer.subject_id); // Use subject_id (CUST-789)
}
```

### 3. Event Check-in (1:1 Verification)

```javascript
// Enroll ticket holder during purchase
const formData = new FormData();
formData.append("subject_id", "TICKET-12345"); // Ticket number
formData.append("image", ticketHolderPhoto);
formData.append(
  "metadata",
  JSON.stringify({
    event: "Concert 2024",
    section: "VIP",
    seat: "A-15",
  })
);

await fetch("https://api.zaits.net/v1/face-matching/enroll", {
  method: "POST",
  headers: { Authorization: "Bearer YOUR_API_KEY" },
  body: formData,
});

// Verify at entrance (1:1 verification)
const verifyData = new FormData();
verifyData.append("image", livePhoto);
verifyData.append("threshold", "0.7");

const verification = await fetch(
  "https://api.zaits.net/v1/face-matching/verify/TICKET-12345",
  {
    method: "POST",
    headers: { Authorization: "Bearer YOUR_API_KEY" },
    body: verifyData,
  }
).then((r) => r.json());

if (verification.verified) {
  checkInAttendee("TICKET-12345");
  console.log("Entry granted - ticket verified");
} else {
  console.log("Entry denied - face does not match ticket holder");
}
```

***

## Best Practices

### Image Quality

* **Resolution:** 640x640 or higher
* **Lighting:** Well-lit, even lighting
* **Angle:** Frontal face, minimal rotation
* **Expression:** Neutral expression preferred

### Enrollment Strategy

* Enroll 2-3 images per user for better accuracy
* Use different lighting conditions
* Include slight angle variations
* Check liveness before enrollment

### Security

* Always use liveness detection before enrollment
* Implement rate limiting on verification endpoints
* Log all face matching operations for audit
* Use appropriate thresholds for your use case

### Performance

* Cleanup old embeddings periodically
* Keep 3-5 most recent enrollments per user
* Use indexed searches for large databases
* Cache frequent verification results

***

**Next:** [OCR API Documentation](/api/api-reference/ocr.md)


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://zaits.gitbook.io/api/api-reference/face-matching.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
