API Reference

REST API for face verification, liveness detection, and live monitoring.

1. Authentication

All requests require an X-API-Key header. Get your key from the Dashboard.

bash
curl https://verify.merilive.com/api/public/v1/verify-face \
  -H "X-API-Key: fv_live_..." \
  -H "Content-Type: application/json" \
  -d '{"external_user_id":"u_123","image_base64":"..."}'

2. Verify Face

POST
https://verify.merilive.com/api/public/v1/verify-face

Runs face detection + liveness + duplicate scan via the MeriCore dual-engine.

Request body

json
{
  "external_user_id": "your_user_id",
  "image_base64": "<base64-encoded JPEG>",
  "metadata": { "any": "context" }
}

Response

json
{
  "verification_id": "uuid",
  "status": "approved" | "needs_review" | "rejected" | "duplicate",
  "confidence": 98.4,
  "liveness_passed": true,
  "gender": "female",
  "engine_agreement": "both_passed"
}

3. Live Monitoring

POST
https://verify.merilive.com/api/public/v1/monitor-frame

Real-time frame analysis. Detects sleeping, face-lost, and looking-away conditions. Call once per second during a live stream.

Response

json
{
  "face_present": true,
  "eyes_open": false,
  "looking_forward": true,
  "alerts": ["sleep_detected"]
}

4. Get Verification

GET
https://verify.merilive.com/api/public/v1/verification/{id}

Fetch full details for a previously created verification.

5. Content Moderation (Chat / Comments)

POST
https://verify.merilive.com/api/public/v1/scan-content

Scans any text (chat message, comment, profile bio) for hate speech, harassment, sexual content, threats, and self-harm. Combines OpenAI Moderation, Lovable AI (Gemini 2.5 Flash), your custom keyword blocklist, and a South Asian hate-speech lexicon (Bangla, Hindi, Urdu, Arabic). Worst-of-four verdict.

Request body

json
{
  "text": "the message to scan",
  "external_user_id": "u_123"
}

Response

json
{
  "verdict": "allow" | "review" | "block",
  "categories": ["hate_speech", "insult"],
  "score": 0.92,
  "sources": {
    "openai": { ... },
    "lovable_ai": { ... },
    "custom_keywords": [...],
    "hate_lexicon": [...]
  }
}

Note: This endpoint uses Lovable AI (Gemini 2.5 Flash) for nuanced multilingual moderation. Each scan consumes a small amount of workspace AI credit on top of your MeriCore request quota. Manage your custom blocklist words per API key from Admin → API Keys.

6. Index Face (Duplicate Account Prevention)

POST
https://verify.merilive.com/api/public/v1/index-face

Indexes a user's selfie into your tenant's AWS Rekognition collection. Call this once per user during signup. The face vector is stored and later matched by /search-face to block duplicate signups.

Request body

json
{
  "external_user_id": "u_123",
  "image_base64": "<base64-encoded JPEG>",
  "metadata": { "any": "context" }
}

Response

json
{
  "status": "indexed",
  "face_id": "aws-rekognition-face-id",
  "external_user_id": "u_123",
  "collection_id": "fv_<tenant>",
  "confidence": 99.8
}

7. Search Face (Find Duplicates)

POST
https://verify.merilive.com/api/public/v1/search-face

Searches your tenant's face index for selfies similar to the supplied image. Returns all matches above the similarity threshold so you can detect users trying to open a second account. Default threshold (configurable per API key from Admin → API Keys) is 95%.

Request body

json
{
  "image_base64": "<base64-encoded JPEG>",
  "threshold": 95,
  "max_matches": 10
}

Response

json
{
  "matches": [
    {
      "external_user_id": "u_123",
      "similarity": 99.4,
      "face_id": "...",
      "indexed_at": "2026-05-23T..."
    }
  ],
  "is_duplicate": true,
  "threshold_used": 95
}

Flagged duplicates are listed in Admin → Duplicate Accounts.

8. Verify Document (OCR + Tamper + Face Match)

POST
https://verify.merilive.com/api/public/v1/verify-document

OCR + tamper detection + ID-photo vs selfie face match for Aadhaar, PAN, Passport (MRZ), NID, Driving License. Powered by AWS Textract, Rekognition CompareFaces, and Gemini vision.

Request body

json
{
  "external_user_id": "u_123",
  "document_image_base64": "<base64 JPEG of ID>",
  "selfie_image_base64": "<base64 JPEG of selfie>"
}

Response

json
{
  "verification_id": "uuid",
  "status": "approved" | "needs_review" | "rejected",
  "document_type": "passport" | "aadhaar" | "pan" | "nid" | "driving_license",
  "name": "...", "dob": "1990-01-01", "id_number": "...", "expiry": "2030-01-01",
  "nationality": "IND", "gender": "M",
  "face_match_score": 96.4, "face_match_passed": true,
  "tamper_score": 0.08, "tamper_passed": true, "tamper_signals": [],
  "mrz": { "format": "TD3", "...": "..." },
  "reasons": []
}

9. Webhooks

Receive real-time events instead of polling. Configure a webhook URL per API key in the admin dashboard. We POST signed JSON when subscribed events fire, with automatic retries (5 attempts, exponential backoff: 30s → 2m → 10m → 1h → 6h).

Events

EventFires when
verification.completedverify-face or verify-document succeeds (approved / needs_review)
verification.failedverify-face or verify-document is rejected
frame.flaggedmonitor-frame detects sleep / face-lost / looking-away
content.blockedscan-content blocks chat / comment (profanity, keywords, age)
duplicate.detectedsearch-face matches an existing identity above the threshold

Request headers

http
POST <your-webhook-url>
Content-Type: application/json
X-MeriCore-Event: verification.completed
X-MeriCore-Signature: sha256=<hex digest>
X-MeriCore-Delivery: <delivery-uuid>
X-MeriCore-Attempt: 1

Payload shape

json
{
  "id": "<event-uuid>",
  "event": "verification.completed",
  "created_at": "2026-05-23T18:00:00.000Z",
  "api_key_id": "<your-key-uuid>",
  "data": { /* event-specific — see your endpoint's response shape */ }
}

Verify signature — Node.js

javascript
import crypto from "crypto";

app.post("/hooks/mericore", express.raw({ type: "application/json" }), (req, res) => {
  const sig = req.header("X-MeriCore-Signature") || "";
  const expected = "sha256=" + crypto
    .createHmac("sha256", process.env.MERICORE_WEBHOOK_SECRET)
    .update(req.body) // raw Buffer
    .digest("hex");

  const ok =
    sig.length === expected.length &&
    crypto.timingSafeEqual(Buffer.from(sig), Buffer.from(expected));
  if (!ok) return res.status(401).send("bad signature");

  const event = JSON.parse(req.body.toString());
  // handle event.event / event.data
  res.sendStatus(200);
});

Verify signature — Python

python
import hmac, hashlib, os
from flask import Flask, request, abort

app = Flask(__name__)
SECRET = os.environ["MERICORE_WEBHOOK_SECRET"].encode()

@app.post("/hooks/mericore")
def hook():
    raw = request.get_data()  # raw bytes — do NOT use request.json
    sig = request.headers.get("X-MeriCore-Signature", "")
    expected = "sha256=" + hmac.new(SECRET, raw, hashlib.sha256).hexdigest()
    if not hmac.compare_digest(sig, expected):
        abort(401)
    event = request.get_json()
    # handle event["event"] / event["data"]
    return "", 200

Delivery rules

  • Respond with any 2xx within 10s to acknowledge.
  • Any non-2xx, timeout, or network error triggers a retry.
  • After 5 failed attempts the delivery is marked dead.
  • Manually replay any delivery from /admin/webhooks.
  • Always verify the signature against the raw request body — JSON re-serialization will break it.

10. Code Examples

Node.js

javascript
const res = await fetch("https://verify.merilive.com/api/public/v1/verify-face", {
  method: "POST",
  headers: {
    "X-API-Key": process.env.MERICORE_KEY,
    "Content-Type": "application/json",
  },
  body: JSON.stringify({
    external_user_id: "u_123",
    image_base64: imageBuffer.toString("base64"),
  }),
});
const data = await res.json();
console.log(data.status); // "approved" | "needs_review" | ...

Python

python
import base64, requests, os

with open("face.jpg", "rb") as f:
    img = base64.b64encode(f.read()).decode()

r = requests.post(
    "https://verify.merilive.com/api/public/v1/verify-face",
    headers={"X-API-Key": os.environ["MERICORE_KEY"]},
    json={"external_user_id": "u_123", "image_base64": img},
)
print(r.json()["status"])

11. Compliance & GDPR/DPDP

MeriCore is GDPR (EU) and DPDP Act 2023 (India) compliant. Every API request is audit-logged with IP + user-agent. The following endpoints implement Subject Access, Right to Erasure, and Consent.

MethodEndpointPurpose
GET/v1/user/:id/dataGDPR Art. 15 — export all user data as JSON
DELETE/v1/user/:idGDPR Art. 17 — right to be forgotten
POST/v1/user/:id/consentDPDP Act — record consent grant/revoke
GET/v1/user/:id/consentRetrieve consent history
bash
# Record user consent (DPDP Act)
curl -X POST https://verify.merilive.com/api/public/v1/user/u_123/consent \
  -H "X-API-Key: $MERICORE_KEY" \
  -H "Content-Type: application/json" \
  -d '{"purpose":"face_verification","granted":true,"policy_version":"v1.0"}'

# Export user data (GDPR SAR)
curl https://verify.merilive.com/api/public/v1/user/u_123/data \
  -H "X-API-Key: $MERICORE_KEY"

# Delete user (GDPR Right to Erasure)
curl -X DELETE https://verify.merilive.com/api/public/v1/user/u_123 \
  -H "X-API-Key: $MERICORE_KEY" \
  -H "Content-Type: application/json" \
  -d '{"reason":"user_requested"}'

Security posture: All data encrypted at rest with AES-256 (managed by Lovable Cloud). TLS 1.3 in transit. Row-Level Security on every user-data table. Face embeddings stored as mathematical vectors (not raw biometric images). Every API request captured to an immutable audit log with IP + user-agent for SOC 2 Type 2 and ISO 27001 evidence. Deletion and export requests are logged immutably even after the underlying data is purged.

12. Error Codes

CodeMeaning
401Missing or invalid X-API-Key
402Insufficient credits — top up your balance
403API key revoked or suspended
400Invalid request body or unsupported image
429Rate limit exceeded (10 req/sec per key)
500Internal error — please retry