The CLI (
pip install mailaccess) wraps this API. All CLI commands call these endpoints.
All REST endpoints are prefixed with /api. The WebSocket endpoint and Maltego transform server have no prefix.
When MAILACCESS_API_KEY is set in .env, all /api/ routes require the header:
X-API-Key: <your-key>
Requests without a valid key receive 401 {"error": "unauthorized"}.
/health and /ws/ routes are always unauthenticated. The Maltego transform at /maltego/ is also exempt — it is designed to be called by the Maltego desktop app on localhost.
Health check. Always unauthenticated.
Response 200
{
"status": "ok",
"version": "0.1.0",
"modules_loaded": ["hibp", "emailrep", "gravatar", "domain_intel", "social"],
"db": "connected"
}db is "connected" or "error".
Start an investigation. Returns immediately with an ID — the investigation runs in the background.
Request
{
"email": "user@example.com",
"modules": ["hibp", "gravatar"],
"enable_modules": ["breach_deep", "ghunt"],
"force": false
}modules is optional. Omit it to run all registered modules. Set force: true to bypass the investigation cache and always run a fresh investigation.
enable_modules is a list of opt-in module names to enable for this run only. Equivalent to the CLI -m flag. Valid values: breach_deep, ghunt, email_discovery. Pass ["all"] to enable all three opt-in modules.
New modules available in 0.4.0: breach_deep, email_discovery, wayback, github_commits. Pass them in the modules array to run selectively:
{ "email": "user@example.com", "modules": ["breach_deep"] }Response 202 — new investigation started
{
"id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
"status": "pending",
"created_at": "2026-05-19T12:00:00+00:00"
}Response 200 — cached result returned (when ENABLE_INVESTIGATION_CACHE=true and a complete result exists within the cache window)
{
"id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
"status": "complete",
"cached": true,
"created_at": "2026-05-19T12:00:00+00:00"
}Connect to WS /ws/investigate/{id} immediately after to stream results in real time. The internal queue is discarded after 5 minutes if no WebSocket consumer connects.
Paginated list of past investigations, newest first.
Note: This endpoint returns
exposure_scoreonly — a single aggregate number. For per-module status, findings, and metadata, useGET /api/report/{id}.
Query parameters
| Param | Type | Default | Max |
|---|---|---|---|
page |
int | 1 |
— |
page_size |
int | 20 |
100 |
Response 200
{
"total": 42,
"page": 1,
"page_size": 20,
"pages": 3,
"items": [
{
"id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
"email": "user@example.com",
"status": "complete",
"exposure_score": 72,
"created_at": "2026-05-19T12:00:00+00:00",
"completed_at": "2026-05-19T12:00:15+00:00"
}
]
}status values: pending, running, complete, failed.
Full investigation report with all module runs and findings.
The response includes exposure_score plus the separate credential risk fields: credential_risk_score, credential_risk_band, score_drivers, and recommended_actions.
Known issue: The route handler for this endpoint is currently missing in
backend/api/routes/investigations.py— the response code at lines 80–83 is present but the@router.getdecorator and function signature are absent, making the endpoint unreachable. UseGET /api/report/{id}/export?format=jsonas a workaround until the route is added.
Intended response 200
{
"id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
"email": "user@example.com",
"status": "complete",
"exposure_score": 72,
"risk_level": "high",
"credential_risk_score": 84,
"credential_risk_band": "CRITICAL",
"score_drivers": [
"infostealer hit",
"multiple high-severity breach findings",
"reused credentials across sources"
],
"recommended_actions": [
"Reset affected passwords immediately and revoke active sessions",
"Review MFA enrollment and strengthen account recovery settings",
"Prioritize containment and analyst follow-up for exposed credentials"
],
"summary": "Ran 8 modules (7 successful, 1 failed). Found 14 data points.",
"created_at": "2026-05-19T12:00:00+00:00",
"completed_at": "2026-05-19T12:00:15+00:00",
"module_runs": [
{
"id": "a1b2c3d4-...",
"module_name": "hibp",
"status": "success",
"run_metadata": {
"total_breaches": 3,
"breach_dates": "2013-10-04 to 2023-01-01",
"most_critical_breach": "Adobe",
"all_data_classes": ["Email addresses", "Passwords"]
},
"errors": null,
"started_at": "2026-05-19T12:00:01+00:00",
"finished_at": "2026-05-19T12:00:02+00:00"
}
],
"findings": [
{
"id": "f1e2d3c4-...",
"module_name": "hibp",
"data": {
"platform": "HaveIBeenPwned",
"url": "https://haveibeenpwned.com/PwnedWebsites#Adobe",
"metadata": {
"name": "Adobe",
"domain": "adobe.com",
"breach_date": "2013-10-04",
"severity": "critical",
"data_classes": ["Email addresses", "Passwords", "Password hints"]
},
"confidence": "high"
},
"created_at": "2026-05-19T12:00:02+00:00"
}
],
"findings_by_module": {
"hibp": [{"platform": "HaveIBeenPwned", "...": "..."}]
},
"metadata_table": {
"hibp": {"total_breaches": 3, "breach_dates": "2013-10-04 to 2023-01-01"}
}
}Export a completed investigation in the requested format as a file download.
Query parameters
| Param | Values | Default |
|---|---|---|
format |
json csv markdown pdf stix maltego |
json |
Response — binary file with Content-Disposition: attachment header.
Filename pattern: mailaccess_{email}_{id}.{ext}
| Format | Extension |
|---|---|
| JSON | .json |
| CSV | .csv |
| Markdown | .markdown |
.pdf |
|
| STIX 2.1 | .stix.json |
| Maltego | .maltego.csv |
Errors
404— investigation not found501— format not yet implemented
Returns the identity clusters built from cross-module correlation, with confidence scores and reasoning strings.
Response 200
{
"clusters": [
{
"id": "cluster-1",
"confidence": "high",
"score": 0.91,
"reasoning": "Shared username 'janedoe' across GitHub, HackerNews, and Twitter findings",
"members": [
{"module": "social", "platform": "GitHub", "username": "janedoe"},
{"module": "whatsmyname", "platform": "HackerNews", "username": "janedoe"}
]
}
]
}Errors
404— investigation not found or not yet complete
Returns a D3-compatible graph representation of the identity graph for use in visualization or export.
Response 200
{
"nodes": [
{"id": "email:user@example.com", "type": "email", "label": "user@example.com"},
{"id": "account:github:janedoe", "type": "account", "label": "janedoe", "platform": "GitHub"}
],
"links": [
{"source": "email:user@example.com", "target": "account:github:janedoe", "confidence": "high"}
]
}Errors
404— investigation not found or not yet complete
Hard-delete an investigation and all associated findings and module runs.
Response 204 — no body.
Errors
404— investigation not found
List all registered modules.
Response 200
[
{
"name": "hibp",
"description": "Check if the email appears in known data breaches via the HIBP v3 API.",
"requires_key": true
},
{
"name": "emailrep",
"description": "Query EmailRep.io for reputation score, risk flags, and linked profile data.",
"requires_key": false
}
]Maltego TRX local transform. Accepts an XML POST body in the Maltego TRX protocol, runs a full investigation, and returns Maltego entity XML. No API key required.
See Integrations — Maltego for setup instructions.
Stream investigation events in real time. Connect immediately after POST /api/investigate.
The server pushes one JSON frame per module event, then a final investigation_complete frame once all modules have finished and results are persisted to the database.
Event: module_start
{
"type": "module_start",
"module": "hibp",
"timestamp": "2026-05-19T12:00:01.234567+00:00"
}Event: module_result
{
"type": "module_result",
"module": "hibp",
"findings": [
{
"platform": "HaveIBeenPwned",
"url": "https://haveibeenpwned.com/PwnedWebsites#Adobe",
"metadata": {"name": "Adobe", "severity": "critical"},
"confidence": "high"
}
],
"status": "success"
}Event: module_error
{
"type": "module_error",
"module": "shodan",
"error": "SHODAN_API_KEY not set",
"status": "failed"
}Event: investigation_complete
{
"type": "investigation_complete",
"exposure_score": 72,
"risk_level": "high"
}Risk level thresholds: low (0–20), medium (21–50), high (51–80), critical (81–100).
Error frame — sent and socket closed if the investigation ID is not found or the queue has already been consumed:
{
"type": "error",
"error": "investigation not found or already streaming"
}If the client disconnects mid-stream, the server drains the internal queue silently so the engine's background task is not blocked.
The exposure score (0–100) is computed once all modules complete:
| Module category | Weight per finding |
|---|---|
Breach modules (hibp, emailrep with breach flag) |
×15 |
| Social presence modules | ×5 |
| All other modules | ×2 |
Score is clamped to 100.