Introduction
To utilize the KYC (Know Your Customer) service, you must first register the user using the RegisterUser service. Once the user is registered with their nationalID, you can proceed to use the KYC service by providing the registered nationalID along with a video. The system will then process the information and provide the verification result.
RegisterUser
The RegisterUser endpoint allows users to upload an image along with their national code. This image is then stored and can be used for further verification processes.
HTTP POST Request
POST https://gapi.presentid.com/api/UserImage/saveImage
Parameters
- nationalCode: A unique identifier for the user.
- userImageFile: An image file sent as part of form data.
Example Request
[HttpPost] public async TaskSaveImage([FromForm] string nationalCode, [FromForm] IFormFile userImageFile) { if (string.IsNullOrEmpty(nationalCode) || userImageFile == null || userImageFile.Length == 0) { return BadRequest(new { message = "National code and image file are required." }); } try { string base64Image; using (var memoryStream = new MemoryStream()) { await userImageFile.CopyToAsync(memoryStream); base64Image = Convert.ToBase64String(memoryStream.ToArray()); } var requestData = new { NationalCode = nationalCode, Base64Image = base64Image }; var content = new StringContent(JsonConvert.SerializeObject(requestData), Encoding.UTF8, "application/json"); var request = new HttpRequestMessage { Method = HttpMethod.Post, RequestUri = new Uri("https://gapi.presentid.com/api/UserImage/saveImage"), Content = content, Headers = { { "Authorization", $"Bearer {BearerToken}" } } }; var response = await _httpClient.SendAsync(request); var responseString = await response.Content.ReadAsStringAsync(); Log.Information("SaveImage Response: {Response}", responseString); if (!response.IsSuccessStatusCode) { return StatusCode((int)response.StatusCode, new { message = "Error saving image." }); } return Ok(responseString); } catch (Exception ex) { Log.Error(ex, "Error occurred during SaveImage."); return StatusCode(500, $"Internal server error: {ex.Message}"); } }
Code Breakdown
1. Method Annotation
[HttpPost]: Indicates that this method handles HTTP POST requests.
2. Method Signature
public async Task: Defines an asynchronous method that returns anSaveImage([FromForm] string nationalCode, [FromForm] IFormFile userImageFile)
IActionResult. It accepts two parameters: "nationalCode" and "userImageFile", both sent via form data.
3. Input Validation
if (string.IsNullOrEmpty(nationalCode) || userImageFile == null || userImageFile.Length == 0) { return BadRequest(new { message = "National code and image file are required." }); }Purpose: Ensures that both the national code and image file are provided.
Action: Returns a 400 Bad Request response if validation fails.
4. Converting Image to Base64
string base64Image; using (var memoryStream = new MemoryStream()) { await userImageFile.CopyToAsync(memoryStream); base64Image = Convert.ToBase64String(memoryStream.ToArray()); }Purpose: Converts the uploaded image file to a Base64 string for transmission.
5. Preparing JSON Payload
var requestData = new { NationalCode = nationalCode, Base64Image = base64Image }; var content = new StringContent(JsonConvert.SerializeObject(requestData), Encoding.UTF8, "application/json");Purpose: Creates a JSON payload containing the national code and Base64-encoded image.
6. Creating the HTTP Request
var request = new HttpRequestMessage { Method = HttpMethod.Post, RequestUri = new Uri("https://gapi.presentid.com/api/UserImage/saveImage"), Content = content, Headers = { { "Authorization", $"Bearer {BearerToken}" } } };Purpose: Constructs an HTTP POST request to the "saveImage" endpoint with the JSON payload and authorization header.
7. Sending the Request
var response = await _httpClient.SendAsync(request); var responseString = await response.Content.ReadAsStringAsync();Purpose: Sends the HTTP request asynchronously and reads the response content as a string.
8. Logging the Response
Log.Information("SaveImage Response: {Response}", responseString);Purpose: Logs the server's response for debugging and monitoring purposes.
9. Handling Non-Success Status Codes
if (!response.IsSuccessStatusCode) { return StatusCode((int)response.StatusCode, new { message = "Error saving image." }); }Purpose: Checks if the response indicates a successful request.
Action: If not successful, returns a response with the corresponding HTTP status code and an error message.
10. Returning Success Response
return Ok(responseString);Purpose: Returns a 200 OK response with the server's response content if the request was successful.
11. Exception Handling
catch (Exception ex) { Log.Error(ex, "Error occurred during SaveImage."); return StatusCode(500, $"Internal server error: {ex.Message}"); }Purpose: Catches any exceptions that occur during the request processing.
Action:
- Logs the exception details.
- Returns a 500 Internal Server Error response with the exception message.
Responses
Successful Upload:
HTTP 200 OK Content: { "message": "Video uploaded successfully." }
Request Failure:
HTTP 400 Bad Request Content: { "message": "National code and image file are required." }
Internal Server Error:
HTTP 500 Internal Server Error Content: { "message": "Internal server error: [error description]" }
Liveness Detection
The Liveness Detection endpoint verifies that the video provided by the user displays real human activity, confirming the presence and authenticity of the user at the time the video was recorded.
HTTP POST Request
POST https://gapi.presentid.com/LivenessDetection
Parameters
- video: A video file sent as part of form data. The video should capture the user performing designated actions.
Example Request
[HttpPost("LivenessDetection")] public async TaskLivenessDetection([FromForm] IFormFile video) { if (video == null || video.Length == 0) { Log.Warning("LivenessDetection: No video file provided."); return BadRequest(new { message = "Video file is required." }); } try { using var content = new MultipartFormDataContent(); content.Add(new StreamContent(video.OpenReadStream()), "video", video.FileName); var request = new HttpRequestMessage { Method = HttpMethod.Post, RequestUri = new Uri("https://gapi.presentid.com/LivenessDetection"), Content = content, Headers = { { "Authorization", $"Bearer {BearerToken}" } } }; var response = await _httpClient.SendAsync(request); var responseString = await response.Content.ReadAsStringAsync(); var responseObject = JsonConvert.DeserializeObject (responseString); Log.Information("LivenessDetection Response: {Response}", responseString); if (!response.IsSuccessStatusCode) { return StatusCode((int)response.StatusCode, new { message = responseObject?.message ?? "Error occurred." }); } return Ok(responseString); } catch (Exception ex) { Log.Error(ex, "Error occurred during LivenessDetection."); return StatusCode(500, new { message = $"Internal server error: {ex.Message}" }); } }
Code Breakdown
1. Method Annotation
[HttpPost("LivenessDetection")]: Specifies that this method handles HTTP POST requests sent to the "LivenessDetection" endpoint.
2. Method Signature
public async Task: Defines an asynchronous method that returns anLivenessDetection([FromForm] IFormFile video)
IActionResult. It accepts a single parameter, "video", which is an uploaded file sent via form data.
3. Input Validation
if (video == null || video.Length == 0) { Log.Warning("LivenessDetection: No video file provided."); return BadRequest(new { message = "Video file is required." }); }Purpose: Checks if the video file is present and not empty.
Action: Logs a warning and returns a 400 Bad Request response if validation fails.
4. Try-Catch Block
Encloses the main logic to handle potential exceptions that may occur during the processing of the request.
5. Preparing the Request Content
using var content = new MultipartFormDataContent(); content.Add(new StreamContent(video.OpenReadStream()), "video", video.FileName);Purpose: Creates multipart form data content to send the video file.
Action: Adds the video file stream to the content with the key "video" and the original file name.
6. Creating the HTTP Request
var request = new HttpRequestMessage { Method = HttpMethod.Post, RequestUri = new Uri("https://gapi.presentid.com/LivenessDetection"), Content = content, Headers = { { "Authorization", $"Bearer {BearerToken}" } } };Purpose: Constructs an HTTP POST request to the specified URI.
Action:
- Sets the HTTP method to POST.
- Specifies the request URI.
- Attaches the prepared content.
- Adds an Authorization header with a bearer token for authentication.
7. Sending the Request
var response = await _httpClient.SendAsync(request); var responseString = await response.Content.ReadAsStringAsync(); var responseObject = JsonConvert.DeserializeObjectPurpose: Sends the HTTP request and processes the response.(responseString);
Action:
- Sends the request asynchronously.
- Reads the response content as a string.
- Deserializes the JSON response into a dynamic object for easier access to its properties.
8. Logging the Response
Log.Information("LivenessDetection Response: {Response}", responseString);Purpose: Logs the server's response for debugging and monitoring purposes.
9. Handling Non-Success Status Codes
if (!response.IsSuccessStatusCode) { return StatusCode((int)response.StatusCode, new { message = responseObject?.message ?? "Error occurred." }); }Purpose: Checks if the response indicates a successful request.
Action: If not successful, returns a response with the corresponding HTTP status code and an error message.
10. Returning Success Response
return Ok(responseString);Purpose: Returns a 200 OK response with the server's response content if the request was successful.
11. Exception Handling
catch (Exception ex) { Log.Error(ex, "Error occurred during LivenessDetection."); return StatusCode(500, new { message = $"Internal server error: {ex.Message}" }); }Purpose: Catches any exceptions that occur during the request processing.
Action:
- Logs the exception details.
- Returns a 500 Internal Server Error response with the exception message.
Responses
Successful Processing:
HTTP 200 OK Content: { "message": "Liveness verified successfully." }
Request Failure:
HTTP 400 Bad Request Content: { "message": "Video file is required." }
Internal Server Error:
HTTP 500 Internal Server Error Content: { "message": "Internal server error: [error description]" }
Face Verification
The Face Verification endpoint compares two images to verify if they belong to the same individual. This is essential for confirming the authenticity of the user's identity.
HTTP POST Request
POST https://gapi.presentid.com/FaceVerification
Parameters
- image1: The first image file sent as part of form data.
- image2: The second image file sent as part of form data.
Example Request
[HttpPost] public async TaskVerification([FromForm] IFormFile image1, [FromForm] IFormFile image2) { if (image1 == null || image2 == null || image1.Length == 0 || image2.Length == 0) { Log.Warning("FaceVerification: One or both images are missing."); return BadRequest(new { message = "Both images are required." }); } try { using var content = new MultipartFormDataContent(); content.Add(new StreamContent(image1.OpenReadStream()), "photo1", image1.FileName); content.Add(new StreamContent(image2.OpenReadStream()), "photo2", image2.FileName); var request = new HttpRequestMessage { Method = HttpMethod.Post, RequestUri = new Uri("https://gapi.presentid.com/FaceVerification"), Content = content, Headers = { { "Authorization", $"Bearer {BearerToken}" } } }; var response = await _httpClient.SendAsync(request); var responseString = await response.Content.ReadAsStringAsync(); var responseObject = JsonConvert.DeserializeObject (responseString); Log.Information("FaceVerification Response: {Response}", responseString); if (!response.IsSuccessStatusCode) { return StatusCode((int)response.StatusCode, new { message = responseObject?.message ?? "Error occurred." }); } return Ok(responseString); } catch (Exception ex) { Log.Error(ex, "Error occurred during FaceVerification."); return StatusCode(500, new { message = $"Internal server error: {ex.Message}" }); } }
Code Breakdown
1. Method Annotation
[HttpPost]: Indicates that this method handles HTTP POST requests.
2. Method Signature
public async Task: Defines an asynchronous method that returns anVerification([FromForm] IFormFile image1, [FromForm] IFormFile image2)
IActionResult. It accepts two parameters, "image1" and "image2", which are uploaded files sent via form data.
3. Input Validation
if (image1 == null || image2 == null || image1.Length == 0 || image2.Length == 0) { Log.Warning("FaceVerification: One or both images are missing."); return BadRequest(new { message = "Both images are required." }); }Purpose: Ensures that both image files are provided and not empty.
Action: Logs a warning and returns a 400 Bad Request response if validation fails.
4. Try-Catch Block
Encloses the main logic to handle potential exceptions that may occur during the processing of the request.
5. Preparing the Request Content
using var content = new MultipartFormDataContent(); content.Add(new StreamContent(image1.OpenReadStream()), "photo1", image1.FileName); content.Add(new StreamContent(image2.OpenReadStream()), "photo2", image2.FileName);Purpose: Creates multipart form data content to send both image files.
Action: Adds both image file streams to the content with keys "photo1" and "photo2" respectively.
6. Creating the HTTP Request
var request = new HttpRequestMessage { Method = HttpMethod.Post, RequestUri = new Uri("https://gapi.presentid.com/FaceVerification"), Content = content, Headers = { { "Authorization", $"Bearer {BearerToken}" } } };Purpose: Constructs an HTTP POST request to the "FaceVerification" endpoint with the image files and authorization header.
7. Sending the Request
var response = await _httpClient.SendAsync(request); var responseString = await response.Content.ReadAsStringAsync(); var responseObject = JsonConvert.DeserializeObjectPurpose: Sends the HTTP request and processes the response.(responseString);
Action:
- Sends the request asynchronously.
- Reads the response content as a string.
- Deserializes the JSON response into a dynamic object.
8. Logging the Response
Log.Information("FaceVerification Response: {Response}", responseString);Purpose: Logs the server's response for debugging and monitoring purposes.
9. Handling Non-Success Status Codes
if (!response.IsSuccessStatusCode) { return StatusCode((int)response.StatusCode, new { message = responseObject?.message ?? "Error occurred." }); }Purpose: Checks if the response indicates a successful request.
Action: If not successful, returns a response with the corresponding HTTP status code and an error message.
10. Returning Success Response
return Ok(responseString);Purpose: Returns a 200 OK response with the server's response content if the request was successful.
11. Exception Handling
catch (Exception ex) { Log.Error(ex, "Error occurred during FaceVerification."); return StatusCode(500, new { message = $"Internal server error: {ex.Message}" }); }Purpose: Catches any exceptions that occur during the request processing.
Action:
- Logs the exception details.
- Returns a 500 Internal Server Error response with the exception message.
Responses
Successful Verification:
HTTP 200 OK Content: { "message": "Verification successful.", "isMatch": true }
Request Failure:
HTTP 400 Bad Request Content: { "message": "Both images are required." }
Internal Server Error:
HTTP 500 Internal Server Error Content: { "message": "Internal server error: [error description]" }
KYC
The KYC endpoint allows users to upload a video along with their national code. This video is then used in conjunction with other services such as liveness detection and face verification.
HTTP POST Request
POST https://gapi.presentid.com/IQAandFaceVerification
Parameters
- video: A video file sent as part of form data.
- nationalCode: A unique identifier for the user.
Example Request
[HttpPost] public async TaskUploadVideo([FromForm] IFormFile video, [FromForm] string nationalCode) { if (video == null || video.Length == 0) { Log.Warning("UploadVideo: Video file is missing."); return BadRequest(new { message = "Video file is missing." }); } try { using var content = new MultipartFormDataContent(); content.Add(new StreamContent(video.OpenReadStream()), "video", video.FileName); content.Add(new StringContent(nationalCode), "nationalCode"); var request = new HttpRequestMessage { Method = HttpMethod.Post, RequestUri = new Uri("https://gapi.presentid.com/IQAandFaceVerification"), Content = content, Headers = { { "Authorization", $"Bearer {BearerToken}" } } }; var response = await _httpClient.SendAsync(request); var responseString = await response.Content.ReadAsStringAsync(); Log.Information("UploadVideo Response: {Response}", responseString); if (!response.IsSuccessStatusCode) { return StatusCode((int)response.StatusCode, new { message = "Error uploading video." }); } return Ok(responseString); } catch (Exception ex) { Log.Error(ex, "Error uploading video."); return StatusCode(500, $"Internal server error: {ex.Message}"); } }
Code Breakdown
1. Method Annotation
[HttpPost]: Indicates that this method handles HTTP POST requests.
2. Method Signature
public async Task: Defines an asynchronous method that returns anUploadVideo([FromForm] IFormFile video, [FromForm] string nationalCode)
IActionResult. It accepts two parameters: "video" (an uploaded file) and "nationalCode" (a string), both sent via form data.
3. Input Validation
if (video == null || video.Length == 0) { Log.Warning("UploadVideo: Video file is missing."); return BadRequest(new { message = "Video file is missing." }); }Purpose: Ensures that the video file is provided and not empty.
Action: Logs a warning and returns a 400 Bad Request response if validation fails.
4. Try-Catch Block
Encloses the main logic to handle potential exceptions that may occur during the processing of the request.
5. Preparing the Request Content
using var content = new MultipartFormDataContent(); content.Add(new StreamContent(video.OpenReadStream()), "video", video.FileName); content.Add(new StringContent(nationalCode), "nationalCode");Purpose: Creates multipart form data content to send both the video file and the national code.
Action: Adds the video file stream and the national code to the content with appropriate keys.
6. Creating the HTTP Request
var request = new HttpRequestMessage { Method = HttpMethod.Post, RequestUri = new Uri("https://gapi.presentid.com/IQAandFaceVerification"), Content = content, Headers = { { "Authorization", $"Bearer {BearerToken}" } } };Purpose: Constructs an HTTP POST request to the "IQAandFaceVerification" endpoint with the video file, national code, and authorization header.
7. Sending the Request
var response = await _httpClient.SendAsync(request); var responseString = await response.Content.ReadAsStringAsync();Purpose: Sends the HTTP request asynchronously and reads the response content as a string.
8. Logging the Response
Log.Information("UploadVideo Response: {Response}", responseString);Purpose: Logs the server's response for debugging and monitoring purposes.
9. Handling Non-Success Status Codes
if (!response.IsSuccessStatusCode) { return StatusCode((int)response.StatusCode, new { message = "Error uploading video." }); }Purpose: Checks if the response indicates a successful request.
Action: If not successful, returns a response with the corresponding HTTP status code and an error message.
10. Returning Success Response
return Ok(responseString);Purpose: Returns a 200 OK response with the server's response content if the request was successful.
11. Exception Handling
catch (Exception ex) { Log.Error(ex, "Error uploading video."); return StatusCode(500, $"Internal server error: {ex.Message}"); }Purpose: Catches any exceptions that occur during the request processing.
Action:
- Logs the exception details.
- Returns a 500 Internal Server Error response with the exception message.
Responses
Successful Upload:
HTTP 200 OK Content: { "message": "Video uploaded successfully." }
Request Failure:
HTTP 400 Bad Request Content: { "message": "Video file is missing." }
Internal Server Error:
HTTP 500 Internal Server Error Content: { "message": "Internal server error: [error description]" }
Front
The following code demonstrates the front-end implementation for the KYC (Know Your Customer) process. This implementation allows users to enter their national code, access their camera, perform face detection, record a video, and submit the data to the server.
Front-End Code
<link href="~/css/site.css" rel="stylesheet" /> <div class="relative" style="margin-top: 100px"> <h1 class="text-3xl m-4 text-gray-600" style="text-align: center">Know Your Customer</h1> <div class="relative p-4"> <form id="uploadForm" style="text-align: center"> <div class="mb-4 pt-0 flex flex-col"> <label class="mb-2 text-gray-800 text-lg font-light" for="nationalCode">National Code:</label> <input type="text" id="nationalCode" name="nationalCode" class="border-2 rounded h-10 px-6 text-lg text-gray-600 focus:outline-none focus:ring focus:border-blue-300" autocomplete="off" required style="width: 300px; margin: auto"> </div> <div id="videoContainer"> <div id="feedback"></div> <video id="videotoPreview" autoplay muted></video> <div class="overlay border-red"></div> <div class="red-dot" id="redDot"></div> </div> <button type="button" class="bg-yellow-500 text-white p-5 h-16 rounded-lg font-bold" id="openCamera">Open Camera</button> <button type="button" class="bg-green-500 text-white p-5 h-16 rounded-lg font-bold" id="startRecording" disabled>Start Recording</button> <button type="button" class="hidden" id="stopRecording" disabled>Stop Recording</button> <p id="timer">Time Left: <span id="timerValue">5</span> seconds</p> <br><br> <input type="hidden" id="videoBlob" name="videoBlob"> <button type="submit" class="bg-blue-500 p-5 text-white h-16 rounded-lg font-bold">Submit</button> <p id="loading">Submitting... Please wait.</p> <div id="responseMessage" style="margin-top: 30px"></div> </form> </div> </div> <script src="~/js/tfjs.js"></script> <script src="~/js/blazeface.js"></script> <script> const openCameraButton = document.getElementById('openCamera'); const videotoPreview = document.getElementById('videotoPreview'); const startRecordingButton = document.getElementById('startRecording'); const stopRecordingButton = document.getElementById('stopRecording'); const uploadForm = document.getElementById('uploadForm'); // Added declaration const responseMessage = document.getElementById('responseMessage'); const loading = document.getElementById('loading'); const timer = document.getElementById('timer'); const timerValue = document.getElementById('timerValue'); const redDot = document.getElementById('redDot'); let mediaRecorder; let recordedChunks = []; let countdown; let stream; // Added declaration openCameraButton.addEventListener('click', async () => { try { stream = await navigator.mediaDevices.getUserMedia({ video: true }); videotoPreview.srcObject = stream; startRecordingButton.disabled = false; openCameraButton.disabled = true; console.log('Camera opened successfully.'); const model = await blazeface.load(); // Removed modelUrl if not necessary console.log('BlazeFace model loaded.'); detectFaces(model); } catch (err) { console.error('Error accessing camera:', err); alert('Could not access the camera. Please check your device settings.'); } }); async function detectFaces(model) { const canvas = document.createElement('canvas'); const context = canvas.getContext('2d'); canvas.width = videotoPreview.videoWidth || 400; canvas.height = videotoPreview.videoHeight || 300; const feedbackMessage = document.getElementById('feedback'); feedbackMessage.style.position = 'absolute'; feedbackMessage.style.color = 'white'; feedbackMessage.style.fontSize = '15px'; feedbackMessage.style.width = '100%'; feedbackMessage.style.backgroundColor = 'rgba(0, 0, 0, 0.7)'; feedbackMessage.style.padding = '10px'; feedbackMessage.style.borderRadius = '5px'; feedbackMessage.style.zIndex = '5'; feedbackMessage.innerText = ''; const overlay = document.querySelector('.overlay'); const ellipseX = canvas.width / 2; const ellipseY = canvas.height / 2; const ellipseWidth = 139; const ellipseHeight = 177; const minFaceWidth = 150; const maxFaceWidth = 250; setInterval(async () => { context.drawImage(videotoPreview, 0, 0, canvas.width, canvas.height); const predictions = await model.estimateFaces(canvas, false); if (predictions.length > 0) { const face = predictions[0]; const startX = face.topLeft[0]; const startY = face.topLeft[1]; const endX = face.bottomRight[0]; const endY = face.bottomRight[1]; const faceWidth = endX - startX; const faceHeight = endY - startY; const faceCenterX = (startX + endX) / 2; const faceCenterY = (startY + endY) / 2; const normalizedX = (faceCenterX - ellipseX) / ellipseWidth; const normalizedY = (faceCenterY - ellipseY) / ellipseHeight; const isInsideEllipse = (normalizedX ** 2 + normalizedY ** 2) <= 1; const isFaceSizeValid = faceWidth >= minFaceWidth && faceWidth <= maxFaceWidth; if (isInsideEllipse && isFaceSizeValid) { redDot.style.backgroundColor = 'green'; overlay.classList.add('border-green'); overlay.classList.remove('border-red'); feedbackMessage.innerText = 'Face detected and positioned correctly!'; } else { redDot.style.backgroundColor = 'red'; overlay.classList.add('border-red'); overlay.classList.remove('border-green'); let feedback = 'Adjust your position: '; if (!isInsideEllipse) { if (faceCenterX < ellipseX) feedback += 'Move left, '; if (faceCenterX > ellipseX) feedback += 'Move right, '; if (faceCenterY < ellipseY) feedback += 'Move down, '; if (faceCenterY > ellipseY) feedback += 'Move up, '; } if (!isFaceSizeValid) { if (faceWidth < minFaceWidth) feedback += 'Move closer.'; if (faceWidth > maxFaceWidth) feedback += 'Move farther.'; } feedbackMessage.innerText = feedback.trim().replace(/,\s*$/, '.'); } } else { redDot.style.backgroundColor = 'red'; overlay.classList.add('border-red'); overlay.classList.remove('border-green'); feedbackMessage.innerText = 'No face detected. Please position yourself in front of the camera.'; } }, 100); } startRecordingButton.addEventListener('click', () => { if (!stream) { alert('Camera is not open.'); return; } recordedChunks = []; mediaRecorder = new MediaRecorder(stream, { mimeType: 'video/webm' }); // Specified MIME type mediaRecorder.ondataavailable = event => { if (event.data.size > 0) { recordedChunks.push(event.data); } }; mediaRecorder.start(); startRecordingButton.disabled = true; stopRecordingButton.disabled = false; timer.style.display = 'block'; redDot.style.display = 'block'; let timeLeft = 5; timerValue.textContent = timeLeft; countdown = setInterval(() => { timeLeft -= 1; timerValue.textContent = timeLeft; if (timeLeft <= 0) { clearInterval(countdown); mediaRecorder.stop(); timer.style.display = 'none'; redDot.style.display = 'none'; startRecordingButton.disabled = false; stopRecordingButton.disabled = true; console.log('Recording stopped automatically after 5 seconds.'); } }, 1000); }); stopRecordingButton.addEventListener('click', () => { clearInterval(countdown); mediaRecorder.stop(); timer.style.display = 'none'; redDot.style.display = 'none'; startRecordingButton.disabled = false; stopRecordingButton.disabled = true; }); uploadForm.addEventListener('submit', async (event) => { event.preventDefault(); const nationalCode = document.getElementById('nationalCode').value; if (!nationalCode) { responseMessage.textContent = 'Please enter your national code.'; responseMessage.style.color = 'red'; return; } if (recordedChunks.length === 0) { responseMessage.textContent = 'Please record a video before submitting.'; responseMessage.style.color = 'red'; return; } const blob = new Blob(recordedChunks, { type: 'video/webm' }); // Changed to match MIME type const formData = new FormData(); formData.append('nationalCode', nationalCode); formData.append('video', blob, 'recorded_video.webm'); // Changed extension to match MIME type loading.style.display = 'block'; try { const response = await fetch('/Home/UploadVideo', { // Updated URL to a placeholder method: 'POST', body: formData, }); const result = await response.json(); if (response.ok) { responseMessage.innerHTML = `<pre class="text-green-700" style="color: rgb(60 255 0); background: #000; text-align: left; overflow: auto;">${JSON.stringify(result, null, 2)}</pre>`; } else { responseMessage.innerHTML = `<p class='text-red-500'>Error: ${result.message || "An unknown error occurred."}</p>`; } } catch (err) { console.error('Error sending video:', err); responseMessage.textContent = 'Error occurred while sending the video.'; responseMessage.style.color = 'red'; } finally { loading.style.display = 'none'; } }); </script>
VerifyVideo API
The VerifyVideo API processes a video and an image to verify if they belong to the same person.
Note: A valid Bearer Token must be included in the request header as Authorization: Bearer <token>
.
Workflow:
-
Receive Files: The API accepts two files via multipart form data:
video
: The video file capturing the user's actions.image
: The image file of the user.
- Liveness Detection: The API calls the LivenessDetection service to check if the video is live (not spoofed).
- Face Verification: The extracted frame and the original image are sent to the FaceVerification service to compare the faces.
HTTP POST Request
POST https://gapi.presentid.com/verifyvideo
Headers
Authorization: Bearer <token>
– A valid Bearer Token is required for authentication.
Input Parameters
- video: A video file (multipart/form-data) capturing the user's actions.
- image: An image file (multipart/form-data) of the user.
Expected Output
The response is a JSON object with the following structure:
{ "statusCode": 200, "statusMessage": "OK", "data": { "resultIndex": 3, "resultMessage": "The two faces belong to different people.", "similarPercent": 0.5345810558997499 } }
Interpretation of resultIndex
:
0
: The two faces are exactly the same.1
: The two faces are almost identical.2
: The two faces are moderately similar.3
: The two faces are completely different.
Your application should determine the final verification outcome based on the resultIndex
value.