Integration guide

AI Tools

After completing the onboarding process on Yoti Hub, you can begin integrating our AI services API for retail terminals and self-checkouts.

Note: Once your organisation account is verified and you have generated the SDK ID for the 'Age Estimation' application, please contact us to have it whitelisted. This step is required to use our dedicated endpoint for this integration.

Face Capture

To ensure optimal face capture, Yoti offers the Face Capture Module (FCM), designed to capture images that meet the API’s requirements. This is available as a React/JavaScript module and a native .NET package.

Native face capture

Capture your images by using our Face Capture Module (FCM).


SDK Integration

To simply the integration process, Yoti provides SDKs to integrate with our API. These are available via popular dependency management systems.

npm install -S -E yoti
// If you are using Maven, add the following dependency: <dependency> <groupId>com.yoti</groupId> <artifactId>yoti-sdk-api</artifactId> <version>3.5.1</version> </dependency> // If you are using Gradle, add the following dependency: compile group: 'com.yoti', name: 'yoti-sdk-api', version: '3.5.1'
// Get the Yoti PHP SDK library via a Composer package composer require yoti/yoti-php-sdk
pip install yoti
// To install the Yoti NuGet package you will need to install NuGet. // To import the latest Yoti SDK into your project, enter the following // command from NuGet Package Manager Console in Visual Studio: Install-Package Yoti // For other installation methods, see https://www.nuget.org/packages/Yoti
// Simply add this as an import: import "github.com/getyoti/yoti-go-sdk/v3" // Or add the following line to your go.mod file require github.com/getyoti/yoti-go-sdk/v3 // Or you can run the following command in your terminal: go get github.com/getyoti/yoti-go-sdk/v3
gem install yoti # The gem provides a configuration generator for Ruby on Rails: rails generate yoti:install

Create a request

Once you have added the Yoti SDK dependency to your project, you can use it to build and send your request. See the code snippets below for examples.

const PATHS = { AGE_LIVENESS: '/age-antispoofing', }; const data = { img: 'base64img', }; const request = new RequestBuilder() .withBaseUrl('https://api.yoti.com/ai/v1/self-checkout') .withPemFilePath('<YOTI_KEY_FILE_PATH>') .withEndpoint(PATHS.AGE_LIVENESS) .withPayload(new Payload(data)) .withMethod('POST') .withHeader('X-Yoti-Auth-Id', '<YOTI_CLIENT_SDK_ID>') .withHeader('Terminal-Id', '<TERMINAL_ID>') .withHeader('Session-Id', '<SESSION_ID>') // Optional .build(); const response = request.execute();
String AGE_LIVENESS = "/age-antispoofing"; JsonObject body = new JsonObject(); body.put("img", imageBytes); byte[] payload = body.encode().getBytes(); try { SignedRequest signedRequest = new SignedRequestBuilder() .withKeyPair(<YOTI_KEY_FILE_PATH>) .withBaseUrl("https://api.yoti.com/ai/v1/self-checkout") .withEndpoint(AGE_LIVENESS) .withPayload(payload) .withHttpMethod("POST") .withHeader("X-Yoti-Auth-Id", "<YOTI_CLIENT_SDK_ID>") .withHeader('Terminal-Id', '<TERMINAL_ID>') .withHeader('Session-Id', '<SESSION_ID>') // Optional .build(); YourPojo yourPojo = signedRequest.execute(YourPojo.class); } catch (GeneralSecurityException | URISyntaxException | IOException | ResourceException ex) { ex.printStackTrace(); }
<?php use Yoti\Http\RequestBuilder; use Yoti\Http\Payload; define("AGE_LIVENESS", "/age-antispoofing"); $img = [ "img" => "base64Image" ]; $request = (new RequestBuilder()) ->withBaseUrl('https://api.yoti.com/ai/v1/self-checkout') ->withPemFilePath('<YOTI_KEY_FILE_PATH>') ->withEndpoint(AGE_LIVENESS) ->withPayload(Payload::fromJsonData($img)) // For version < 3, use ->withPayload(new Payload($img)) ->withMethod('POST') ->withHeader('X-Yoti-Auth-Id', '<YOTI_CLIENT_SDK_ID>') ->withHeader('Terminal-Id', '<TERMINAL_ID>') ->withHeader('Session-Id', '<SESSION_ID>') // Optional ->build(); // Execute request $response = $request->execute();
from yoti_python_sdk.http import SignedRequest, RequestHandler import json import requests def execute(request): response = requests.request( url=request.url, img=request.img, headers=request.headers, method=request.method) return response.content def generate_session(): payload_string = json.dumps(img).encode() signed_request = ( SignedRequest .builder() .with_pem_file("<YOTI_KEY_FILE_PATH>") .with_base_url("https://api.yoti.com/ai/v1/self-checkout") .with_endpoint("/age-antispoofing") .with_http_method("POST") .with_header("X-Yoti-Auth-Id", "<YOTI_CLIENT_SDK_ID>") .with_header("Terminal-Id", "<TERMINAL_ID>") .with_header("Session-Id", "<SESSION_ID>") // Optional .with_payload(payload_string) .build() ) # Execute request response = signed_request.execute()
using System; using System.IO; using System.Net.Http; using System.Text; using Microsoft.AspNetCore.Mvc; using Yoti.Auth.Web; HttpClient httpClient = new HttpClient(); StreamReader privateKeyStream = System.IO.File.OpenText(_pemFilePath); string serializedRequest = Newtonsoft.Json.JsonConvert.SerializeObject(new { img = _base64Face }); byte[] byteContent = Encoding.UTF8.GetBytes(serializedRequest); Uri _baseUrl = new UriBuilder("https", "api.yoti.com", 443, "ai/v1/self-checkout").Uri; Yoti.Auth.Web.Request ageScanRequest = new RequestBuilder() .WithStreamReader(privateKeyStream) .WithBaseUri(_baseUrl) .WithEndpoint("/age-antispoofing") .WithHttpMethod(HttpMethod.Post) .WithContent(byteContent) .WithHeader("X-Yoti-Auth-Id", _clientSdkId) .withHeader("Terminal-Id", "<TERMINAL_ID>") .withHeader("Session-Id", "<SESSION_ID>") // Optional .Build(); HttpResponseMessage response = ageScanRequest.Execute(httpClient).Result;
import ( "io/ioutil" "net/http" "github.com/getyoti/yoti-go-sdk/v2/requests" ) key, _ := ioutil.ReadFile("<YOTI_KEY_FILE_PATH>") // Create request request,_ := requests.SignedRequest{ HTTPMethod: http.MethodPost, BaseURL: "https://api.yoti.com/ai/v1/self-checkout", Endpoint: "/age-antispoofing", Headers: map[string][]string{ "Content-Type": {"application/img"}, "Accept": {"application/img"}, "X-Yoti-Auth-Id": {"<YOTI_CLIENT_SDK_ID>"}, "Terminal-Id": {"<TERMINAL_ID>"}, "Session-Id": {"<SESSION_ID>"}, // Optional }, Body: func(img []byte, _ error) []byte { return img }(json.Marshal(jsonobj{ data })), }.WithPemFile(key).Request() // Get Yoti response response, _ := http.DefaultClient.Do(request)
require 'yoti' Yoti.configure do |config| config.client_sdk_id = '<YOTI_CLIENT_SDK_ID>' config.key_file_path = '<YOTI_KEY_FILE_PATH>' end request = Yoti::Request .builder .with_base_url('https://api.yoti.com/ai/v1/self-checkout') .with_http_method('POST') .with_endpoint('/age-antispoofing') .with_payload(img: 'base64Image') .with_header('X-Yoti-Auth-Id', Yoti.configuration.client_sdk_id) .with_header('Terminal-Id', '<TERMINAL_ID>') .with_header('Session-Id', '<SESSION_ID>') // Optional .build response = request.execute

JSON example:

{ "img": "/9j/4AAQSkZJRgABAgAAAQABAAD/2wAcHNXCKigjEaYH51Me1Zy1Za0P/Z...." }

Retrieve the results

The endpoint will return the Anti-spoofing result alongside Age estimation.

// get response body
int statusCode = response.getResponseCode(); Map<String, List<String>> headers = response.getResponseHeaders(); // get response body byte[] responseBody = response.getResponseBody();
// Get response body $body = $response->getBody();
# get response body response_body = json.loads(response.text)
// get response body
// get response body
# get response body body = response.body puts body

JSON example:

{ "antispoofing": { "prediction": "real" }, "age": { "age": 25.1, "st_dev": 3.5 } }

API Integration

You can also integrate with the API directly.

Endpoints

The API supports the following endpoints.

Endpoint

Description

POST https://api.yoti.com/ai/v1/self-checkout/age-antispoofing

Use Yoti's Age estimation service and the Anti-spoofing check.

Headers

The API supports the following headers:

Header

Description

X-Yoti-Auth-Id

SDK ID for the Yoti Hub application.

Terminal-Id

Unique ID per machine. Mandatory for non-browser integrations.

Session-Id

May be provided to demonstrate multiple attempts are from a single user transaction. Optional.

Request

The JSON object body for the API request has the following structure:

{ "img": "base64encoded_image" }

Response

The JSON object body returned from the API has the following structure:

{ "antispoofing": { "prediction": "real | fake" }, "age": { "age": float, "st_dev": float } }

Response

Explained

Prediction - real

Yoti has detected a real user.

Prediction - fake

Yoti has detected a spoof attempt.

Age - age

The age estimation of the user.

Age - st_dev

The st_dev value is an uncertainly value. Yoti recommends rejecting any response with an uncertainty greater than 6.0. Typically this indicates a problem with image capture. This should only be treated as a quality score.

Error codes

In case of any failure, you will receive the following error responses:

Error code

Error

Description

404

APP_NOT_FOUND

Application app_id not found.

401

INVALID_X_YOTI_AUTH_ID

  • X-Yoti-Auth-Id header not provided.

  • auth id is not a valid uuid.

400

INVALID_APP_ID

Application id cannot be empty.

400

INVALID_PUBLIC_KEY

Application public key cannot be empty.

403

DISABLED_APP_STATE

Application must be enabled.

400

INVALID_ORG_ID

Organisation id cannot be empty.

400

INVALID_BILLING_SOURCE_ID

Application billing source id cannot be empty.

404

ORG_NOT_FOUND

Organisation org_id not found.

401

INVALID_YOTI_AUTH_DIGEST

  • X-Yoti-Auth-Digest header is missing.

  • X-Yoti-Auth-Digest is not base64 encoded.

401

INVALID_NONCE

  • Nonce is missing. nonce parameter is mandatory

  • Provided nonce is not a valid uuid.

401

INVALID_TIMESTAMP

  • Timestamp is missing. timestamp parameter is mandatory.

  • Provided timestamp is not a valid unix timestamp.

401

INVALID_PUBLIC_KEY_ENCODING

Failed to load public key. key is not der encoded.

401

UNSUPPORTED_ALGORITHM

Serialised key is of a type that is not supported by the backend.

401

INVALID_SIGNATURE

Failed to verify signature.

403

INVALID_ORG_STATUS

Organisation has an invalid status.

404

INVALID_METADATA_DEVICE

Invalid device metadata provided.

400

INVALID_BODY_ENCODING

Request body should be a valid JSON.

404

INVALID_ENDPOINT

The endpoint request is invalid.

413

PAYLOAD_TOO_LARGE

Payload too large.

400

IMAGE_NOT_PROVIDED

Image has not been provided.

400

INVALID_B64_IMAGE

  • Base64 image is incorrectly padded.

  • Cannot create image from base64 decoded bytes

400

UNSUPPORTED_IMAGE_FORMAT

Image format not supported. Please use JPEGs (95 to 100 quality) and PNGs.

400

IMAGE_SIZE_TOO_BIG

Image size too big, the maximum size is 1.5MB.

400

IMAGE_SIZE_TOO_SMALL

Image size too small, the minimum size is 50KB.

400

MIN_HEIGHT

The image height is incorrect. Image minimum height required is 300 pixels.

400

MAX_HEIGHT

The image height is incorrect. Image maximum height required is 2000 pixels.

400

MIN_WIDTH

The image width is incorrect. Image minimum width required is 300 pixels.

400

MAX_WIDTH

The image width is incorrect. Image maximum width required is 2000 pixels.

400

MIN_PIXELS

To process the image the minimum number of pixels required is 90,000 pixels.

400

MAX_PIXELS

To process the image the maximum number of pixels required is 2,100,000 pixels.

400

IMAGE_WRONG_CHANNELS

Missing colour channel, the input image must be RGB or RGBA.

400

IMAGE_GRAYSCALE_NOT_SUPPORTED

Grayscale images not supported.

503

SERVICE_UNAVAILABLE

The service is temporarily unavailable.

400

FACE_NOT_FOUND

Face not found.

400

MULTIPLE_FACES

Multiple faces in the image provided.

400

FACE_BOX_TOO_SMALL

The face in the image provided is too small.

400

FACE_TO_IMAGE_RATIO_TOO_LOW

Face ratio is lower than the minimum ratio.

400

FACE_TO_IMAGE_RATIO_TOO_HIGH

Face ratio is bigger than the maximum ratio.

400

INSUFFICIENT_AREA_AROUND_THE_FACE

Insufficient area around the face in the image provided.

400

IMAGE_TOO_BRIGHT

Image too bright..

400

IMAGE_TOO_DARK

Image too dark.

400

INVALID_LEVEL_OF_ASSURANCE

Invalid antispoofing level of assurance provided.

400

INVALID_REQUEST_BODY

Request body is invalid, '-' field is invalid.

400

INVALID_IMG_VALIDATION_LEVEL

The image validation level is invalid.

401

UNAUTHORIZED

The X-Yoti-Auth-Id provided isn't authorized to access this resource.

500

FAIL_PREDICTION

  • Age distribution is empty.

  • Standard deviation is empty.

  • Cannot build model result.

  • Antispoofing prediction failed.

500

UNSPECIFIED_ERROR

An internal server error occurred.

400

SECURE_REQUEST_IS_EMPTY

Secure request field is empty.

400

SECURE_SESSION_NOT_FOUND

Secure session not found.

400

SECURE_SIGNATURE_NOT_FOUND

Secure signature not found.

400

SECURE_VERSION_NOT_FOUND

Secure version not found.

400

INVALID_SECURE_SIGNATURE

Failed to verify secure session signature.

400

SECURE_VERIFICATION_NOT_FOUND

Secure verification not found.

400

UNTRUSTED_SECURE_SESSION

Untrusted secure session

401

INVALID_SECURE_SESSION

Invalid secure session token.