Web photo verify API

POST /photoverify?accuracy={accuracy}

Performs a liveness detection on the uploaded samples to verify whether they are recorded from a live person. And then perform a one-to-one comparison with the ID photo submitted in order to verify whether the live images and ID photo belong to the same person.

PhotoVerify is a BWS service, which uses one passport image from an ID document, and compares that to two "live" images of a person, to find out whether the persons shown are the same. Periocular biometrics is used as it gives better results than face (and allows for close-view recordings). No classes are created, no templates or patterns are stored. It fulfills all requirements for an anonymous ID proofing service.

To perform a photo verification, three images have to be provided:

  • two live recorded images, which are sent to the quality-check where, among other things, the face detection is done. If the images are suitable, a live-detection is executed. Only if live-detection succeeds, the procedure is continued.
  • a photo, typically a passport image from an ID document. If the photo also contains a face, it is compared to the live images.

A decision about the similarity of the photo and the live images is made according to an accuracy level. The higher the accuracy level, the better the faces on the images must match. Higher accuracy levels are recommended, but lower accuracy levels can be used with low quality ID photos (e.g. scanned passport images), where a higher accuracy cannot be reached any more.

Five accuracy settings are defined from 1 to 5 with accuracy lower or equal to 1 being the worst (with a false acceptance rate of about 10%), and greater or equal to 5 being the best (with a false acceptance rate of about 0.1%). The default is 4, with a false acceptance rate of 1%.

Request Information


This API call requires Basic Authentication, i. e. you have to provide an HTTP authorization header using the authorization method Basic and the base64 encoded string App-ID:App-Secret (therefore the transport is secured using TLS/SSL). To receive the necessary BWS WebAPI access data (App-ID and App-Secret) you have to register your application on the BWS Management Portal first. This requires a valid BWS subscription.



optional integer containing the desired accuracy level:

  • 1 (and below): allow FAR (False Acceptance Rate) of 10% - we do not recommend to use this level, which is intended for really bad ID photos only. Keep in mind that about each tenth call using this level might respond wrong.
  • 2: FAR of 5% - still a very high false acceptance rate.
  • 3: FAR of 2% - should be the lowest acceptable level.
  • 4: FAR of 1% - still OK, is the default setting.
  • 5 (and above): FAR 0.1% - the identity can be seen as approved (wink)


The body contains the three images encoded into a Data-URL using the data URI scheme as described in RFC 2397 (see also at Wikipedia), e.g. using the application/json media type:

"liveimage1": "data:image/...",
"liveimage2": "data:image/...",
"idphoto": "data:image/..."

or using the application/x-www-form-urlencoded media type:



If all three provided images could be processed successfully, this method returns the OK HTTP status code (200) with simply true or false in the body content, indicating whether the live images match the ID photo or not with regard to the applied accuracy level.

In case something goes wrong, an error HTTP status code is returned together with some additional information if available.

Response HTTP Status Codes

The call returns one of the standard HTTP status codes:

200 OKThe response body simply says true or false, indicating whether the live images match the ID photo or not.
400 Bad RequestInvalid samples have been uploaded or they could not be processed successfully, e.g. no face found or live detection failed, etc. The response body typically has a Message field containing the error code:
  • "MissingData": Not all three images have been supplied.
  • "InvalidSampleData": The submitted samples could not be decoded into images.
  • One of the error codes as generated by a Quality Check.
  • "LiveDetectionFailed": The submitted live images do not prove that they are recorded from a live person.
401 UnauthorizedBasic Authentication is required.
500 Internal Server ErrorA server side exception occurred. The content may contain a Message and an ExceptionMessage.

Sample Code

using (var client = new HttpClient())
    client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Basic",
    string json;
    using (var idstream = passprt.OpenRead())
    using (var img1stream = live1.OpenRead())
    using (var img2stream = live2.OpenRead())
        var bfrid = new byte[idstream.Length];
        var bfrl1 = new byte[img1stream.Length];
        var bfrl2 = new byte[img2stream.Length];
        await Task.WhenAll(
            Task.Run(async () => await idstream.ReadAsync(bfrid, 0, bfrid.Length)),
            Task.Run(async () => await img1stream.ReadAsync(bfrl1, 0, bfrl1.Length)),
            Task.Run(async () => await img2stream.ReadAsync(bfrl2, 0, bfrl2.Length))
        json = $@"{{""liveimage1"":""data:image/png;base64,{Convert.ToBase64String(bfrl1)}"""
            + $@",""liveimage2"":""data:image/png;base64,{Convert.ToBase64String(bfrl2)}"""
            + $@",""idphoto"":""data:image/png;base64,{Convert.ToBase64String(bfrid)}""}}";
    using (var content = new StringContent(json, Encoding.ASCII, "application/json"))
    using (var response = await client.PostAsync(ENDPOINT + "photoverify", content))
        if (response.StatusCode == HttpStatusCode.OK)
            if (bool.TryParse(await response.Content.ReadAsStringAsync(), out var parsed))
                return parsed;
        return false;
            // using org.json.JSONObject from JSON-java library
            JSONObject requestBody = new JSONObject();
            requestBody.put("liveimage1", "data:image/png;base64," + Base64.getEncoder().encodeToString(png1AsByteArray));
            requestBody.put("liveimage2", "data:image/png;base64," + Base64.getEncoder().encodeToString(png2AsByteArray));
            requestBody.put("idphoto", "data:image/png;base64," + Base64.getEncoder().encodeToString(photoIdPngAsByteArray));

            // using OkHttpClient from the OkHttp library
            Request request = new Request.Builder()
                    .addHeader("Authorization", Credentials.basic(APP_IDENTIFIER, APP_SECRET))
                    .post(RequestBody.create(MediaType.parse("application/json"), requestBody.toString()))
            OkHttpClient client = new OkHttpClient();
            Response response = client.newCall(request).execute();
            if (response.code() == 200) {
                if (response.body().string().equals("true")) {
                    System.out.println("live images do match the ID photo");
                } else {
                    System.out.println("live images do not match the ID photo");