SAGEA LogoDocs & API
Helios

Run a KYC request

Create an API key, send ID images plus a liveness video, and handle the KYC decision.

  • Authenticate with your API key
  • Send a v1 multipart request with front/back images and a liveness video
  • Handle the approved / review / declined decision

Everything here mirrors the hosted Helios flow. v2 (JSON) and a local simulator are included so you can integrate without a camera.

Time to complete: ~10 minutes

Prerequisites

  • Python 3.9+ or Node.js 18+ installed on your machine.
  • A SAGEA account. Create account
  • A SAGEA API key. Foundry is enabled in Free mode by default, with no credit card required.
  • Three test assets:
    • front.jpg — front of the ID, fully visible, min 1200px wide.
    • back.jpg — back of the ID, fully visible (v1 requires both sides).
    • liveness.mp4 — 3–10s selfie video (MP4/MOV/WebM), single face, good light.

Step 1: Get your API key

  1. Open Foundry → API keys.
  2. Click Create new key.
  3. Give the key a name (for example, helios-kyc) and click Create.
  4. Copy the key to your clipboard. The key appears only once; if you lose it, generate a new one.
  5. Set the key as an environment variable in your terminal:
export SAGEA_API_KEY="your_api_key_here"

Step 2: Prepare your assets

Helios verifies a real person holding a real document. Your client must collect:

ArtifactRequirements
front_imageJPG/PNG, ID front fully visible, min 1200px wide
back_imageJPG/PNG, ID back fully visible (v1 requires both sides; v2 makes it optional)
liveness_videoMP4/MOV/WebM, 3–10s selfie video, single face, good light, no filters

Quick sanity check before sending:

ls -lh front.jpg back.jpg liveness.mp4
ffprobe -v error -show_entries format=duration -of default=noprint_wrappers=1 liveness.mp4

Trim or compress to 720p if the video exceeds ~50MB.

Step 3: Send a v1 request

POST https://api.sagea.space/helios/kyc/v1 accepts multipart/form-data. The API key is required; front_image, back_image, and liveness_video are all required.

curl -X POST https://api.sagea.space/helios/kyc/v1 \
  -H "Authorization: Bearer $SAGEA_API_KEY" \
  -F front_image=@"front.jpg" \
  -F back_image=@"back.jpg" \
  -F liveness_video=@"liveness.mp4" \
  -F external_id="user_12345"

Step 4: Try v2 (JSON, server-side)

POST https://api.sagea.space/helios/kyc/v2 accepts the same artifacts as base64 JSON — useful when files already live server-side. front_image_b64 and liveness_video_b64 are required; back_image_b64 is optional for single-sided documents.

curl -X POST https://api.sagea.space/helios/kyc/v2 \
  -H "Authorization: Bearer $SAGEA_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "external_id": "user_12345",
    "front_image_b64": "<base64 of front.jpg>",
    "back_image_b64": "<base64 of back.jpg>",
    "liveness_video_b64": "<base64 of liveness.mp4>",
    "options": {"store_media": false}
  }'

Use v1 for browser and mobile uploads (multipart streams better) and v2 for back-office pipelines.

Step 5: Handle the decision

Both versions return the same schema:

{
  "verification_id": "helios_vrf_9f3a2c1e",
  "external_id": "user_12345",
  "decision": "approved",
  "scores": {
    "document_authenticity": 0.97,
    "face_match": 0.93,
    "liveness": 0.99,
    "overall": 0.96
  },
  "reasons": [],
  "extracted": {
    "full_name": "Aarav Sharma",
    "document_number": "N1234567",
    "date_of_birth": "1998-04-12",
    "expiry_date": "2030-06-30",
    "issuing_country": "NP"
  },
  "model_used": "helios-kyc-1.0"
}

Branch on decision:

data = resp.json()
if data["decision"] == "approved":
    onboard(data["external_id"])
elif data["decision"] == "review":
    queue_manual_review(data["verification_id"], data["scores"])
else:
    block_and_log(data["verification_id"], data["reasons"])

A review example includes reasons:

{
  "decision": "review",
  "scores": {"document_authenticity": 0.81, "face_match": 0.68, "liveness": 0.97, "overall": 0.79},
  "reasons": ["face_match_below_threshold", "glare_on_front_image"]
}

Simulate a response locally

No camera handy? Stub the endpoint shape so your onboarding logic can be tested without network calls. Swap the stub for the real requests.post(...) call when going live — the schema is identical.

def simulate_helios_response(external_id="user_12345", decision="approved"):
    return {
        "verification_id": "helios_vrf_SIMULATED",
        "external_id": external_id,
        "decision": decision,
        "scores": {
            "document_authenticity": 0.97,
            "face_match": 0.93 if decision == "approved" else 0.61,
            "liveness": 0.99,
            "overall": 0.96 if decision == "approved" else 0.74,
        },
        "reasons": [] if decision == "approved" else ["face_match_below_threshold"],
        "extracted": {
            "full_name": "Test User",
            "document_number": "T0000001",
            "date_of_birth": "1990-01-01",
            "expiry_date": "2030-01-01",
            "issuing_country": "NP",
        },
        "model_used": "helios-kyc-1.0",
    }
 
assert simulate_helios_response()["decision"] == "approved"
assert simulate_helios_response(decision="review")["reasons"] == ["face_match_below_threshold"]

Verify

A successful run returns HTTP 200 with a decision of approved, review, or declined. If it doesn't, check the error table below.

ErrorCauseFix
401 UnauthorizedAPI key is incorrect or not setRun echo $SAGEA_API_KEY to confirm the variable is set
400 missing_artifactfront_image, back_image (v1), or liveness_video absentAttach all required files; v2 needs front_image_b64 + liveness_video_b64 minimum
413 Payload Too LargeVideo or images exceed limits (video max ~50MB)Compress to 720p, trim to 3–10s
422 spoof_detectedPrinted face or screen replay detectedRecapture a live selfie video with no filters

What's next

On this page