# Extractors API ## Base URL ``` {BASE_URL} ``` - **Local development:** `http://localhost:54400` - **Docker (internal):** `http://extractors:54400` - **Production:** use your configured hostname (port `14400`) ## Authentication None at the service level — access is mediated by the platform API gateway (Bearer token at the perimeter). Do not expose this service directly. ## Endpoints ### GET /health Liveness probe. ```json { "status": "ok", "version": "0.1.0" } ``` ### GET /ready Readiness + optional tooling availability (informational; the service degrades gracefully if ffprobe/ffmpeg are absent). ```json { "status": "ready", "ffprobe": true, "ffmpeg": true } ``` ### POST /v1/metadata Extract deterministic media metadata & integrity features. The applicable extractors are chosen automatically from the detected media type. **Request** — `multipart/form-data` | Field | Type | Description | |-------|------|-------------| | `file` | file | Image, video or audio file | ```bash curl -X POST http://localhost:54400/v1/metadata \ -F "file=@photo.jpg" ``` **Response** `200 OK` ```json { "filename": "photo.jpg", "media_type": "image", "sha256": "9f86d081884c7d65...", "size_bytes": 84211, "analyses": { "integrity": { "tool_id": "integrity", "name": "Integrity & signature", "ok": true, "results": { "container": "JPEG", "sha256": "9f86...", "size_bytes": 84211 }, "evidence": ["Container: JPEG.", "SHA-256: 9f86d081884c7d65…"], "anomalies": [], "confidence": 1.0 }, "exif": { "tool_id": "exif", "name": "EXIF metadata", "ok": true, "results": { "format": "JPEG", "dimensions": [4032, 3024], "make": "Apple", "model": "iPhone 13", "datetimeoriginal": "2024:06:15 14:30:00", "gps": { "latitude": 44.426, "longitude": 26.102 }, "software": "Adobe Photoshop 25.0" }, "evidence": ["Captured with Apple iPhone 13.", "GPS location present: 44.426, 26.102."], "anomalies": ["Editing/generation software detected in EXIF: Adobe Photoshop 25.0."], "confidence": 0.95 }, "ela": { "tool_id": "ela", "name": "Error Level Analysis", "ok": true, "results": { "quality": 90, "mean_error": 6.1, "max_error": 211.0, "p99_error": 38.0, "hot_pixel_fraction": 0.031 }, "evidence": ["ELA mean error 6.1, p99 38.0 (quality=90)."], "anomalies": ["Localized high-error region(s) detected — possible splice/edit (3.1% of pixels)."], "confidence": 0.6 } }, "evidence": ["..."], "anomalies": ["..."], "execution_time_ms": 42.7 } ``` For **video** inputs the `analyses` block contains `integrity`, `video_metadata` (codec/width/height/fps/bitrate/encoder) and `spectrogram`. For **audio**: `integrity` + `spectrogram`. Each extractor returns a uniform `FeatureResult`: | Field | Type | Description | |-------|------|-------------| | `tool_id` | string | Stable extractor id | | `name` | string | Human-readable name | | `ok` | bool | Ran without error | | `results` | object | Structured extracted data | | `evidence` | string[] | Neutral findings (LLM-readable) | | `anomalies` | string[] | Tampering/edit hints | | `confidence` | number\|null | 0..1 (extraction confidence, not a verdict) | | `error` | string\|null | Set when `ok` is false | ## Error Responses | Status | Meaning | |--------|---------| | 400 | Empty file | | 413 | File exceeds `EXTRACTORS_MAX_UPLOAD_MB` | | 422 | Missing `file` field | ```json { "detail": "empty file" } ``` ## Request Headers | Header | Required | Notes | |--------|----------|-------| | `Content-Type` | yes | `multipart/form-data` (set by the client) |