# Identity API Specification > Version: V4.0 | Date: 2026-04-28 > Architecture: Two-layer (Face → Identity) > Base URL: `http://localhost:3003/api/v1` --- ## Overview | Category | Count | Description | |----------|-------|-------------| | **List API** | 6 | One-to-many queries | | **Candidates API** | 2 | Unregistered face candidates | | **Suggest API** | 2 | AI clustering suggestions | | **Detail API** | 2 | Single item detail | | **Register/Bind API** | 3 | Identity management operations | | **Total** | **15** | Core endpoints | --- ## Terminology | Term | Type | Description | |------|------|-------------| | **file_uuid** | UUID | Video file identifier | | **identity_uuid** | UUID | Global identity identifier | | **face_id** | string | Single face detection | | **trace_id** | int | Face tracking ID | | **chunk_id** | string | Sentence chunk ID | --- ## Pagination Parameters | Parameter | Type | Default | Description | |-----------|------|---------|-------------| | `page` | int | 1 | Page number (>=1) | | `page_size` | int | 15 | Items per page (1-100) | | `limit` | int | null | Total items limit | | `search` | string | null | Search query | | `sort` | string | created_at | Sort field | | `order` | string | DESC | Sort direction (ASC/DESC) | --- ## Response Format ### List API Response ```json { "success": true, "data": { "[items]": [...], "pagination": { "page": 1, "page_size": 15, "total": 100, "total_pages": 7, "limit": null } } } ``` ### Detail API Response ```json { "success": true, "data": { "[item]": {...} } } ``` ### Error Response ```json { "success": false, "error": { "code": "NOT_FOUND", "message": "Identity not found", "details": {} } } ``` --- ## 1. List API (One-to-Many) --- ### 1.1 GET /api/v1/files List all files. **Parameters**: | Parameter | Type | Required | Default | |-----------|------|----------|---------| | `page` | int | No | 1 | | `page_size` | int | No | 15 | | `limit` | int | No | null | | `search` | string | No | null | | `status` | string | No | null | **Request**: ```bash curl "http://localhost:3003/api/v1/files?page=1&page_size=15" \ -H "X-API-Key: YOUR_KEY" ``` **Response**: ```json { "success": true, "data": { "files": [ { "file_uuid": "384b0ff44aaaa1f14cb2cd63b3fea966", "file_name": "Charade_1963.mp4", "duration": 6879.33, "status": "completed", "total_identities": 5, "total_faces": 800, "created_at": "2026-04-28T10:00:00Z" } ], "pagination": { "page": 1, "page_size": 15, "total": 100, "total_pages": 7 } } } ``` --- ### 1.2 GET /api/v1/identities List all identities. **Parameters**: | Parameter | Type | Required | Default | |-----------|------|----------|---------| | `page` | int | No | 1 | | `page_size` | int | No | 15 | | `limit` | int | No | null | | `search` | string | No | null | | `source` | string | No | null | **Request**: ```bash curl "http://localhost:3003/api/v1/identities?page=1&page_size=15" \ -H "X-API-Key: YOUR_KEY" ``` **Response**: ```json { "success": true, "data": { "identities": [ { "identity_uuid": "a9a90105-6d6b-...", "name": "Audrey Hepburn", "source": "manual", "total_files": 3, "total_faces": 1500, "reference_vectors": { "total": 4, "angles": ["frontal", "profile_right"] }, "created_at": "2026-04-28T10:00:00Z" } ], "pagination": { "page": 1, "page_size": 15, "total": 50, "total_pages": 4 } } } ``` --- ### 1.3 GET /api/v1/identities/:identity_uuid/files List files where identity appears (N:N relationship). **Parameters**: | Parameter | Type | Required | Default | |-----------|------|----------|---------| | `identity_uuid` | UUID | Yes | - | | `page` | int | No | 1 | | `page_size` | int | No | 15 | | `status` | string | No | null | **Request**: ```bash curl "http://localhost:3003/api/v1/identities/a9a90105.../files" \ -H "X-API-Key: YOUR_KEY" ``` **Response**: ```json { "success": true, "data": { "identity_uuid": "a9a90105...", "name": "Audrey Hepburn", "files": [ { "file_uuid": "384b0ff44aaaa1f14cb2cd63b3fea966", "file_name": "Charade_1963.mp4", "face_count": 500, "speaker_count": 10, "first_appearance": 5.2, "last_appearance": 180.5, "confidence": 0.86 } ], "total_files": 2 } } ``` --- ### 1.4 GET /api/v1/files/:file_uuid/identities List identities in a file (N:N relationship). **Parameters**: | Parameter | Type | Required | Default | |-----------|------|----------|---------| | `file_uuid` | UUID | Yes | - | | `page` | int | No | 1 | | `page_size` | int | No | 15 | | `status` | string | No | null | **Request**: ```bash curl "http://localhost:3003/api/v1/files/384b0ff44aaaa1f14cb2cd63b3fea966/identities" \ -H "X-API-Key: YOUR_KEY" ``` **Response**: ```json { "success": true, "data": { "file_uuid": "384b0ff44aaaa1f14cb2cd63b3fea966", "file_name": "Charade_1963.mp4", "identities": [ { "identity_uuid": "a9a90105...", "name": "Audrey Hepburn", "face_count": 500, "speaker_count": 10, "confidence": 0.86 } ], "total_identities": 5 } } ``` --- ### 1.5 GET /api/v1/identities/:identity_uuid/faces List faces bound to an identity. **Parameters**: | Parameter | Type | Required | Default | |-----------|------|----------|---------| | `identity_uuid` | UUID | Yes | - | | `page` | int | No | 1 | | `page_size` | int | No | 100 | | `limit` | int | No | 1000 | | `pose_angle` | string | No | null | **Request**: ```bash curl "http://localhost:3003/api/v1/identities/a9a90105.../faces?page_size=100" \ -H "X-API-Key: YOUR_KEY" ``` **Response**: ```json { "success": true, "data": { "identity_uuid": "a9a90105...", "faces": [ { "face_id": "face_100", "file_uuid": "384b0ff44aaaa1f14cb2cd63b3fea966", "frame": 100, "timestamp": 5.2, "pose_angle": "frontal", "confidence": 0.92, "trace_id": 2 } ], "total_faces": 1500, "pose_distribution": { "frontal": 400, "profile_right": 300 } } } ``` --- ### 1.6 GET /api/v1/identities/:identity_uuid/chunks List chunks bound to an identity. **Parameters**: | Parameter | Type | Required | Default | |-----------|------|----------|---------| | `identity_uuid` | UUID | Yes | - | | `page` | int | No | 1 | | `page_size` | int | No | 50 | | `limit` | int | No | 500 | | `speaker_id` | string | No | null | **Request**: ```bash curl "http://localhost:3003/api/v1/identities/a9a90105.../chunks" \ -H "X-API-Key: YOUR_KEY" ``` **Response**: ```json { "success": true, "data": { "identity_uuid": "a9a90105...", "chunks": [ { "chunk_id": "chunk_1", "file_uuid": "384b0ff44aaaa1f14cb2cd63b3fea966", "text": "Hello, how are you?", "start_time": 5.2, "end_time": 8.5, "speaker_id": "SPEAKER_0" } ], "total_chunks": 30, "speaker_ids": ["SPEAKER_0"], "total_duration": 45.5 } } ``` --- ## 2. Candidates API (Unregistered) --- ### 2.1 GET /api/v1/faces/candidates List unregistered faces (identity_id = NULL). **Parameters**: | Parameter | Type | Required | Default | |-----------|------|----------|---------| | `file_uuid` | UUID | No | null | | `min_confidence` | float | No | 0.5 | | `pose_angle` | string | No | null | | `page` | int | No | 1 | | `page_size` | int | No | 15 | | `limit` | int | No | 100 | **Request**: ```bash curl "http://localhost:3003/api/v1/faces/candidates?min_confidence=0.8&pose_angle=frontal" \ -H "X-API-Key: YOUR_KEY" ``` **Response**: ```json { "success": true, "data": { "candidates": [ { "face_id": "face_100", "file_uuid": "384b0ff44aaaa1f14cb2cd63b3fea966", "frame": 100, "timestamp": 5.2, "pose_angle": "frontal", "confidence": 0.92, "trace_id": 2, "embedding_quality": 0.88 } ], "statistics": { "total_candidates": 78, "pose_distribution": { "frontal": 20, "profile_right": 30 }, "avg_confidence": 0.85 }, "pagination": { "page": 1, "page_size": 15, "total": 78, "total_pages": 6 } } } ``` --- ### 2.2 GET /api/v1/files/:file_uuid/faces/candidates List unregistered faces in a specific file. **Parameters**: | Parameter | Type | Required | Default | |-----------|------|----------|---------| | `file_uuid` | UUID | Yes | - | | `min_confidence` | float | No | 0.5 | | `page` | int | No | 1 | | `page_size` | int | No | 15 | **Request**: ```bash curl "http://localhost:3003/api/v1/files/384b0ff44aaaa1f14cb2cd63b3fea966/faces/candidates" \ -H "X-API-Key: YOUR_KEY" ``` --- ## 3. Suggest API (AI Agent) --- ### 3.1 POST /api/v1/agents/suggest/clustering AI clustering suggestions for unregistered faces. **Request Body**: ```json { "file_uuid": "384b0ff44aaaa1f14cb2cd63b3fea966", "min_confidence": 0.8, "pose_angles": ["frontal"], "clustering_threshold": 0.85, "max_suggestions": 5 } ``` **Request**: ```bash curl -X POST "http://localhost:3003/api/v1/agents/suggest/clustering" \ -H "Content-Type: application/json" \ -H "X-API-Key: YOUR_KEY" \ -d '{"min_confidence": 0.8, "max_suggestions": 5}' ``` **Response**: ```json { "success": true, "data": { "suggestions": [ { "suggestion_id": "suggest_1", "cluster_type": "high_confidence", "confidence": 0.92, "recommended_faces": [ { "face_id": "face_100", "pose_angle": "frontal", "confidence": 0.95, "is_primary": true } ], "cluster_stats": { "total_faces": 50, "avg_similarity": 0.89, "trace_ids": [2, 3] }, "reason": "High confidence frontal faces from same trace", "action": "register" } ], "analysis_summary": { "total_candidates": 78, "potential_clusters": 5, "suggested_actions": { "register": 3, "bind": 2 } } } } ``` --- ### 3.2 POST /api/v1/agents/suggest/merge AI merge suggestions for identities. **Request Body**: ```json { "identity_uuids": ["a9a90105...", "b8b80206..."], "threshold": 0.85 } ``` **Request**: ```bash curl -X POST "http://localhost:3003/api/v1/agents/suggest/merge" \ -H "Content-Type: application/json" \ -H "X-API-Key: YOUR_KEY" \ -d '{"identity_uuids": ["a9a90105...", "b8b80206..."]}' ``` **Response**: ```json { "success": true, "data": { "suggestions": [ { "suggestion_type": "merge", "confidence": 0.88, "identities": [ {"identity_uuid": "a9a90105...", "name": "Person A", "face_count": 500}, {"identity_uuid": "b8b80206...", "name": "Person B", "face_count": 300} ], "reason": "High embedding similarity (0.88)", "recommended_action": { "merge_target": "a9a90105...", "merge_sources": ["b8b80206..."] } } ] } } ``` --- ## 4. Detail API (One-to-One) --- ### 4.1 GET /api/v1/identities/:identity_uuid Identity detail. **Parameters**: | Parameter | Type | Required | |-----------|------|----------| | `identity_uuid` | UUID | Yes | **Request**: ```bash curl "http://localhost:3003/api/v1/identities/a9a90105..." \ -H "X-API-Key: YOUR_KEY" ``` **Response**: ```json { "success": true, "data": { "identity_uuid": "a9a90105...", "name": "Audrey Hepburn", "source": "manual", "identity_type": "person", "global_stats": { "total_files": 3, "total_faces": 1500, "total_speaker_segments": 30 }, "reference_vectors": { "total": 4, "angles": ["frontal", "profile_right"], "quality_avg": 0.875 }, "created_at": "2026-04-28T10:00:00Z" } } ``` --- ### 4.2 GET /api/v1/files/:file_uuid File detail. **Parameters**: | Parameter | Type | Required | |-----------|------|----------| | `file_uuid` | UUID | Yes | **Request**: ```bash curl "http://localhost:3003/api/v1/files/384b0ff44aaaa1f14cb2cd63b3fea966" \ -H "X-API-Key: YOUR_KEY" ``` **Response**: ```json { "success": true, "data": { "file_uuid": "384b0ff44aaaa1f14cb2cd63b3fea966", "file_name": "Charade_1963.mp4", "duration": 6879.33, "status": "completed", "identity_stats": { "total_identities": 5, "identities": [ {"identity_uuid": "a9a90105...", "name": "Audrey Hepburn", "face_count": 500} ] } } } ``` --- ## 5. Register/Bind API --- ### 5.1 POST /api/v1/identities/register Register new identity from faces. **Request Body**: ```json { "face_ids": ["face_100", "face_150", "face_200"], "name": "Audrey Hepburn", "source": "manual", "auto_bind_chunks": true } ``` **Request**: ```bash curl -X POST "http://localhost:3003/api/v1/identities/register" \ -H "Content-Type: application/json" \ -H "X-API-Key: YOUR_KEY" \ -d '{ "face_ids": ["face_100"], "name": "Audrey Hepburn", "auto_bind_chunks": true }' ``` **Response**: ```json { "success": true, "data": { "identity_uuid": "a9a90105-...", "name": "Audrey Hepburn", "faces_bound": 3, "chunks_bound": 10, "speaker_ids": ["SPEAKER_0"], "reference_vectors": { "total": 3, "angles": ["frontal"] } } } ``` --- ### 5.2 POST /api/v1/identities/:identity_uuid/bind Bind additional faces to existing identity. **Request Body**: ```json { "face_ids": ["face_300", "face_400"], "auto_bind_chunks": true } ``` **Request**: ```bash curl -X POST "http://localhost:3003/api/v1/identities/a9a90105.../bind" \ -H "Content-Type: application/json" \ -H "X-API-Key: YOUR_KEY" \ -d '{"face_ids": ["face_300"]}' ``` **Response**: ```json { "success": true, "data": { "identity_uuid": "a9a90105...", "faces_bound": 1, "chunks_bound": 3 } } ``` --- ### 5.3 POST /api/v1/identities/:identity_uuid/unbind Unbind faces from identity. **Request Body**: ```json { "face_ids": ["face_400"] } ``` **Request**: ```bash curl -X POST "http://localhost:3003/api/v1/identities/a9a90105.../unbind" \ -H "Content-Type: application/json" \ -H "X-API-Key: YOUR_KEY" \ -d '{"face_ids": ["face_400"]}' ``` **Response**: ```json { "success": true, "data": { "identity_uuid": "a9a90105...", "faces_unbound": 1 } } ``` --- ## 6. Error Codes | Code | HTTP Status | Description | |------|-------------|-------------| | `NOT_FOUND` | 404 | Resource not found | | `BAD_REQUEST` | 400 | Invalid request | | `UNAUTHORIZED` | 401 | Invalid API key | | `INTERNAL_ERROR` | 500 | Server error | | `VALIDATION_ERROR` | 422 | Validation failed | --- ## 7. Authentication All endpoints require API key in header: ```bash -H "X-API-Key: YOUR_API_KEY" ``` --- ## Version History | Version | Date | Changes | |---------|------|---------| | V4.0 | 2026-04-28 | Two-layer architecture, 15 core endpoints | | V3.x | 2026-04-10 | 33 endpoints (many deprecated) | --- ## Deprecated Endpoints (V3.x → V4.0) | Endpoint | Status | Replacement | |----------|--------|--------------| | `/api/v1/person/list` | ❌ Removed | `/api/v1/faces/candidates` | | `/api/v1/person/:id` | ❌ Removed | `/api/v1/identities/:uuid` | | `/api/v1/person/merge` | ❌ Removed | `/api/v1/agents/suggest/merge` | | `/api/v1/person/:id/split` | ❌ Removed | Manual face re-binding | | `/api/v1/chunks/candidates` | ❌ Removed | Chunks auto-bind | | **26 more person APIs** | ❌ Removed | See above replacements |