This is intended for technical developer who will implement One Smart Lab’s Rest API Services

 

Currently, One Smart Lab offers 3 primary access:

  1. PhotoVerify
    • confirm that face in a selfie picture matches the ID
    • confirm that the face in the selfie is not spoofed
  2. VideoVerify
    • confirm that face in a selfie video matches the ID
    • confirm that the user has spoken a 6 digit number that your app generates and asks the user to repeat
    • confirm that the face in the selfie is not spoofed
  3. SpoofDetect
    • confirm that the face in the selfie is not spoofed

Current API version is 1.1.

For apps needing more “industrial strength” verification of the user, we recommend VideoVerify since it uses both deep neural network and behavioral spoof detection. It is much harder to “fool” the AI with a video than a single photo because One Smart Lab AI model is able to pick up subtle nuances in video time series.

 


Create an API Key


/photoverify

URL EndPoint:

  • https://api.onesmartlab.com/v1.1/photoverify

POST Parameters:

  • id_card – HTTP multipart POST data for ID card that contains the face of the person you are trying to authenticate
  • photo – HTTP multipart POST  data for image that contains the person’s selfie taken real time
  • api_key – your API key

API Call Example

curl:

id_card=/path/to/your/id_card.jpg
photo=/path/to/your/selfie_pic.jpg
server="https://api.onesmartlab.com/v1.1/photoverify"
api_key="YOUR_API_KEY"

curl -X POST \
  -F "api_key=$api_key" \
  -F "id_card=@$id_card" \
  -F "photo=@$photo" \
  $server

 

python:

import requests


data = {
  "api_key" : "YOUR_API_KEY"
}

files = {
  "id_card" : open('/path/to/your/id_card.jpg', 'rb'), 
  "photo" : open('/path/to/your/selfie_photo.jpg', 'rb')
}
r = requests.post("https://api.onesmartlab.com/v1.1/photoverify", data=data, files=files)
print(r.text)

 

php:

$url = "https://api.onesmartlab.com/v1.1/photoverify"

$data = array(
    "api_key"   => "YOUR_API_KEY",
    "id_card"   => new \CurlFile("/path/to/your/selfie.jpg", 'image/jpeg', 'id_pic.jpg'),
    "photo"   => new \CurlFile("/path/to/your/selfie.jpg", 'image/jpeg', 'selfie.jpg') 
);

$curl = curl_init();
curl_setopt($curl, CURLOPT_POST, 1);
curl_setopt($curl, CURLOPT_POSTFIELDS, $data);
curl_setopt($curl, CURLOPT_URL, $url);
curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1);

$result = curl_exec($curl);

curl_close($curl);

print_r($result)

 

JSON Response:

  • if error exists
    • {“error” : “SOME_ERROR”}
  • if successful:
{
    "predictions":{
        "duration":"1.10",
        "end":1534534646.186395,
        "model_input":{
            "audiochallenge":null,
            "languageCode":null,
            "video":{
                "fps":null,
                "frames":null,
                "height":null,
                "width":null
            }
        },
        "model_output":{
            "audio_challenge_passed":true,
            "face_distance_avg":0.7475451231002808,
            "face_sameness":0.0,
            "largest_face_to_frame_ratio":0.5253456221198156,
            "non_spoof_detected":1.0,
            "single_face_in_frames":1.0,
            "transcription":null
        },
        "model_params":{
            "FACE_TO_FRAME_RATIO_MAX":0.7,
            "THRESHOLD_FACE_SIMILARITY":0.9,
            "THRESHOLD_L2_DISTANCE":0.9,
            "THRESHOLD_SPOOF":0.9
        },
        "start":1534534645.0817783,
        
        "verification":{  
         "breakdown":{  
            "id_card":{  
               "face_to_frame_width_ratio":0.0966796875,
               "not_spoof_confidence":"0.65",
               "not_spoof_passed":true,
               "num_faces":1
            },
            "photo":{  
               "distance":0.5682702660560608,
               "face_to_frame_width_ratio":0.4419047619047619,
               "not_spoof_confidence":"1.00",
               "not_spoof_passed":true,
               "num_faces":1
            }
         },
         "status":true
      }
    },
    "success":true
}

 

How to Determine if Self Photo Matches the ID & is NOT Spoofing

Check field – json[“predictions”][“verification”][“status”]

 

Explanation of the Fields

{
    "predictions":{
        "duration":"How long the model took to run",
        "end":"Time model prediction ended, Milliseconds since Unix Epoch",
        "model_input":{
            "audiochallenge":"Should be null since this is photo verification, not video",
            "languageCode":"Should be null since this is photo verification, not video",
            "video":{
                "fps":"Should be null since this is photo verification, not video",
                "frames":"Should be null since this is photo verification, not video",
                "height":"Should be null since this is photo verification, not video",
                "width":"Should be null since this is photo verification, not video"
            }
        },
        "model_output":{
            "audio_challenge_passed":"Should be True since this is photo verification, not video",
            "face_distance_avg":"[MODERATION_FIELD] How far the face is from the ID. The closer the face to the ID, the lower this number should be. We currently use THRESHOLD_FACE_SIMILARITY.",
            "face_sameness":"Should be null or zero since this is photo verification, not video",
            "largest_face_to_frame_ratio":"[MODERATION_FIELD] How big the face width is relative to the video frame width, in percentage. We currently use FACE_TO_FRAME_RATIO_MAX as acceptable max limit.",
            "non_spoof_detected":"[MODERATION_FIELD] How likely that the faces found are spoofed. Closer to 1 means more normal. Closer to 0 means more likely to be spoofing",
            "single_face_in_frames":"Should be 1 since this is photo verification, not video.",
            "transcription":"Should be null since there is no audio"
        },
        "model_params":{
            "FACE_TO_FRAME_RATIO_MAX":"0.7 but YOU CAN SAFELY IGNORE. Internal Value for OneSmartLab team" ,
            "THRESHOLD_FACE_SIMILARITY":"0.9 but YOU CAN SAFELY IGNORE. Internal Value for OneSmartLab team" ,
            "THRESHOLD_L2_DISTANCE":"0.9 but YOU CAN SAFELY IGNORE. Internal Value for OneSmartLab team" ,
            "THRESHOLD_SPOOF":"0.9 but YOU CAN SAFELY IGNORE. Internal Value for OneSmartLab team"
        },
        "start":"Time model prediction started, Milliseconds since Unix Epoch"
        
        "verification":{  
         "breakdown":{  
            "id_card":{  
               "face_to_frame_width_ratio": "Face to Frame Ratio",
               "not_spoof_confidence":"Confidence that this is not spoof",
               "not_spoof_passed":"Whether or not the confidence exceeds threshold",
               "num_faces":"Number of faces detected"
            },
            "photo":{  
               "distance":"How far the face is from the photo is from the ID, smaller is bette",
               "face_to_frame_width_ratio":"Face to Frame Ratio",
               "not_spoof_confidence":"Confidence that this is not spoof",
               "not_spoof_passed":"Whether or not the confidence exceeds threshold",
               "num_faces":"Number of faces detected"
            }
         },
         "status":"Whether or not face is matched to the ID"
      }
    },
    "success":"true if everything ran correctly"
}

 

 

/videoverify

URL EndPoint:

  • https://api.onesmartlab.com/v1.1/videoverify

POST Parameters:

  • id_card – HTTP multipart POST data for ID card that contains the face of the person you are trying to authenticate
  • video – HTTP multipart POST  data for video that contains the person’s selfie taken real time
    • This video must be valid MP4 video file
    • The speaker in the video must clearly show his/her face speaking the 6 digit audiochallenge that your app. See example
    • Please view the video guidelines as it contains detailed information on how the video should be taken
  • audiochallenge – sequence of 6 digits your app has requested the user to speak in the video
  • languageCode (notice the capital “C”) – language that the user has spoken in, such as “en-US” (view the accepted language codes)
  • api_key – your API key

 

API Call Example

curl:

id_card=/path/to/your/id_card.jpg
video=/path/to/your/selfie_video.mp4
server="https://api.onesmartlab.com/v1.1/videoverify"
audiochallenge="YOUR_6_DIGIT_AUDIOCHALLENGE"
languageCode="YOUR_LANGUAGE_CODE"
api_key="YOUR_API_KEY"

curl -X POST \
  -F "api_key=$api_key" \
  -F "id_card=@$id_card" \
  -F "video=@$video" \
  -F "audiochallenge=$audiochallenge" \
  -F "languageCode=$languageCode"
  $server

 

python:

import requests


data = {  
  "audiochallenge" : "YOUR_AUDIO_CHALLENGE",
  "languageCode" : "YOUR_LANGUAGE_CODE",
  "api_key" : "YOUR_API_KEY"
}

files = {
  "id_card" : open('/path/to/your/id_card.jpg', 'rb'), 
  "video" : open('/path/to/your/selfie_video.mp4', 'rb')
}
r = requests.post("https://api.onesmartlab.com/v1.1/videoverify", data=data, files=files)
print(r.text)

 

php:

$url = "https://api.onesmartlab.com/v1.1/photoverify"

$data = array(
    "api_key"   => "YOUR_API_KEY",
    "audiochallenge" => "YOUR_AUDIO_CHALLENGE", 
    "languageCode"  => "YOUR_LANGUAGE_CODE",
    "id_card" => new \CurlFile("/path/to/your/selfie.jpg", 'image/jpeg', 'id_pic.jpg'),
    "video" => new \CurlFile("/path/to/your/selfie_video.mp4", 'video/mp4', 'selfie_video.mp4')
);

$curl = curl_init();
curl_setopt($curl, CURLOPT_POST, 1);
curl_setopt($curl, CURLOPT_POSTFIELDS, $data);
curl_setopt($curl, CURLOPT_URL, $url);
curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1);

$result = curl_exec($curl);

curl_close($curl);

print_r($result)

 

Response:

  • if error exists
    • {“error” : “SOME_ERROR”}
  • sample successful response:
{
    "predictions":{
        "duration":"55.86",
        "end":1534534753.1725538,
        "model_input":{
            "audiochallenge":"123457",
            "languageCode":"th-TH",
            "video":{
                "fps":30,
                "frames":105,
                "height":480,
                "width":640
            }
        },
        "model_output":{
            "audio_challenge_passed":true,
            "face_distance_avg":0.5534744282563527,
            "face_sameness":0.9904761904761905,
            "largest_face_to_frame_ratio":0.334375,
            "non_spoof_detected":1.0,
            "single_face_in_frames":1.0,
            "transcription":{
                "results":[
                    {
                        "alternatives":[
                            {
                                "confidence":0.95064026,
                                "transcript":"1 2 3 4 5 7 "
                            }
                        ]
                    }
                ]
            }
        },
        "model_params":{
            "FACE_TO_FRAME_RATIO_MAX":0.7,
            "THRESHOLD_FACE_SIMILARITY":0.9,
            "THRESHOLD_L2_DISTANCE":0.9,
            "THRESHOLD_SPOOF":0.9
        },
        "start":1534534697.3109004,
        "verification":{
            "breakdown":{
                "audio_challenge_passed":true,
                "face_to_frame_width_ratio_passed":true,
                "not_spoof_passed":true,
                "video_face_no_change_passed":true,
                "video_face_to_id_face_passed":true
            },
            "status":true
        }
    },
    "success":true
}

How to Determine if Self Video Matches the ID  & isn’t Spoofing

Check field – json[“predictions”][“verification”][“status”]

 

Explanation of the Fields

{
    "predictions":{
        "duration":"How long the model took to run",
        "end":"Time model prediction ended, Milliseconds since Unix Epoch",
        "model_input":{
            "audiochallenge":"sequence of numbers that the user is supposed to say in the video",
            "languageCode":"language code passed to the model",
            "video":{
                "fps":"Frames per second in video",
                "frames":"# of frames in video",
                "height":"Video height",
                "width":"Video width"
            }
        },
        "model_output":{
            "audio_challenge_passed":"whether or not the user has spoken the sequence of numbers",
            "face_distance_avg":"[MODERATION_FIELD] How far the face is from the ID. The closer the face to the ID, the lower this number should be. We currently use THRESHOLD_FACE_SIMILARITY.",
            "face_sameness":"How 'same' the face looks in the entire video. Closer to 1 is better.",
            "largest_face_to_frame_ratio":"[MODERATION_FIELD] How big the face width is relative to the video frame width, in percentage. We currently use FACE_TO_FRAME_RATIO_MAX as acceptable max limit.",
            "non_spoof_detected":"[MODERATION_FIELD] How likely that the faces found are spoofed. Closer to 1 means more normal. Closer to 0 means more likely to be spoofing",
            "single_face_in_frames":"[MODERATION_FIELD] Whether or not we found weird number of faces (i.e. not 1). Closer to 1 is better.",
            "transcription":{
                "results":[
                    {
                        "alternatives":[
                            {
                                "confidence":"Transcription confidence level - 1 is better",
                                "transcript":"Transcription from the Audio"
                            }
                        ]
                    }
                ]
            }
        },
        "model_params":{
            "FACE_TO_FRAME_RATIO_MAX":"0.7 but YOU CAN SAFELY IGNORE. Internal Value for OneSmartLab team" ,
            "THRESHOLD_FACE_SIMILARITY":"0.9 but YOU CAN SAFELY IGNORE. Internal Value for OneSmartLab team" ,
            "THRESHOLD_L2_DISTANCE":"0.9 but YOU CAN SAFELY IGNORE. Internal Value for OneSmartLab team" ,
            "THRESHOLD_SPOOF":"0.9 but YOU CAN SAFELY IGNORE. Internal Value for OneSmartLab team"
        },
        "start":"Time model prediction started, Milliseconds since Unix Epoch""
        "verification":{
            "breakdown":{
                "audio_challenge_passed":"Whether or not the audio in the video transcribes to match the audiochallenge ",
                "face_to_frame_width_ratio_passed":"Whether or not the face to frame ratio is acceptable",
                "not_spoof_passed": "whether or not spoofing in the photo /video was detected",
                "video_face_no_change_passed":"whether or not the photo /video matches the ID",
                "video_face_to_id_face_passed":"whether or not the face in the photo /video is consistent"
            },
            "status":"True if ALL the breakdown are true. False otherwise."
        }
    },
    "success":"true if everything ran correctly"
}






 

/spoofdetect

URL EndPoint::

  • https://api.onesmartlab.com/v1.1/spoofdetect

POST Parameters:

  • photo – HTTP multipart POST  data for image that contains the person’s selfie taken real time
  • api_key – your API key

API Call Example

 

photo=/path/to/your/photo.jpg
server="https://api.onesmartlab.com/v1.1/spoofdetect"
api_key="YOUR_API_KEY"

curl -X POST \
  -F "api_key=$api_key" \
  -F "photo=@$photo" \
  $server

 

python:

import requests


data = {
  "api_key" : "YOUR_API_KEY"
}

files= {
   "photo" : open('/path/to/your/photo.jpg', 'rb')
}
r = requests.post("https://api.onesmartlab.com/v1.1/spoofdetect", data=data, files=files)
print(r.text)

 

php:

$url = "https://api.onesmartlab.com/v1.1/spoofdetect"

$data = array(
  "api_key"   => "YOUR_API_KEY",
  "id_card" => new \CurlFile("/path/to/your/photo.jpg", 'image/jpeg', 'photo.jpg')
);


$curl = curl_init();
curl_setopt($curl, CURLOPT_POST, 1);
curl_setopt($curl, CURLOPT_POSTFIELDS, $data);
curl_setopt($curl, CURLOPT_URL, $url);
curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1);

$result = curl_exec($curl);

curl_close($curl);

print_r($result)

 

Response:

  • if error exists
    • {“error” : “SOME_ERROR”}
  • sample successful response:
{  
   "predictions":{  
      "metadata":{  
         "face_to_frame_width_ratio":0.9,
         "face_to_frame_width_ratio_passed":false,
         "not_spoof_confidence":"1.00",
         "not_spoof_passed":true,
         "num_faces":1,
         "single_face":true
      },
      "verification":{  
         "breakdown":{  
            "face_to_frame_width_ratio_passed":false,
            "not_spoof_passed":true,
            "single_face":true
         },
         "status":false
      }
   },
   "success":true
}

How to Determine if Selfie Photo is not Spoofed

Check field – json[“predictions”][“verification”][“status”]

 

Explanation of the Fields

{
    "predictions":{
        "metadata":{
            "face_to_frame_width_ratio": ,
            "num_faces":"Number of faces"
        },
        "verification":{
            "breakdown":{
                "face_to_frame_width_ratio_passed":"Whether the ratio of width of the face found in the photo to the width of the detected face is acceptable",
                "not_spoof_passed":"This is non-spoof",
                "single_face":"Whether single face was detected"
            },
            "status": "True if all parameters in breakdown are true. False otherwise"
        }
    },
    "success":"true if everything ran correctly"
}

{  
   "predictions":{  
      "metadata":{  
         "face_to_frame_width_ratio":"Ratio of width of the face found in the photo to the width of the detected face",
         "face_to_frame_width_ratio_passed":"Whether or not the ratio threshold is met",
         "not_spoof_confidence":"Confidence that its not spoof",
         "not_spoof_passed":"Whether or not confidence threshold is met,
         "num_faces":"Number of face",
         "single_face":"true if only 1 face found"
      },
      "verification":{
         "breakdown":{
            "face_to_frame_width_ratio_passed":"Whether the ratio of width of the face found in the photo to the width of the detected face is acceptable",
            "not_spoof_passed":"This is non-spoof",
            "single_face":"Whether single face was detected"
         },
         "status": "True if all parameters in breakdown are true. False otherwise"
      }
    },
    "success":"true if everything ran correctly"
}

 


Create an API Key