Face Scan Embed API

Face Scan Embed API

Self-hosted integration documentation for the Face Scan experience

v1.0
REST API

The Face Scan Embed API enables partners to deploy a Next.js application that collects user intake details, creates patient records, and loads the Face Scan experience within an iframe.

This documentation covers the complete integration flow, including authentication, environment setup, data requirements, and runtime behavior.

ℹ️

Integration Method

iframe only - All integrations must use the iframe embed method with camera permissions enabled.

Authentication

Authentication is handled through a validate endpoint that returns a bearer token. This token must be included in all Create Patient API requests.

Required Credentials

Provided by Face Scan per partner and environment

funnelID
Required

Partner attribution ID (e.g., partner-acme-prod)

AWS_VALIDATE_URL
Required

Endpoint URL for token retrieval

AWS_USERNAME / AWS_PASSWORD
Required

Credentials for validate authentication

Scan base URL
Required

Base URL for scan iframe (e.g., https://vitals.scanyourface.co)

Environment Variables

Configure these environment variables in your hosting platform. Without them, createPatient or scan loading will fail.

VariableRequiredDescription
NEXT_PUBLIC_SCAN_BASE_URL
Yes
Base scan page URL
AWS_VALIDATE_URL
Yes
Validate endpoint URL
AWS_USERNAME
Yes
Validate username
AWS_PASSWORD
Yes
Validate password
AWS_CREATE_PATIENT_URL
Yes
Create Patient API base URL
AWS_CREATE_PATIENT_DATA_TYPE
Optional
Defaults to non-sensitive

Website Integration

Embed the deployed application in your website using an iframe with camera permissions enabled.

Implementation

<iframe
  src="https://YOUR-EMBED-DOMAIN.com?funnelID=YOUR_FUNNEL_ID"
  allow="camera; microphone"
  style="width:100%; min-height:85vh; border:0;"
></iframe>

⚠️ Important Requirements

  • Your website must be served over HTTPS
  • The iframe must include allow="camera; microphone"
  • If content appears clipped, increase min-height or use full-height container

Required Intake Fields

The embed flow collects these inputs before proceeding to the scan. All fields are sent to createPatient.

Demographics

  • • biologicalSex
  • • age
  • • height (cm)
  • • weight

Health Data

  • • hypertension (boolean)

Location

  • • city
  • • state
  • • zip

Contact & Consent

  • • firstName
  • • lastName
  • • email
  • • phone
  • • tcpaConsent

Create Patient API

Your embed application calls this endpoint via /api/create-patient to register a patient and obtain confirmation.

Request Payload

{
  "patientUUID": "550e8400-e29b-41d4-a716-446655440000",
  "funnelID": "partner-acme-prod",
  "assessmentType": "FaceScan",
  "biologicalSex": "male",
  "age": 35,
  "height": 175,
  "weight": 70,
  "hypertension": false,
  "city": "San Francisco",
  "state": "CA",
  "zip": "94102",
  "firstName": "John",
  "lastName": "Doe",
  "email": "john.doe@example.com",
  "phone": "+1234567890",
  "tcpaConsent": true
}

Runtime Flow

  1. User completes all intake screens
  2. System generates unique patientUUID
  3. Call /api/create-patient with intake data
  4. Endpoint calls validate to obtain bearer token
  5. Endpoint calls Create Patient API with token and payload
  6. Build scan URL with PatientUUID, funnelID, and embedData
  7. Load scan iframe

Embed Data

embedData is a base64url-encoded JSON string passed to the scan page containing required demographics for the Face Scan SDK.

Required Fields

sex

0 = female, 1 = male

Required
age

Number value

Required
height

Value in centimeters

Required
weight

Number value

Required
bp_mode

Ternary value (implementation-specific)

Required
bp_group

hypertension / normal

Required
facing_mode

user or environment

Required
email

User email address

Required

Encoding Example

function toBase64Url(obj) {
  const json = JSON.stringify(obj);
  const b64 = btoa(unescape(encodeURIComponent(json)));
  return b64.replace(/\+/g, '-').replace(/\//g, '_').replace(/=+$/g, '');
}

// Example usage
const embedData = toBase64Url({
  sex: 1,
  age: 35,
  height: 175,
  weight: 70,
  bp_mode: 0,
  bp_group: "normal",
  facing_mode: "user",
  email: "john.doe@example.com"
});

const scanUrl = `${scanBaseUrl}/scan.html?PatientUUID=${uuid}&funnelID=${funnelID}&embedData=${embedData}`;

Decoding Example

function fromBase64Url(str) {
  let b64 = str.replace(/-/g, '+').replace(/_/g, '/');
  while (b64.length % 4) b64 += '=';
  
  const json = decodeURIComponent(escape(atob(b64)));
  return JSON.parse(json);
}

PostMessage Events

The scan iframe communicates with the embed application via postMessage events. Listen for these events to handle scan lifecycle.

HIQOR_SCAN_COMPLETE
Success

Fired when scan completes successfully. Scan page typically redirects to results view inside iframe.

HIQOR_CAMERA_ERROR
Error

Camera initialization failed. Show retry overlay - retry should reload scan iframe.

{
  "type": "HIQOR_CAMERA_ERROR",
  "message": "Camera access denied"
}
HIQOR_START_MEASURING_FAILED
Error

Measurement process failed to start. Show retry overlay - retry should reload scan iframe.

HIQOR_IFRAME_HEIGHT
Optional

Resize hint to adjust iframe height and avoid clipping (if implemented).

Implementation Example

window.addEventListener('message', (event) => {
  const { type, message } = event.data;
  
  switch (type) {
    case 'HIQOR_SCAN_COMPLETE':
      console.log('Scan completed successfully');
      // Handle completion
      break;
      
    case 'HIQOR_CAMERA_ERROR':
      console.error('Camera error:', message);
      // Show retry UI
      break;
      
    case 'HIQOR_START_MEASURING_FAILED':
      console.error('Measurement failed:', message);
      // Show retry UI
      break;
      
    case 'HIQOR_IFRAME_HEIGHT':
      // Adjust iframe height if needed
      break;
  }
});

Refresh Methods

Different refresh strategies achieve different outcomes. Choose the correct method based on your use case.

Retry During Scan (Recommended)

Use for camera or measurement failures. Reloads scan iframe with same PatientUUID.

// Reload iframe src to retry scan
iframe.src = iframe.src;

Refresh Results View

Refreshes the results displayed inside the scan iframe. Add cache-busting timestamp if needed.

<iframe
  src="https://YOUR-EMBED-DOMAIN.com?funnelID=YOUR_FUNNEL_ID&ts=1700000000000"
  allow="camera; microphone"
  style="width:100%; min-height:85vh; border:0;"
></iframe>

Start New Scan Session

Refresh the full embed app to restart intake flow with new PatientUUID.

// Refresh parent embed to start completely new scan
window.location.reload();

Troubleshooting

Common issues and their solutions.

Camera not working

Cause: Missing HTTPS or camera permissions

Solution: Ensure website uses HTTPS and iframe includes allow="camera; microphone"

createPatient failing

Cause: Invalid credentials or missing environment variables

Solution: Verify AWS_VALIDATE_URL, AWS_USERNAME, AWS_PASSWORD, and AWS_CREATE_PATIENT_URL are correctly set

Blank scan iframe

Cause: Incorrect scan base URL

Solution: Confirm NEXT_PUBLIC_SCAN_BASE_URL is correct and /scan.html endpoint is reachable

Missing demographics errors

Cause: embedData not included or malformed

Solution: Ensure embedData is properly base64url-encoded and includes all required fields

Need Support?

Provide these details when requesting assistance:

  • Your embed deployment URL and iframe src URL (including funnelID)
  • Timestamp of the test and browser/device used
  • Screenshots of errors and console output
  • HTTP status and error message from /api/create-patient

Go-Live Checklist

Complete this checklist before deploying to production.

  • Confirm funnelID is present and correct in iframe src URL
  • Verify all environment variables are set and deployment has been redeployed
  • Test scan on desktop Chrome and at least one mobile browser
  • Verify createPatient succeeds (no 401/403 from validate; no 5xx from createPatient)
  • Verify camera permission prompt appears and scan completes
  • Verify "Try again" works for camera errors