NAV Navbar
cURL javascript python

Get Started

Welcome to Ubble's Certified product API documentation !

In the dashboard, in the developper space, you will be able to generate you mutual TLS credentials. Make sure that you have created them, as they will be used across all the documentation.

By the end of this section, you will be able to create an identification, check your identity and consult results on Ubble's identity verification service.

Mutual TLS Authentication

You must authenticate your calls by including your secret credentials as well as your client certificate and key in API requests. You can manage your credentials and certificates in the Dashboard. Your credentials and certificates carry many privileges, so be sure to keep them secure. Do not share your secret API keys or API certificates in publicly accessible areas such as GitHub, client-side code, and so forth.

Requests are authenticated using HTTP Basic Auth and mutual TLS Provide your CLIENT_ID and CLIENT_SECRET as the Basic Auth username and password. Provide your client certificate and client key as the mutual TLS certificate authentication

All API requests must be made over HTTPS as calls made over plain HTTP will fail. API requests without authentication will also fail.

Create an identification

Create an identification

curl -X POST 'https://api.ubble.ai/identifications/' \
  -u CLIENT_ID:CLIENT_SECRET \
  --header 'Content-Type: application/vnd.api+json' \
  --cert /path/client.crt \
  --data-raw '{
    "data": {
      "type": "identifications",
      "attributes": {
        "reference-data": {
          "first_name":"JOHN",
          "last_name":"DOE"
        }
      }
    }
  }'
  --key /path/client.key | jq
const axios = require("axios");
const fs = require("fs");
const https = require("https");
const config = {
  auth: { username: "CLIENT_ID", password: "CLIENT_SECRET" },
  headers: {
    Accept: "application/vnd.api+json",
    "Content-Type": "application/vnd.api+json",
  },
  body: {
    "data": {
      "type": "identifications",
      "attributes": {
        "reference-data": {
          "first_name":"JOHN",
          "last_name":"DOE"
        }
      }
    }
  }
};
const httpsAgent = new https.Agent({
  cert: fs.readFileSync("/path/client.crt"),
  key: fs.readFileSync("/path/client.key"),
});
axios
  .post("https://api.ubble.ai/identifications/", { httpsAgent }, config)
  .then((res) => {
    const identification = res.data;
    const attributes = identification.data.attributes;
    const identificationId = attributes["identification-id"];
    console.log(attributes["identification-url"]);
    console.log(attributes["redirect-url"]);
  })
  .catch((err) => console.log(err.response.data));
import requests

headers = {
  "Accept": "application/vnd.api+json",
  "Content-Type": "application/vnd.api+json"
}

res = requests.post(
    "https://api.ubble.ai/identifications/",
    auth=("CLIENT_ID", "CLIENT_SECRET"),
    cert=('/path/client.crt', '/path/client.key'),
    data={
      "data": {
        "type": "identifications",
        "attributes": {
          "reference-data": {
            "first_name":"JOHN",
            "last_name":"DOE"
          }
        }
      }
    },
    headers=headers
)
identification = res.json()
attributes = identification["data"]["attributes"]
identification_id = attributes["identification-id"]
print(attributes["identification-url"])
print(attributes["redirect-url"])

To verify the identity of a user you will need to create an identification object. The identification object is the main object of Ubble's product and corresponds to one identity verification, see objects reference. One identification corresponds to one and only one user.

Verify your identity

Go to the identification-url from the identification object that you've just created and complete Ubble's identity verification process (at the end, you will be redirected to the redirect_url associated to the identification, see configuration to customize it).

As you will see if you use a desktop you will be redirected to your phone to perform the verification. You will be able to prefill the phone_number when generating an identification in production. See create an identification.

Get the results

Get the results

curl 'https://api.ubble.ai/identifications/:identification-id/' \
  -u CLIENT_ID:CLIENT_SECRET | jq
const axios = require("axios");
const config = {
  auth: { username: "CLIENT_ID", password: "CLIENT_SECRET" },
  headers: {
    Accept: "application/vnd.api+json",
  },
};
axios
  .get(`https://api.ubble.ai/identifications/${identificationId}/`, config)
  .then((res) => {
    const identification = res.data;
    console.log(identification.data.attributes.score);
    // Getting first name, last name and birth date
    console.log(
      identification.included.find((obj) => obj.type === "identities")
        .attributes
    );
  })
  .catch((err) => console.log(err.response.data));
import requests

headers = {"Accept": "application/vnd.api+json"}

res = requests.get(
    f"https://api.ubble.ai/identifications/{identification_id}/",
    auth=("CLIENT_ID", "CLIENT_SECRET"),
    headers=headers,
)
identification = res.json()
print(identification["data"]["attributes"]["score"])
for obj in identification["included"]:
    # Getting first name, last name and birth date
    if obj["type"] == "identities":
        print(obj["attributes"])

Once you're done, you can fetch the results.
Congrats ! You've completed your first identification. To go further, you can go through the different steps of our integration, or look at the results that you can get from an identification.

Integration

To integrate with Ubble identity verification service, you will need to follow these five steps:

  1. Create identification object in your backend for a user
  2. Redirect user to the identification-url in your frontend
  3. Manage user return
  4. Get automatic answer
  5. Get final answer

Integration flow

Step 1: Create an identification object

At this point you should have created your first identification with our Get started. We strongly advise you to create your identification in your backend, to avoid using your Ubble credentials in your frontend. Once your backend is correctly setup to create identification, you can go to Step 2.

All the details to create an identification can be found there: Create identification - POST /identifications/

The external_user_id is mandatory in the POST request (in the identification-form object), as well as the declared first-name and last-name (in the reference-data object).

You can modify the redirect_url, or use the one that is set by default in your configuration, see how.

We strongly recommend you to send the phone_number if you use a desktop flow : we use it to pre-fill the SMS redirection page (one of the 2 redirection options along with the QR Code).

The identity verification process has an asynchronous response (since it's dependent on the user pace and Ubble's processing). To be notified of every identification status change, you can configure a webhook, see how. You can modify the webhook url.

Step 2: Redirect user

Once you have created an identification object your user needs to be redirected to Ubble's web application as explained on the graph below.

Integration flow

Ubble uses RTCPeerConnection and getUserMedia to enable the live streaming video on the web. Therefore we depend on the different implementations of web browsers.

Web Redirection

You can redirect user using web redirection. We support all the major browsers current versions.

We've built an integration example showcasing how to integrate Ubble in a web app:

Web Redirection is compatible with the following browsers / OS. We do not ensure the compatibility of our service with beta versions of browsers / OS.

Desktop Chrome Firefox Safari Internet Explorer Edge Opera
Min. Version ≥ 53 ≥ 52 ≥ 11.1 - ≥ 16 ≥ 58
Android Chrome for Android Firefox for Android Samsung Internet IE Mobile
Min. Version ≥ 73 ≥ 66 ≥ 6.2 -
iOS Safari Mobile Chrome All other browsers
Min. Version ≥ 11.0 ≥ 14.3 -

To integrate Ubble in your website, create an identification in your backend, pass the identificationUrl to your web app and simply add it as a link :

<a href="`${identificationUrl}`"></a>

Webview integration

For a more integrated user experience in your mobile application, you can redirect your user using a webview.

Here is the list of integration examples that we've built for you :

For iOS Native you will have to open safari using the open method:

UIApplication.shared.open(identificationUrl, options: [:])


Flutter

If you wish to use Ubble with Flutter, you can use the flutter_inappwebview.

Make sure to follow the WebRTC API section of the documentation to ensure we're able to launch a video stream.

Iframe integration

When using the Desktop-to-Mobile redirection flow, we recommend that you use our Iframe integration on desktop described below:

Include the SDK as a script tag.

If you need an example of Iframe usage, you can use our iframe tester

<script
  src="https://cdn.ubble.ai/iframe-sdk-0.0.3.js"
  type="application/javascript"
></script>

We expect your page to implement a global method onUbbleReady that will be triggered when the SDK is loaded

function onUbbleReady() {}


Initialize a new Ubble IDV object:

function onUbbleReady() {
  const ubbleIDV = new Ubble.IDV(document.getElementById("ubble"), options);
}



API

elementId: string | Element
new Ubble.IDV("ubble", options);
new Ubble.IDV(document.getElementById("ubble"), options);
options Object
{
  "status": "processing",
  "redirectUrl": "https://your-redirect-url.com?identification_id=<ubble identification id>"
}
{
  "status": "aborted",
  "returnReason": "NO_DOCUMENT",
  "redirectUrl": "https://your-redirect-url.com?identification_id=<ubble identification id>"
}
{
  "status": "expired",
  "redirectUrl": "https://your-redirect-url.com?identification_id=<ubble identification id>"`
}



Methods

destroy()
const ubbleIDV = new Ubble.IDV("id", {
  events: {
    onComplete(event) {
      console.log(`Done with ubble flow: ${event}`);
      ubbleIDV.destroy();
    },
  },
});



Full example

const ubbleIDV = new Ubble.IDV("idv", {
  width: "500",
  height: "600",
  allowCamera: true,
  identificationUrl: "https://id.ubble.ai/11111111-1111-1111-1111-111111111111",
  events: {
    onComplete(event) {
      ubbleIDV.destroy();
    },
    onAbort(event) {
      ubbleIDV.destroy();
    },
    onExpired(event) {
      ubbleIDV.destroy();
    }
  },
});



Known Issues

Step 3: Manage user return

When users have completed the verification, they are redirected to the redirect_url associated with the identification.

You can customize this redirect_url, see configuration.

Users also have the option of leaving the verification, either voluntarily or because they have encountered an error, using the calls to action in the header of the application. In this case, they are also redirected to the redirect_url, but the status is aborted and you find the reason for their abandonment in the URL parameter.

For example :

?identification_id=123&status=aborted&return_reason=error&error_type=device_not_found

Possible values are

status return_reason error_type description
processing none none The user completed his verification.
aborted refusal none The user refused to perform the verification now.
aborted no_document none The user did not have his document with him.
aborted verify_later none The user refused to start the verification process.
aborted focus-lost none The user switched tabs/application while performing the id verification.
aborted connection_issue bad_connexion The connexion was not good enough.
aborted doc_instructions_not_followed challenge_timeout The user did not follow the instruction for the document challenge.
aborted face_instructions_not_followed challenge_timeout The user did not follow the instruction for the face challenge.
aborted error no_SMS The user did not receive the SMS.
aborted error bad_connexion The connexion was not good enough.
aborted error publish Error during video connection.
aborted error browser-not-supported The browser was not supported.
aborted error device-not-allowed The user refuses to give access to the camera.
aborted error device-not-found The user’s device did not have any camera.
aborted error wrong_phone_number The user wanted to change their phone number and were not allowed to for security reasons (see Configuration).

Step 4: Get automatic answer

The automatic answer is already available when the user is redirected to the redirect_url.

If you configured a webhook, see how, you will be notified as the status switch from initiated to processing.

Getting this answer is similar to what you did in the Get started.

The objects available in the automatic answer are identification, identity. If you choose the form option, see forms, the objects form and identification-form-match will also be available. Assets are included in document and face objects. See see objects reference.

Step 5: Get final answer

The final answer is available at the end of the manual reviews. This delay is defined in the service-level agreements (SLAs).

If you configured a webhook, see how, you will be notified as the status switch from processing to processed.

Getting this answer is similar to what you did in the Get started.

All objects are now available. To better understand the different results see identification results.

Identification results

Objects

All the objects mentionned below are accessible via the GET /identifications/:identification-id endpoint. In depth description is available in API Reference.

Name Description
identification Main object. Stores technical infos of the identification, includes other objects
identity Object summarizing the identity of the user
reference-data Identity sent when the identification is created
external-identity Additional data sent about the user
document Object storing all the data extracted from the user's document
face Object storing all the data extracted from the user's face
form Identity declared by the user in the ubble pre-filled form (optional)
identity-form-match Match check between identity and form (optional)
reason-code Codes that provide insight on why an identification was not validated

Lifecycle

Identification has a status field that can take different values during its life.
Depending on the status, the GET identification call includes different objects:

Status Description Included objects
uninitiated Identification has only been created (user has not started the verification flow) identification, identity, reference-data
initiated User has started the verification flow identification, identity, reference-data
processing User has ended the verification flow, identification-url is not usable anymore identification, identity, form, identity-form-match, reference-data, document, face, external-identity
processed Identification is completely processed by Ubble identification, identity, form, document, face, identity-form-match, reference-data, external-identity
aborted User has left the identification, the identification-url is no longer usable (this status is in beta test) identification, identity, reference-data
expired The identification-url has expired and is no longer usable (only uninitiated and initiated identifications can become expired)

Scores

Identification has a score field that can take different values. All the scores in the different objects follow the same rule:

Score Description
1.0 The check is validated
0.0 The check is invalidated. Ubble has enough information to say that there is an issue (e.g. document is expired)
-1.0 The check cannot be validated. Ubble does not have enough information to provide a correct answer (e.g. user did not show its ID card during the video)

Reason codes

Identification has a relationship named reason-codes.

In case an identification is not validated, reason codes can provide some insight on why it was the case. A refused identification can contain multiple reason codes.

Code Description
1201 Applicant did not have a sufficient connexion
1301 Applicant’s document video is too blurry (mostly due to too much movement but if this error persists the camera quality might be at fault)
1302 Applicant has not presented the front of the document
1303 Applicant has not presented the back of the document
1304 Applicant hides part of the document
1305 Applicant did not present a dynamic view of the document
1310 Applicant’s video of their face is too blurry (mostly due to too much movement but if this error persists the camera quality might be at fault)
1311 Applicant has not presented a face
1312 Applicant did not show the full front view of their face
1313 Applicant did not move to prove the liveness
1320 Applicant performed their id verification under poor lighting conditions
1901 Internal non-categorizable error
1911 The received videos cannot be played
2101 Applicant presented an expired document
2102 Applicant presented a document which is not accepted
2103 Applicant has submitted a damaged document
2201 Applicant presented a photocopy of the document
2202 Applicant presented the document on a screen
2399 Generic code when a fraud has been detected within a certified identity verification
2401 Applicant’s identity does not match with the expected one
2402 Applicant used a device that has been technically altered
2403 Applicant seems to have performed the check against his will

Comment

Identification has a comment field providing insights about processed identifications that are incomplete.

The comment field combines different sub-comments, each of them being generated by different events.

The different values of these subcomments are detailled below.

The comment field is mostly filled automatically depending on the context, however it can also be expanded manually by reviewers if necessary.

The subcomments used to generate the comment field can take the following values:

Comment
The document video resolution is too low
The document is not presented
The document video quality is too low
Back of the document is not presented
Back of the document video quality is too low
Some required data of the document could not be extracted
Face is not presented
Face video quality is too low
Authenticity of the document could not be verified
User liveness could not be verified
Face and the document photo match could not be verified
User did not follow the instructions when submitting their face
User did not follow the instructions when submitting their document

PDF

Get PDF result

curl -X POST 'https://api.ubble.ai/identifications/11111111-1111-1111-1111-111111111111/pdf/' \
 -u CLIENT_ID:CLIENT_SECRET > identification.pdf
const axios = require("axios");
const config = {
  auth: { username: "CLIENT_ID", password: "CLIENT_SECRET" },
  responseType: "stream",
};
axios
  .post(`https://api.ubble.ai/identifications/${identificationId}/pdf/`, config)
  .then(function (response) {
    response.data.pipe(fs.createWriteStream("~/identification.pdf"));
  })
  .catch((err) => console.log(err.response.data));
import requests
headers = {
    "Accept": "application/vnd.api+json",
}
identification_id = "11111111-1111-1111-1111-111111111111"

res = requests.post(
    f"https://api.ubble.ai/identifications/{identification_id}/pdf/",
    auth=("CLIENT_ID", "CLIENT_SECRET"),
)
if res.ok:
    open("identification.pdf", "wb").write(res.content)
else:
    print("Error", res.content)

Once an identification is processed, you can request a pdf export of an identification by calling the endpoint.

POST - /api/identifications/:identification_id/pdf/

Internationalization

You can request the PDF in different languages, by either adding a lang query parameter, or sending an Accept-language header

POST - /api/identifications/:identification_id/pdf/?lang=en

curl -X POST 'https://id.ubble.ai/api/identifications/:identification_id/pdf/' --header 'Accept-Language: fr-FR'

Supported languages are currently English and French, the default language is English.

Examples

Get standard answer

curl 'https://api.ubble.ai/identifications/11111111-1111-1111-1111-111111111111/' \
  -u CLIENT_ID:CLIENT_SECRET | jq
const axios = require("axios");
const identificationId = "11111111-1111-1111-1111-111111111111";
const config = {
  auth: { username: "CLIENT_ID", password: "CLIENT_SECRET" },
  headers: {
    Accept: "application/vnd.api+json",
  },
};
axios
  .get(`https://api.ubble.ai/identifications/${identificationId}/`, config)
  .then((res) => {
    const identification = res.data;
    console.log(
      `Identification score is ${identification.data.attributes.score}`
    );
    identification.included.forEach((obj) => {
      console.log(`Object ${obj.type} :`);
      console.log(obj.attributes);
    });
  })
  .catch((err) => console.log(err.response.data));
import requests

headers = {
    "Accept": "application/vnd.api+json",
}
identification_id = "11111111-1111-1111-1111-111111111111"

res = requests.get(
    f"https://api.ubble.ai/identifications/{identification_id}/",
    auth=("CLIENT_ID", "CLIENT_SECRET"),
)
identification = res.json()
print(f'Identification score is {identification["data"]["attributes"]["score"]}')
for obj in identification["included"]:
    print(f'Object {obj["type"]} - {obj["attributes"]}')

In order to ease your integration, you are provided with 3 standard answers that you can play with.

identification-id score description
11111111-1111-1111-1111-111111111111 1.0 The identification is validated
00000000-0000-0000-0000-000000000000 0.0 The identification is not validated because the document is a photocopy
22222222-2222-2222-2222-222222222222 -1.0 We're missing some information to make a final decision : in this example, the user didn't show the back of the ID

Configuration

Webhook

Webhook body Processed

{
  "configuration": {
    "id": 5,
    "name": "MyConfig"
  },
  "identification_id": "11111111-1111-1111-1111-111111111111",
  "status": "processed"
}

Webhook body Aborted

{
  "configuration": {
    "id": 5,
    "name": "MyConfig"
  },
  "identification_id": "11111111-1111-1111-1111-111111111111",
  "status": "aborted",
  "return_reason": "no_document"
}

The identity verification process has an asynchronous response (since it depends on the user pace and ubble's processing). By configuring your webhook, you will be notified of every identification status change. You will be notified when the user starts, successfully ends, and when the identification has been processed by Ubble.

You can easily configure your webhook:

We expect that you return us a 200 or 201 status code within 10 seconds before we retry, up to 2 retries will be performed. If needed, webhook notifications can be resend manually using the notify endpoint.

Webhook security

import hashlib
import hmac

# Ubble request is the webhook call
request = ubble_request

ubble_signature = request.headers['Ubble-Signature']
ubble_signature_dict = dict(token.split('=') for token in ubble_signature.split(','))
# Let's compare the hash

# First we create the signed_payload
signed_payload = ubble_signature_dict['ts'] + '.' + request.body

# Then we create the hash
expected_signature = hmac.new(
  # WEBHOOK_SECRET can be found in the Configuration page on your dashboard.
  WEBHOOK_SECRET.encode('utf-8'),
  msg=signed_payload.encode('utf-8'),
  digestmod=hashlib.sha256
).hexdigest()

# Then we compare both signature.
expected_signature == ubble_signature_dict['v1']

For security reason all our webhook calls are signed.

Ubble-Signature header contains the timestamp of the signature plus the signature itself. This allow you to ensure the content of the webhook was not modified.

The timestamp is prefixed by ts=, and the signature is prefixed by v1=. Example : ts=1492774577,v1=5257a869e7ecebeda32affa62cdca3fa51cad7e77a0e56ff536d0ce8e108d8bd

To compare the signature, you will need the webhook secret, that you can find on your dashboard configuration page. There is one for secret for test identifications and one for live identifications.

See the example in python if you need help.

Webhook ip whitelisting

For security purposes, if you need to whitelist our incoming api calls, see our public ip.

Webhooks Authentication

You can also choose to authentify our webhook calls against OAuth2. Please contact your account manager in order set up the authentication. You will need to provide an URL Token, a CLIENT_ID, a CLIENT_SECRET and optionnally a refresh token URL.

Redirect URL

You can easily configure the redirect-url of your identifications :

Form

You may need to use the user's full identity data in your on-boarding workflow. In this case, to make the automatically extracted data more reliable, we suggest you create a form in the user path.

The form will be pre-filled with the data extracted during the flow, and can contain all the fields of the extended identity : first name, last name, married name, gender, nationality, birth place, country, birth place, city. The results of the form will be available in the object form in the identification results.

Moreover you can get a confirmation of the accuracy of this data in the final results. We compare the extracted name, first name and birthdate with the form data. The results are available in the identity-form-match object.

Other

Many elements are configurable, see with your account manager. You will be able to change the UI of your Ubble flow (colors, logos, and country / document choices). You will also be able to change how the user data is stored on our servers.

API Reference

API public ip

The api is hosted on our cloud provider, whose public ip adress is available on his website.

JSON API

API Host

https://api.ubble.ai/

All request and response bodies, including errors, are encoded in JSON. Our api follows the jsonapi spec for formatting. Examples of response objects can be found in the spec can be found here. For security reasons most endpoints are disabled.

Authentication

The Ubble API uses two types of authentication. For standard accounts Basic authenication is used, and for certified accounts mutual TLS authentication in addition to Basic Authentication is used. Basic authentication credentials and mutual TLS authentication certificates can be managed in the client dashboard or by your account manager.

Mutual TLS Authentication

Authentication using mutual TLS and Basic auth.

curl -X POST 'https://api.ubble.ai/identifications/' \
  -u {CLIENT_ID}:{CLIENT_SECRET} --cert /path/client.crt --key /path/client.key
import requests

headers = {
  "Accept": "application/vnd.api+json",
  "Content-Type": "application/vnd.api+json"
}

res = requests.post(
    "https://api.ubble.ai/identifications/",
    auth=("CLIENT_ID", "CLIENT_SECRET"),
    cert=('/path/client.crt', '/path/client.key'),
    headers=headers
)
const axios = require("axios");
const fs = require("fs");
const https = require("https");
const config = {
  auth: { username: "CLIENT_ID", password: "CLIENT_SECRET" },
  headers: {
    Accept: "application/vnd.api+json",
    "Content-Type": "application/vnd.api+json",
  },
};
const httpsAgent = new https.Agent({
  cert: fs.readFileSync("/path/client.crt"),
  key: fs.readFileSync("/path/client.key"),
});
axios
  .post("https://api.ubble.ai/identifications/", { httpsAgent }, config)
  .then((res) => console.log(res.data))
  .catch((err) => console.log(err.response.data));

You must authenticate your calls by including your secret credentials as well as your client certificate and key in API requests. You can manage your credentials and certificates with your account manager. Your credentials and certificates carry many privileges, so be sure to keep them secure. Do not share your secret API keys or API certificates in publicly accessible areas such as GitHub, client-side code, and so forth.

Requests are authenticated using HTTP Basic Auth and/or mutual TLS Provide your CLIENT_ID and CLIENT_SECRET as the Basic Auth username and password. Provide your client certificate and client key as the mutual TLS certificate authentication

All API requests must be made over HTTPS as calls made over plain HTTP will fail. API requests without authentication will also fail.

API response signing

If enabled in your configuration (Contact your account manager in order to activate the response signature), Ubble API responses will be signed. This signature can be used to verify that the api response has not been altered and has been issued by Ubble and not by anyone else. To also verify that assets data (images) has not been altered and comes from Ubble, the assets hash has been added to the response body, and after verification of the signature, the images can be hashed and compared to the hashes in the verified response. Ubble uses an asymetric key signing algorithm of type ECDSA with a sha2-512 hashing algorithm. Assets are hashed using the sha2-256 hashing algorithm.

Signing key policy

A signing key will be created for each configuration and for each environment (Live and Test). The public key (used for signature verification) associated with the private key that is managed by ubble can be downloaded from the client dashboard. The private key has a validity of 1 year and will be automatically renewed. Upon renewal the public key will also change and has to be re-downloaded from the dashboard. You can detect a key rotation by looking at the signature version in the api response, to verify that response you will need to use the public key with the same version. All versions of the public key can be downloaded from the dashboard so you don't have to worry about losing older versions.

Verifying Response signature

import base64
import ecdsa
from ecdsa.util import sigdecode_der
from hashlib import sha512

# response is the python requests response object received from Ubble

# Extract the signature
timestamp, ubble_signature_version, ubble_signature = response.headers["ubble-signature"].split(":")

# First we create the signed_payload
signed_payload = f"{timestamp}:{response.text}".encode("utf-8")

# Use the public key from the dashboard (check version from ubble_signature_version)
public_key_file = open("ubble_public_key.key")

# Generate veryfing key signature
verifying_key = ecdsa.VerifyingKey.from_pem(public_key_file.read())

# Verify the signature
result = verifying_key.verify(base64.b64decode(ubble_signature.encode("utf-8")), signed_payload, hashfunc=sha512, sigdecode=sigdecode_der, allow_truncate=True)
print(result)

The Ubble-Signature header contains the timestamp of the request (1635236316.377888), the signing key identifier and version (3456-live-v1) as well as the signature itself (5257a869a7ecebeda35affa62cdcb3fa51cad7e77a0e56ff546d0ae8e108d8bd).

Example : 1635236316.377888:3456-live-v1:5257a869a7ecebeda35affa62cdcb3fa51cad7e77a0e56ff546d0ae8e108d8bd <timestamp>:<configuration id>-<test or live identification>-<key version>:<signature>

The signature can be verified on your side by verifying the signature against the received body using the public key corresponding to the signature key. You will need the Public key corresponding to the signature version, that you can find on your dashboard configuration page. There is one for test identifications and one for live identifications.

See the example in python if you need help.

Verifying Assets

from hashlib import sha256
import requests

# Download image to verify (example url)
image_url = "https://storage.ubble.ai/image-url.png"
received_image = requests.get(image_url).content

# Hash the image
received_image_hash = sha256(received_image).hexdigest()

# Get the hash from the previously verified response (example)
ubble_response_image_hash = "sha2-256:<image-hash-string>"

# Compare the hashes
result = received_image_hash == ubble_response_image_hash.split(":")[1]
print(result)

To verify that the assets that correspond to the received response are correct, the received images have to be hashed using a specific algorithm, this hash must be the same as the hash that was sent with the signed response.

Be aware that all two verification stages must be valid (api response signature and assets hash) for the data to be valid.

Objects

All the following objects related to the identification are included in the GET identification call once the identification is in processed. Identity and Identification data are always included in the GET call. Note that the score of an identification is only available when the identification is processed.

Identifications

identification object

{
  "type": "identifications",
  "id": "801",
  "attributes": {
    "comment": "Identity Verified",
    "created-at": "2019-02-26T16:29:19.857313Z",
    "ended-at": "2019-02-26T17:05:49.096401Z",
    "identification-id": "70f01f19-6ec5-4b14-9b30-2c493e49df15",
    "identification-url": "https://id.ubble.ai/70f01f19-6ec5-4b14-9b30-2c493e49df15",
    "number-of-attempts": 1,
    "redirect-url": "https://www.ubble.ai/",
    "score": 1.0,
    "started-at": "2019-02-26T16:29:43.075181Z",
    "status": "processed",
    "updated-at": "2019-02-26T17:12:02.226018Z",
    "status-updated-at": "2019-02-26T17:12:02.226018Z",
    "user-agent": "Mozilla/5.0 (iPhone; CPU iPhone OS 12_1_4 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/12.0 Mobile/15E148 Safari/604.1",
    "user-ip-address": "123.123.123.123",
    "webhook": "https://3eb5c250.ngrok.io"
  },
  "relationships": {
    "doc-face-matches": {
      "data": [
        {
          "type": "doc-face-matches",
          "id": "546"
        }
      ],
      "links": {
        "related": "http://api/api/identifications/801/doc_face_matches/"
      },
      "meta": {
        "count": 1
      }
    },
    "doc-doc-matches": {
      "data": [
        {
          "type": "doc-doc-matches",
          "id": "62"
        }
      ],
      "links": {
        "related": "http://api/api/identifications/801/doc_doc_matches/"
      },
      "meta": {
        "count": 1
      }
    },
    "reason-codes" : {
      "data": [
        {
          "type": "reason-codes",
          "id": "2401"
        }
      ],
      "meta": {
        "count": 1
      }
    }
    "document-checks": {
      "data": [
        {
          "type": "document-checks",
          "id": "546"
        }
      ],
      "links": {
        "related": "http://api/api/identifications/801/document_checks/"
      },
      "meta": {
        "count": 1
      }
    },
    "face-checks": {
      "data": [
        {
          "type": "face-checks",
          "id": "546"
        }
      ],
      "links": {
        "related": "http://api/api/identifications/801/face_checks/"
      },
      "meta": {
        "count": 1
      }
    },
    "identity-form-match": {
      "data": [
        {
          "type": "identity-form-matches",
          "id": "646"
        }
      ],
      "links": {
        "related": "http://api/api/identifications/801/identity-form-matches/"
      },
      "meta": {
        "count": 1
      }
    },
    "identity": {
      "data": {
        "type": "identities",
        "id": "661"
      },
      "links": {
        "related": "http://api/api/identifications/801/identity/"
      }
    }
  }
}

The identification object contains the information related to the identification performed by the user. This object is included in the response, whatever the status. Depending on the identification's status, some fields will have a NULL value.

Attribute Type Description
comment string Text field in case of incomplete identification (score value is -1)
created-at string (format: YYYY-MM-DDThh:mm:ss.ffffffZ) The identification creation time, when your backend calls ubble’s API to create the identification
ended-at string (format: YYYY-MM-DDThh:mm:ss.ffffffZ) The date and time when the identification final answer is available, when the status changes to processed
identification-id string (UUID) Unique identifier of the identification. It will be used as argument for other API calls
identification-url string Url where the user should be redirected to perform the identification. It follows this format: https://id.ubble.ai/<identification-id>/
number-of-attempts number Number of attempts, or sessions, related to this identification
redirect-url string Url where the user is redirected at the end of the identification
score number Overall trust score of the identification.
  • 1.0: Identification validated
  • 0.0: Identification has issues
  • -1.0: Identification cannot be processed
started-at string (format: YYYY-MM-DDThh:mm:ss.ffffffZ) The date and time when the user made the first attempt / session with the identification
status string Status of the identification, one of: uninitiated, intiated, processing, processed or aborted
updated-at string (format: YYYY-MM-DDThh:mm:ss.ffffffZ) The date and time of the last update to the identification object
status-updated-at string (format: YYYY-MM-DDThh:mm:ss.ffffffZ) The date and time of the last status update to the identification object
user-agent string User agent used for the last session
user-ip-address string IP address from where the user performed the identification
webhook string Url where status change notifications will be sent

Reason codes

{
  "type": "reason-codes",
  "id": "2430"
}

In case an identification is not validated, reason codes can provide some insight on why it was the case. A refused identification can contain multiple reason codes.

The list of reason codes can be found here.

Identities

identity object

{
  "type": "identities",
  "id": "661",
  "attributes": {
    "birth-date": "1978-11-25",
    "first-name": "JEAN",
    "last-name": "VALJEAN"
  },
  "relationships": {
    "document": {
      "data": {
        "type": "documents",
        "id": "632"
      },
      "links": {
        "related": "http://api/api/identities/661/document"
      }
    },
    "face": {
      "data": {
        "type": "faces",
        "id": "629"
      },
      "links": {
        "related": "http://api/api/identities/661/face"
      }
    },
    "form": {
      "data": {
        "type": "forms",
        "id": "762"
      },
      "links": {
        "related": "http://api/api/identities/661/form"
      }
    }
  }
}

An identity object contains the identity data of the user that performed the identification. This object is always included in the response, whatever the status. Values can be null.

Attribute Type Description
first-name string First name of the user
last-name string Last name of the user
birth-date string (format: YYYY-MM-DD) Birth date of the user

Reference data

Identity sent when the identification is created

Attribute Type Description
first-name string First name of the user
last-name string Last name of the user
birth-date string (format: YYYY-MM-DD) Birth date of the user
{
  "type": "reference-data",
  "id": "67",
  "attributes": {
    "last-name": "LASTNAME",
    "first-name": "FIRSTNAME",
    "birth-date": "2000-01-01"
  }
}

External identity

Additional data sent about the user

Attribute Type Description
user-id string Id of the external user
phone-number string Phone number of the external user
mail-address string Mail address of the external user
{
  "type": "external-identity",
  "id": "67",
  "attributes": {
    "user-id": "user-1337",
    "phone-number": "0102030405",
    "mail-address": "mail@exemple.com"
  }
}

Documents

document object

{
  "type": "documents",
  "id": "632",
  "attributes": {
    "all-first-names": ["JEAN", "JEANNE"],
    "birth-date": "1975-11-25",
    "birth-place": "PARIS 1ER",
    "car-driving-license-expiry-date": "2023-08-03",
    "document-number": "180975S01202",
    "document-type-detailed": "NULL",
    "document-type": "ID",
    "expiry-date": "2023-08-03",
    "first-name": "JEAN",
    "gender": "M",
    "issue-date": "2013-08-03",
    "issuing-state-code": "FRA",
    "last-name": "VALJEAN",
    "married-name": "NULL",
    "mrz": "IDFRAVALJEAN<<<<<<<<<<<<<<<<<<75500180975S01202JEAN<<<<<<<<<7511251M6",
    "nationality": "FRA",
    "personal-number": "NULL",
    "obtaining-date": "2018-08-03",
    "remarks": "NULL",
    "residence-address": "62 rue de Picpus 75012 Paris",
    "signed-image-back-url": "https://storage.ubble.ai/production-ubble-ai/UBBLE_DEMO/70f01f19-6ec5-4b14-9b30-2c493e49df15/a92f1974-6d64-4ca7-8266-3c2a573ff55c/tight_crops/FRA-I3-Back-a92f1974-6d64-4ca7-8266-3c2a573ff55c-1551198631997.png?response-content-type=image%2Fpng&X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Credential=XXX&X-Amz-Date=XXX&X-Amz-Expires=3600&X-Amz-SignedHeaders=host&X-Amz-Signature=XXX",
    "image-back-hash": "4971510fe454b467d7c931e38c0349f2",
    "signed-image-front-url": "https://storage.ubble.ai/production-ubble-ai/UBBLE_DEMO/70f01f19-6ec5-4b14-9b30-2c493e49df15/a92f1974-6d64-4ca7-8266-3c2a573ff55c/tight_crops/FRA-I3-Front-a92f1974-6d64-4ca7-8266-3c2a573ff55c-1551198602506.png?response-content-type=image%2Fpng&X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Credential=XXX&X-Amz-Date=XXX&X-Amz-Expires=3600&X-Amz-SignedHeaders=host&X-Amz-Signature=XXX",
    "image-front-hash": "4971510fe454b467d7c931e38c0349f2",
    "signed-image-signature-url": "https://storage.ubble.ai/production-ubble-ai/UBBLE_DEMO/70f01f19-6ec5-4b14-9b30-2c493e49df15/a92f1974-6d64-4ca7-8266-3c2a573ff55c/tight_crops/FRA-I3-Front-a92f1974-6d64-4ca7-8266-3c2a573ff55c-1551198602506.png?response-content-type=image%2Fpng&X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Credential=XXX&X-Amz-Date=XXX&X-Amz-Expires=3600&X-Amz-SignedHeaders=host&X-Amz-Signature=XXX",
    "signature-image-hash": "4971510fe454b467d7c931e38c0349f2",
    "video-back-hash": "4971510fe454b467d7c931e38c0349f2",
    "video-front-hash": "4971510fe454b467d7c931e38c0349f2",
  },
  "relationships": {
    "identity": {
      "data": {
        "type": "identities",
        "id": "661"
      },
      "links": {
        "related": "http://api/api/documents/632/identity"
      }
    }
  }
}

The document object contains information about the document presented during the identification. This object is included in the response when the identification status is processed. Values can be null.

Attribute Type Description
all-first-names list(string) List of first names extracted from the document (Visual Zone)
birth-date string (format: YYYY-MM-DD) Birth date extracted from the document (Visual Zone)
birth-place string City of birth of the user
car-driving-license-expiry-date string (format: YYYY-MM-DD) Expiration date extracted from the French driving license (type B)
document-number string Document number extracted from the document
document-type string Document category, one of (ID, Passport, Residence Permit, Driving licence, Social Security, Fiscal card, VTC, Visa, Other)
document-type-detailed string Exact type of the document (depends on the document)
expiry-date string (format: YYYY-MM-DD) Expiration date extracted from the document
first-name string First name extracted from the document (Visual Zone)
gender string Gender of the user, M,F or NULL
issue-date string (format: YYYY-MM-DD) Issuing date extracted from the document
issuing-state-code string Document issuing state (3 letters code ISO ALPHA-3)
last-name string Last name extracted from the document (Visual Zone) string
married-name string Married name of the user
mrz string MRZ extracted from the document
nationality string Nationality of the user (3 letters code ISO ALPHA-3)
obtaining-date string (format: YYYY-MM-DD) Obtaining date extracted from the document
personal-number string Personnal number of the user (depends on the exact document)
remarks string Remarks about the document
residence-address string Residence address extracted from the document
signed-image-back-url string Signed URL to access the document back image
signed-image-front-url string Signed URL to access the document front image
signed-image-signature-url string Signed URL to access the document signature image
tax-identification-number string Tax Identification number extracted from the document

Faces

face object

{
  "type": "faces",
  "id": "629",
  "attributes": {
    "actions": "rotation",
    "signed-image-url": "https://storage.ubble.ai/production-ubble-ai/UBBLE_DEMO/70f01f19-6ec5-4b14-9b30-2c493e49df15/a92f1974-6d64-4ca7-8266-3c2a573ff55c/live_face/a92f1974-6d64-4ca7-8266-3c2a573ff55c-1551198649996.png?response-content-type=image%2Fpng&X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Credential=XXX&X-Amz-Date=XXX&X-Amz-Expires=3600&X-Amz-SignedHeaders=host&X-Amz-Signature=XXX",
    "image-hash": "4971510fe454b467d7c931e38c0349f2",
    "video-hash": "4971510fe454b467d7c931e38c0349f2",
  },
  "relationships": {
    "identity": {
      "data": {
        "type": "identities",
        "id": "661"
      },
      "links": {
        "related": "http://api/api/documents/629/identity"
      }
    }
  }
}

The face object contains information about the face presented during the identification face scene. This object is included in the response when the identification status is processed.

Attribute Type Description
actions string Specify if an action has been asked to the user, and if yes, which action
signed-image-url string Signed URL to access the face image

Forms

form object

{
  "type": "forms",
  "id": "62",
  "attributes": {
    "birth-place-country": "FRA",
    "birth-date": "1978-11-25",
    "birth-place-city": "Paris",
    "birth-place-city-code": "75109",
    "gender": "M",
    "first-name": "JEAN",
    "last-name": "VALJEAN",
    "married-name": "TENARDIER",
    "nationality": "FRA",
    "phone-number": "0102030405",
    "mail-address": "example@domain.com",
    "address-first-line": "5 Rue du Faubourg Saint-Honoré",
    "address-second-line": "FIVE",
    "address-postcode": "75008",
    "address-city": "Paris",
    "address-country": "France",
    "siren": "123456789"
  },
  "relationships": {
    "identity": {
      "data": {
        "type": "identities",
        "id": "661"
      },
      "links": {
        "related": "http://api/api/identities/62/"
      }
    }
  }
}

The form object contains the information declared by the user about his/her identity. The user is presented a form in the end of the flow, where he/she can amend or enter his/her information. This object is included in the response when the identification status is processing or processed.

Attribute Type Description
gender string Gender of the user, M or F
last-name string Last name of the user
married-name string Married name of the user
first-name string First name of the user
middle-name string Middle name of the user
birth-date string (format: YYYY-MM-DD) Birth date of the user
nationality string Nationality of the user, encoded on 3 letters following ISO ALPHA-3
birth-place-country string Birth country of the user, encoded in 3 letters following ISO ALPHA-3
birth-place-city string City of birth of the user
birth-place-city-code string If in France, the city's INSEE code is returned. If not NULL is returned.
address-first-line string Address line 1 (track number and wording)
address-second-line string Address line 2 (address supplement)
address-postcode string ZIP code
address-city string City of residence
address-country string Country of residence
mail-address string Mail address
phone-number string Phone number
siren number Company number

Identity-form-matches

form object

{
  "type": "identity-form-matches",
  "id": "425",
  "attributes": {
    "score": 1.0,
    "match": 0.95
  },
  "relationships": {
    "identity": {
      "data": {
        "type": "identities",
        "id": "661"
      },
      "links": {
        "related": "http://api/api/documents/425/identity"
      }
    },
    "form": {
      "data": {
        "type": "forms",
        "id": "861"
      },
      "links": {
        "related": "http://api/api/documents/425/form"
      }
    }
  }
}

The identity-form-match object contains the results of a strict comparaison between the extracted identity and the form. This check is a compliance check and allows you to ensure that the data declared by the user is correct. This object is included in the response when the identification status is processing or processed.

Attribute Type Description
score number Matching score between the identity and the form
  • 1.0: Data are matching
  • 0.0: Data are not matching
  • -1.0: Matching cannot be processed
match number Percentage of characters matching between the identity and the form

Endpoints

Create identification - POST /identifications/

Example of request:

curl -X POST \
  https://api.ubble.ai/identifications/ \
  -u {CLIENT_ID}:{CLIENT_SECRET} \
  -H 'Content-Type: application/vnd.api+json' \
  -H 'Accept: application/vnd.api+json' \
  -d '{
  "data": {
    "type": "identifications",
    "attributes": {
      "identification-form": {
        "external-user-id" : "8887-YHYY-98976",
        "phone-number" : "+33666666666",
        "mail-address": "mail@exemple.com",
      },
      "reference-data": {
        "birth-date": "1978-11-25",
        "first-name": "JEAN",
        "last-name": "VALJEAN"
      },
      "webhook": "https://foo.com?titi=toto",
      "redirect_url": "https://bar.com?titi=toto",
      "face_required": true
    }
  }
}' | jq
import json
import requests

data = {
  "data": {
    "type": "identifications",
    "attributes": {
      "identification-form": {
        "external-user-id" : "8887-YHYY-98976",
        "phone-number" : "+33666666666",
        "mail-address": "mail@exemple.com",
      },
      "reference-data": {
        "birth-date": "1978-11-25",
        "first-name": "JEAN",
        "last-name": "VALJEAN"
      },
      "webhook": "https://foo.com?titi=toto",
      "redirect_url": "https://bar.com?titi=toto",
      "face_required": true
    },
  }
}

headers = {
  "Accept": "application/vnd.api+json",
  "Content-Type": "application/vnd.api+json",
}
res = requests.post(
  "https://api.ubble.ai/identifications/",
  auth=("CLIENT_ID", "CLIENT_SECRET"),
  data=json.dumps(data),
  headers=headers,
)
print(res.json())
const axios = require("axios");
const config = {
  auth: { username: "CLIENT_ID", password: "CLIENT_SECRET" },
  headers: {
    Accept: "application/vnd.api+json",
    "Content-Type": "application/vnd.api+json",
  },
};
const data = {
  data: {
    type: "identifications",
    attributes: {
      "identification-form": {
        "external-user-id": "8887-YHYY-98976",
        "phone-number": "+33666666666",
        "mail-address": "mail@exemple.com",
      },
      "reference-data": {
        "birth-date": "1978-11-25",
        "first-name": "JEAN",
        "last-name": "VALJEAN",
      },
      webhook: "https://foo.com?titi=toto",
      redirect_url: "https://bar.com?titi=toto",
      face_required: true,
    },
  },
};
axios
  .post("https://api.ubble.ai/identifications/", data, config)
  .then((res) => console.log(res.data))
  .catch((err) => console.log(err.response.data));

Response:

HTTP/1.1 201 Created
Content-Type: application/vnd.api+json

Content-Type: application/vnd.api+json Accept: application/vnd.api+json

Used to create an identification. The call will return an identification object.

Attribute Type Description
identification-form object Information about the user.
reference-data object Reference information about the user.
redirect_url string The url where the user will be redirected at the end of the identification. If not set, we'll used the default one created with your Ubble account
webhook string The url where you will be notified when the identification status changes. If not set, we'll used the default one created with your Ubble account
face_required boolean Specifies whether the flow should capture the user face or not

The identification-form field is an object described in the following table.

Attribute Type Description
external-user-id string External ID of the user.
phone-number string (international format) Phone number of the user (optional)
mail-address string Mail address of the user (optional)

The reference-data field is an object described in the following table.

Attribute Type Description
last-name string Declared last name sent when creating the identification.
first-name string Declared first name sent when creating the identification
birth-date string (format: YYYY-MM-DD) Declared birth date sent when creating the identification (optional)

Retrieve an identification - GET /identifications/:identification_id/

Example of request:

curl https://api.ubble.ai/identifications/11111111-1111-1111-1111-111111111111/ \
  -u CLIENT_ID:CLIENT_SECRET \
  -H 'Accept: application/vnd.api+json' | jq
import requests

headers = {"Accept": "application/vnd.api+json"}
res = requests.get(
    "https://api.ubble.ai/identifications/11111111-1111-1111-1111-111111111111/",
    auth=("CLIENT_ID", "CLIENT_SECRET"),
    headers=headers,
)
print(res.json())

const axios = require("axios");
const config = {
  auth: { username: "CLIENT_ID", password: "CLIENT_SECRET" },
  headers: {
    Accept: "application/vnd.api+json",
  },
};
axios
  .get(
    "https://api.ubble.ai/identifications/11111111-1111-1111-1111-111111111111/",
    config
  )
  .then((res) => console.log(res.data))
  .catch((err) => console.log(err.response.data));

Response:

HTTP/1.1 200 OK
Content-Type: application/vnd.api+json

Returns an identification object and includes related objects depending on identification status :

Anonymize identification - POST /identifications/:identificationId/anonymize/

Example of request:

curl -X POST https://api.ubble.ai/identifications/:identificationId/anonymize/ -u {CLIENT_ID}:{CLIENT_SECRET}
import requests

res = requests.post(
  "https://api.ubble.ai/identifications/:identificationId/anonymize/",
  auth=("CLIENT_ID", "CLIENT_SECRET"),
)
print(res.status_code)
const axios = require("axios");
const config = {
  auth: { username: "CLIENT_ID", password: "CLIENT_SECRET" },
};
axios
  .post(
    "https://api.ubble.ai/identifications/:identificationId/anonymize/",
    null,
    config
  )
  .then((res) => console.log(res.status))
  .catch((err) => console.log(err.response.data));

Response:

HTTP/1.1 202 Accepted

Used to anonymize an identification. Deletes all personal data of the associated identification. Metadata and scores are kept. If you anonymize an identification that is not processed, the identification becomes expired and is not usable anymore.

Force webhook notification - POST /identifications/:identification_id/notify/

Example of request:

curl -X POST \
  https://api.ubble.ai/identifications/11111111-1111-1111-1111-111111111111/notify/ \
  -u {CLIENT_ID}:{CLIENT_SECRET} \
  -H 'Content-Type: application/json' \
  -d '{
  "webhook": "https://webhook.site/"
}'
import requests

data = {"webhook": "https://webhook.site/"}

res = requests.post(
    "https://api.ubble.ai/identifications/11111111-1111-1111-1111-111111111111/notify/",
    auth=("CLIENT_ID", "CLIENT_SECRET"),
    data=data,
)
print(res.status_code)
const axios = require("axios");
const config = {
  auth: { username: "CLIENT_ID", password: "CLIENT_SECRET" },
  headers: {
    "Content-Type": "application/json",
  },
};
const data = {
  webhook: "https://webhook.site/",
};
axios
  .post(
    "https://api.ubble.ai/identifications/11111111-1111-1111-1111-111111111111/notify/",
    data,
    config
  )
  .then((res) => console.log(res.status))
  .catch((err) => console.log(err.response.data));

Response

HTTP/1.1 204 OK
Attribute Type Description
webhook string The url to notify. If not given, will used the default webhook set with your account manager

Returns a 204 no content.

Endpoints (Test only)

Retrieve assets - GET /identifications/:identification_id/assets/

Example of GET request :

curl https://api.ubble.ai/identifications/:identification_id/assets/ \
  -u CLIENT_ID:CLIENT_SECRET | jq
import requests

res = requests.get(
    "https://api.ubble.ai/identifications/:identification_id/assets/",
    auth=("CLIENT_ID", "CLIENT_SECRET"),
)
print(res.json())

const axios = require("axios");
axios
  .get("https://api.ubble.ai/identifications/:identification_id/assets/", {
    auth: { username: "CLIENT_ID", password: "CLIENT_SECRET" },
  })
  .then((res) => console.log(res.data))
  .catch((err) => console.log(err.response.data));

Exammple of response :

HTTP/1.1 200 OK
Content-Type: application/json
{
  "face_crops": [
    {
      "url": "https://storage.ubble.ai/production-ubble-ai/UBBLE_DEMO/9d263004-9c2d-4949-93d8-897fcd24129a/c1a6b85e-5dd3-4866-aca0-68678a501d93/live_face/c1a6b85e-5dd3-4866-aca0-68678a501d93-1555335128328.png?response-content-type=image%2Fpng&X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Credential=XXX&X-Amz-Date=XXX&X-Amz-Expires=3600&X-Amz-SignedHeaders=host&X-Amz-Signature=XXX",
      "name": "UBBLE_DEMO/9d263004-9c2d-4949-93d8-897fcd24129a/c1a6b85e-5dd3-4866-aca0-68678a501d93/live_face/c1a6b85e-5dd3-4866-aca0-68678a501d93-1555335128328.png"
    }
  ],
  "tight_crops": [
    {
      "url": "https://storage.ubble.ai/production-ubble-ai/UBBLE_DEMO/9d263004-9c2d-4949-93d8-897fcd24129a/c1a6b85e-5dd3-4866-aca0-68678a501d93/tight_crops/FRA-RB6-Front-c1a6b85e-5dd3-4866-aca0-68678a501d93-1555335078791.png?response-content-type=image%2Fpng&X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Credential=XXX&X-Amz-Date=XXX&X-Amz-Expires=3600&X-Amz-SignedHeaders=host&X-Amz-Signature=XXX",
      "area": 10000,
      "name": "UBBLE_DEMO/9d263004-9c2d-4949-93d8-897fcd24129a/c1a6b85e-5dd3-4866-aca0-68678a501d93/tight_crops/FRA-RB6-Front-c1a6b85e-5dd3-4866-aca0-68678a501d93-1555335078791.png",
      "score": 150,
      "template": {
        "id": 1234,
        "code": "RB6",
        "side": "Front",
        "country": "FRA"
      }
    },
    {
      "url": "https://storage.ubble.ai/production-ubble-ai/UBBLE_DEMO/9d263004-9c2d-4949-93d8-897fcd24129a/c1a6b85e-5dd3-4866-aca0-68678a501d93/tight_crops/FRA-RB6-Back-c1a6b85e-5dd3-4866-aca0-68678a501d93-1555335122590.png?response-content-type=image%2Fpng&X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Credential=XXX&X-Amz-Date=XXX&X-Amz-Expires=3600&X-Amz-SignedHeaders=host&X-Amz-Signature=XXX",
      "area": 10000,
      "name": "UBBLE_DEMO/9d263004-9c2d-4949-93d8-897fcd24129a/c1a6b85e-5dd3-4866-aca0-68678a501d93/tight_crops/FRA-RB6-Back-c1a6b85e-5dd3-4866-aca0-68678a501d93-1555335122590.png",
      "score": 150,
      "template": {
        "id": 1234,
        "code": "RB6",
        "side": "Back",
        "country": "FRA"
      }
    }
  ],
  "videos": {
    "face": {
      "filename": "rec-c1a6b85e-5dd3-4866-aca0-68678a501d93-1555335126735-video-face.mp4",
      "creation_date": 1555335148724,
      "url": "https://storage.ubble.ai/production-ubble-ai/UBBLE_DEMO/9d263004-9c2d-4949-93d8-897fcd24129a/c1a6b85e-5dd3-4866-aca0-68678a501d93/video/rec-c1a6b85e-5dd3-4866-aca0-68678a501d93-1555335126735-video-face.mp4?response-content-type=image%2Fpng&X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Credential=XXX&X-Amz-Date=XXX&X-Amz-Expires=3600&X-Amz-SignedHeaders=host&X-Amz-Signature=XXX"
    },
    "back_id": {
      "filename": "rec-c1a6b85e-5dd3-4866-aca0-68678a501d93-1555335093662-video-back_id.mp4",
      "creation_date": 1555335126221,
      "url": "https://storage.ubble.ai/production-ubble-ai/UBBLE_DEMO/9d263004-9c2d-4949-93d8-897fcd24129a/c1a6b85e-5dd3-4866-aca0-68678a501d93/video/rec-c1a6b85e-5dd3-4866-aca0-68678a501d93-1555335093662-video-back_id.mp4?response-content-type=image%2Fpng&X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Credential=XXX&X-Amz-Date=XXX&X-Amz-Expires=3600&X-Amz-SignedHeaders=host&X-Amz-Signature=XXX"
    },
    "front_id": {
      "filename": "rec-c1a6b85e-5dd3-4866-aca0-68678a501d93-1555335066884-video-front_id.mp4",
      "creation_date": 1555335095427,
      "url": "https://storage.ubble.ai/production-ubble-ai/UBBLE_DEMO/9d263004-9c2d-4949-93d8-897fcd24129a/c1a6b85e-5dd3-4866-aca0-68678a501d93/video/rec-c1a6b85e-5dd3-4866-aca0-68678a501d93-1555335066884-video-front_id.mp4?response-content-type=image%2Fpng&X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Credential=XXX&X-Amz-Date=XXX&X-Amz-Expires=3600&X-Amz-SignedHeaders=host&X-Amz-Signature=XXX"
    }
  }
}

It lets you see the different assets generated by Ubble during the session :

Errors

Our API returns standard HTTP success or error status codes. For errors, we will also include extra information about what went wrong encoded in the response as JSON. The various HTTP status codes we might return are listed below.

HTTP Status codes

Error Code Title Description
200 OK The request was successful.
201 Created The resource was successfully created.
202 Async created The resource was asynchronously created
400 Bad Request Your request is invalid.
401 Unauthorized Your API key is wrong.
403 Forbidden The kitten requested is hidden for administrators only.
404 Not Found The specified kitten could not be found.
405 Method Not Allowed You tried to access a kitten with an invalid method.
406 Not Acceptable You requested a format that is not json-api's one.
410 Gone The kitten requested has been removed from our servers.
415 Unsupported Media Type You used a format that is not json-api's one.
429 Too Many Requests You're requesting too many kittens! Slow down!
50X Internal Server Error We had a problem with our server. Try again later.
503 Service Unavailable We're temporarily offline for maintenance. Please try again later.

Error types

Example error response.

{
  "errors": [
    {
      "detail": "Authentication credentials were not provided.",
      "source": {
        "pointer": "/data"
      },
      "status": "401"
    }
  ]
}

All errors are returned in the form of JSON with a type and optional message.

Type Description
params_invalid Your parameters were not valid.
unknown_record Record was not found.
unknown_route URL was not valid.
queued Lookup queued. Try this request again in a few minutes.
rate_limit The request has been rate limited.
api_error Internal API error.

Service Status

To access the service current status, one can use the Ubble status page or its API. Documentation about the API is available here : https://status.ubble.ai/api

In the Ubble status page api response, you can find the status. The status gives you a description and an indicator (a level of outage).

Service in description Indicator Meaning
API major The service is unavailable
API partial The service is unavailable
IDApp major The service is unavailable
IDApp partial The verification service is slower, users are not impacted, but the response delay might be longer
Dashboard all The outage has no operational impact on the user nor on the verification service

Versioning

When we make backwards-incompatible changes to the API, we release new, dated versions. The current version is v0.4. Read our changelog to learn more about backwards compatibility. Note that events generated by API requests will always be structured according to your account API version.

Changelog

Version Date
v1.23 2022-12-07
v1.22 2022-08-25
v1.21 2022-07-05
v1.20 2022-06-13
v1.19 2022-05-10
v1.18 2022-02-10
v1.17 2021-11-26
v1.16 2021-05-05
v1.15 2021-03-18
v1.14 2021-02-26
v1.13 2021-02-25
v1.12 2021-02-22
v1.11 2021-01-19
v1.10 2020-12-04
v1.9 2020-11-10
v1.8 2020-10-07
v1.7 2020-08-31
v1.6 2020-03-02
v1.5 2020-02-19
v1.4 2019-09-04
v1.3 2019-02-26
v1.2 2019-01-16
v1.1 2018-09-01

v1.23 2022-12-07

v1.22 2022-08-25

v1.21 2022-07-05

v1.20 2022-06-13

v1.19 2022-05-10

v1.18 2022-02-10

v1.17 2021-11-26

v1.16 2021-05-05

v1.15 2021-03-18

v1.14 2021-02-26

v1.13 2021-02-25

v1.12 2021-02-22

v1.11 2021-01-19

v1.10 2020-12-04

v1.9 2020-11-10

v1.8 2020-10-07

v1.7 2020-08-31

v1.6 2020-03-02

v1.5 2020-02-19

v1.4 2019-09-04

v1.3 2019-02-26

v1.2 2019-01-16

v1.1 2018-09-01