NAV Navbar
shell

I. API user verification

API Introduction

api_flow

API Postman examples

https://youtu.be/yD3zeC5WiO4

We have already done the work for you! Just use our sample POSTMAN requests to use our API, and retrieve the verification information on your backend.

Step 1 : Authentication

Header parameters

// JS example
const authorization = {
  client_id: '5d7a4cb96fcee22ed7a1511f',
  client_secret: 'JZRCJ06KUJKXPCMA59D0ZAUEZ4YB51JX',
};
const authorizationString = `${authorization.client_id}:${authorization.client_secret}`;
const authorizationHeader = `Basic ${Buffer.from(authorizationString).toString('base64')}`;
{
  'Content-Type': 'application/x-www-form-urlencoded',
  Authorization: 'Basic NWQ3YTRjYjk2ZmNlZTIyZWQ3YTE1MTFmOkpaUkNKMDZLVUpLWFBDTUE1OUQwWkFVRVo0WUI1MUpY',
}

Request parameters

/**
 * @param {string} [grant_type=client_credentials] - Authorization grant type
 */

Request sample

curl -X POST \
  https://api.getmati.com/oauth \
  -H 'Authorization: Basic NWQ4NDkxNzNiNmZkMmUwMDFjZWEyYWNjOjlGMVlCMDRBV0pNMVJXQUJCNE1XM0sxWE5QV1kzVjJO' \
  -H 'Content-Type: application/x-www-form-urlencoded' \
  -d grant_type=client_credentials

Response sample

{
    "access_token": "eyJhbGciOiJIUzI1NiIsInR5",
    "expiresIn": 3600
}

Step 2: Create a new identity

Header parameters

{
  'Content-Type': 'application/json',
  Authorization: 'Bearer eyJhbGciOiJIUzI1NiIsInR5cC',
}

Request parameters

/**
 * @param {Object.<string, *>} metadata - Any metadata values to pass through verification.
 * They are 2 rules: (1) we support only one level of nesting, (2) it should be less 4Kb.
 */

Sample request to create a new mati identity

curl -X POST \
  https://api.getmati.com/v2/identities \
  -H 'Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cC' \
  -H 'Content-Type: application/json' \
  -d '{"metadata":{"user":"JOHN MALCOVICH","id":"8ad234f293ed89a89d88e12ab"}}'

Sample response

{
    "_id": "5d78fa3a2c6c0449dc4209fa",
    "alive": null,
    "dateCreated": "2019-09-11T13:44:26.096Z",
    "dateUpdated": "2019-09-11T13:44:26.096Z",
    "metadata": {
        "user": "JOHN MALCOVICH",
        "id": "8ad234f293ed89a89d88e12ab"
    },
    "status": "pending",
    "user": "5d3aea392127f21828d6d84b"
}

Request params Description
metadata include JSON metadata to pass whatever information you need. This metadata will be sent inside the verification webhook too. You are then able to know which one of your user got verified.
Response params Description
_id Identity _id
alive Shows does a person alive on liveness or not
metadata Any metadata values to pass through verification
status Identity status
user User _id

Step 3: upload user verification data

Header parameters

{
  Authorization: 'Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJjbGllbnQiOnsiX2lkIjoiNWQ4NDkxNzNiNmZkMmUwMDFjZWEyYWNjIiwibWVyY2hhbnQiOiI1ZDg0OTExOGI2ZmQyZTAwMWNlYTJhYzkifSwidXNlciI6eyJfaWQiOiI1ZDg0OTExOGI2ZmQyZTAwMWNlYTJhYzciLCJmaXJzdE5hbWUiOiJKb2huIEFkbWluIiwibGFzdE5hbWUiOiJNYWxrb3ZpYyJ9LCJpYXQiOjE1Njg5NjkzMzcsImV4cCI6MTU2ODk3MjkzNywiaXNzIjoib2F1dGgyLXNlcnZlciJ9.NimhrCKThLwWjQZtfd-RYu97x7Zl89outq6vuPt_qes',
}

Sample BODY for user inputs (to be included into your POST request to Mati)

// JS example 
const inputs = [
  {
    inputType: 'document-photo', 
    group: 0,
    data:
      {
        type: 'national-id',
        country: 'USA', 
        region: 'IL', 
        page: 'front', 
        filename: 'USA-NI-FRONT.jpg', 
      },
  },
  {
    inputType: 'selfie-photo',
    data:
      {
        filename: 'SELFIE_PHOTO.jpg', 
      },
  },
  {
    inputType: 'selfie-video', 
    data:
      {
        filename: 'SELFIE_VIDEO.mp4', 
      },
  },
];

const form = new FormData({});
form.append('inputs', JSON.stringify(inputs));
form.append('document', fs.createReadStream('./USA-NI-FRONT.jpg'), 'USA-NI-FRONT.jpg');
form.append('selfie', fs.createReadStream('./SELFIE_PHOTO.jpg'), 'SELFIE_PHOTO.jpg');
form.append('video', fs.createReadStream('./SELFIE_VIDEO.mp4'), 'SELFIE_VIDEO.mp4');

Response parameters

/**
 * @param {Object[]} response
 * @param {boolean} response.result - Set up to true if input passes an error
 * @param {Object} response.error - Error data
 * @param {string} response.error.code - Error code
*/
Parameter Description
inputType Represents the type of user input. Any of ['document-photo', 'selfie-photo', 'selfie-video']
group Index of verificationSteps with given inputType in merchant configurations
type Any of ["driving-license", "national-id", "passport", "proof-of-residency"]
country Country code. Full list provided on the right section.
region USA states codes. Full list provided on the right section.
page Page id to upload. Any of ['front', 'back']
filename Original file name
Error Description
input.not.found input type is missing in merchant config. To fix check verification requirements on the integration page
input.locked data already uploaded and processing.
media.not.found missing media data. Check that file is assigned to FormData or that "data.filename" param in "inputs" is equal to the real filename
validation.error input data validation fail. Check "data" field params in "inputs".

Sample POST request for: single document photo input

curl -X POST \
  https://api.getmati.com/v2/identities/5d84bebadee2cc001b2167c1/send-input \
  -H 'Authorization: Bearer eyJhbGciOiJIUzI1NiIsI' \
  -F 'inputs=[{"inputType":"document-photo","group":0,"data":{"type":"national-id","country":"US","region":"IL","page":"front","filename":"USA-NI-FRONT.jpg"}}]' \
  -F document=@USA-NI-FRONT.jpg

Sample POST request for: two sided document photos input

curl -X POST \
  https://api.getmati.com/v2/identities/5d84bebadee2cc001b2167c1/send-input \
  -H 'Authorization: Bearer eyJhbGciOiJIUzI1NiIsI' \
  -F 'inputs=[{"inputType":"document-photo","group":0,"data":{"type":"national-id","country":"US","region":"IL","page":"front","filename":"USA-NI-FRONT.jpg"}},{"inputType":"document-photo","group":0,"data":{"type":"national-id","country":"US","region":"IL","page":"back","filename":"USA-NI-BACK.jpg"}}]' \
  -F document=@USA-NI-FRONT.jpg \
  -F document=@USA-NI-BACK.jpg

Sample POST request for: selfie photo input

curl -X POST \
  https://api.getmati.com/v2/identities/5d84bebadee2cc001b2167c1/send-input \
  -H 'Authorization: Bearer eyJhbGciOiJIUzI1NiIsI' \
  -F 'inputs=[{"inputType":"selfie-photo","data":{"filename":"SELFIE_PHOTO.jpg"}}]' \
  -F selfie=@SELFIE_PHOTO.jpg

Sample POST request for: liveness video input

curl -X POST \
  https://api.getmati.com/v2/identities/5d84bebadee2cc001b2167c1/send-input \
  -H 'Authorization: Bearer eyJhbGciOiJIUzI1NiIsI' \
  -F 'inputs=[{"inputType":"selfie-video","data":{"filename":"SELFIE_VIDEO.mp4"}}]' \
  -F video=@SELFIE_VIDEO.mp4 

Sample POST request for: full user input (documents & biometrics)

curl -X POST \
  https://api.getmati.com/v2/identities/5d84bebadee2cc001b2167c1/send-input \
  -H 'Authorization: Bearer eyJhbGciOiJIUzI1NiIsI' \
  -F 'inputs=[{"inputType":"document-photo","group":0,"data":{"type":"national-id","country":"US","region":"IL","page":"front","filename":"USA-NI-FRONT.jpg"}},{"inputType":"document-photo","group":0,"data":{"type":"national-id","country":"US","region":"IL","page":"back","filename":"USA-NI-BACK.jpg"}},{"inputType":"selfie-photo","data":{"filename":"SELFIE_PHOTO.jpg"}},{"inputType":"selfie-video","data":{"filename":"SELFIE_VIDEO.mp4"}}]' \
  -F document=@USA-NI-FRONT.jpg \
  -F document=@USA-NI-BACK.jpg \
  -F selfie=@SELFIE_PHOTO.jpg \
  -F video=@SELFIE_VIDEO.mp4 

Country codes

["AD","AE","AF","AG","AI","AL","AM","AO","AR","AT","AU","AW","AZ","BA","BB","BD","BE","BF","BG","BH","BI","BJ","BM","BN","BO","BR","BS","BT","BW","BZ","CA","CD","CF","CG","CH","CI","CL","CM","CN","CO","CR","CW","CY","CZ","DE","DJ","DK","DM","DO","DZ","EC","EE","EG","ER","ES","ET","FI","FJ","FR","GA","GB","GD","GE","GH","GM","GN","GQ","GR","GT","GW","GY","HK","HN","HR","HT","HU","ID","IE","IL","IN","IS","IT","JM","JO","JP","KE","KG","KH","KI","KM","KN","KR","KV","KW","KZ","LA","LB","LC","LI","LK","LS","LT","LU","LV","LY","MA","MC","MD","ME","MG","MK","ML","MM","MN","MT","MU","MV","MW","MX","MY","MZ","NA","NE","NG","NI","NL","NO","NP","NR","NU","NZ","OM","PA","PE","PG","PH","PK","PL","PS","PT","PY","QA","RO","RS","RU","RW","SA","SB","SC","SE","SG","SI","SK","SL","SM","SN","SO","SR","SS","ST","SV","SZ","TD","TG","TH","TJ","TL","TM","TN","TO","TP","TR","TT","TV","TZ","UA","UG","US","UY","UZ","VA","VE","VN","VU","WS","YE","ZA","ZM"]

USA states

["AL","AK","AZ","AR","CA","CO","CT","DE","DC","FL","GA","HI","ID","IL","IN","IA","KS","KY","LA","ME","MD","MA","MI","MN","MS","MO","MT","NE","NV","NJ","NM","NY","NC","NH","ND","OH","OK","OR","PA","RI","SC","SD","TN","TX","UT","VT","VA","WA","WV","WI","WY"]

II. Web SDK user verification

Android SDKs integration

Web SDK code snippet

// Web SDK 
<script src="https://web-button.mati.io/button.js">
</script>
<mati-button
  clientid="5bbb93f7f24e3050c" // from your Mati dashboard
  metadata={"user_id":"124778"}
/>

websdk

III. Mobile SDKs user verification

Android SDKs integration

iOS SDK user verification

Pod install

pod 'Mati-Global-ID-SDK'
pod install

Swift integration

MFKYC.instance.metadata = ["email": "john@doe.com"]
let matiButton = MFKYCButton()
matiButton.frame = CGRect(x: 0, y: 20, width: 320, height: 60)
matiButton.title = "Start verification"
view.addSubview(matiButton)

Objective-C integration

[MFKYC instance].metadata = @{"email": "john@doe.com"};
MFKYCButton *matiButton =[[MFKYCButton alloc] init];
matiButton.frame = CGRectMake(0, 20, 320, 60);
matiButton.title = @"Start verification";
[self.view addSubview:matiButton];

Min requirements:

Android SDK user verification

Android SDK install

implementation 'com.matilock:mati-global-id-sdk:XXX.YYY.ZZZ'

Java integration

<com.matilock.mati_kyc_sdk.MatiLoginButton
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                app:text="Custom"/>

Metadata metadata = new Metadata.Builder()
                .with("userId", "Your_Client_ID")
                .with("type", 2)
                .build();

Mati.getInstance().setMetadata(metadata);

Other integrations

drawing drawing drawing drawing

IV. Webhooks - receive user verification data

Introduction

Mati webhooks

Few important notes:

Webhook Description
verification_completed Webhook sent once Mati is done verifying a user entirely. When you get this webhook, you should GET the "resource" URL to get the verification data about the user.
verification_started Webhook sent at the beginning of the SDK flow, when Mati is making a new verification record (usually at the upload of the first ID document)
verification_expired Webhook sent when verification is not completed after 30 mins. It means that the user probably did not finish the verification flow.
verification_inputs_completed Webhook sent when the user has uploaded all inputs via SDKs. You can use that webhook to know when to redirect the user after the verification flow on your website/App.
verification_updated Webhook sent from your Mati dashboard manually after updating the user verification information.
step_completed Webhook sent after each verification step is completed (liveness, face match, document reading, etc...)

webhook_flow

Webhook Postman examples

https://youtu.be/yD3zeC5WiO4

We have already done the work for you! Just use our sample POSTMAN requests to use our API, and retrieve the verification information on your backend.

Step 1 : Register a webhook URL on your Mati dashboard

If you login to your Mati dashboard, and go the developer section, you will be able to add a new webhook URL. That way Mati knows to what URL it should communicate webhooks related information. You should also add a "webhook secret" (user any string of any length). That assures you that the webhook is indeed coming from Mati.

Step 2: Receive the webhook

Webhook you will receive once user verification is finished

{
  "eventName": "verification_completed",
  "identityStatus": "reviewNeeded",
  "metadata": {
    "user_email": "john.smith@gmail.com",
    "user_name": "john_smith",
    "user_id": "123456789"
  },
  "resource": "https://api.getmati.com/v1/verifications/5c6b534bd3efe73404b52341",
  "details": {
    "age": {
      "data": 37
    }
  }
}

You will receive a "verification_completed" webhook. This webhook is sent only once Mati could complete the user verification. This webhook will contain the following fields.

Parameter Description
eventName Webhook type
metadata Metadata that you transmitted to Mati SDKs. You can put any type of metadata here. That way, your backend knows what user just got verified
resource Contains the link you should use in order to get the user verification information

Step 3: Validate webhook signature (optional)

Sample code to validate your webhook signature

const crypto = require('crypto');

// A sample webhook coming from Mati
const WEBHOOK_PAYLOAD = 
{   
    eventName: 'verification_completed',
    metadata: {email: 'john@gmail.com'},
    payload: {},
    resource: 'https://api.mati.io/api/v1/verifications/db8d24783',
};

const MERCHANT_SECRET = 'your_mati_webhook_secret';

// Mati hashes your webhook payload
const signature = crypto.createHmac('sha256', MERCHANT_SECRET).update(JSON.stringify(WEBHOOK_PAYLOAD)).digest('hex');
console.log(signature);

function verify(signature, secret, payloadBody) {
    let hash = crypto.createHmac('sha256', secret);
    hash = hash.update(payloadBody).digest('hex');
    return hash === signature;
}

let isValidPayload;

isValidPayload = verify(signature, MERCHANT_SECRET, JSON.stringify(WEBHOOK_PAYLOAD));
console.log(isValidPayload);

When you create a webhook url on your Mati dashboard, you define a "secret". This "secret" will then be hashed with the "payloadBody" (using SHA256) and sent in the webhook's header. In order to authenticate the webhook received, you should verify that this signature on header 'x-signature' (Signature-Sha-256) is valid. See a code snippet on the right.

Step 4: Get your authentication token

POST request to get a valid token

curl --location --request POST "https://api.getmati.com/oauth/token" \
  --header "Content-Type: application/x-www-form-urlencoded" \
  --header "Authorization: Basic $(echo -n client_id:client_secret | base64)" \
  --data "grant_type=client_credentials&scope=identity"

In order to be able to fetch the data inside the resource link, you should first get a valid token. To get a new valid token, it'you just need to perform a POST request and pass as parameters your client_id and client_secret available on your Mati dashboard.

Headers Value
Content-Type application/x-www-form-urlencoded
Authorization Basic
Body Value
grant_type client_credentials
score identity

Step 5: GET users' "resource" URL

GET request on the "resource" URL

curl --location --request GET "<your_resource_url>" \
  --header "Authorization: Bearer {{ACCESS_TOKEN}}"

Response sample

{
        "steps": [
            {
                "status": 200,
                "id": "liveness",
                "data": {
                    "selfieUrl": "http://api.getmati.com/media/selfie/bae11202.jpg",
                }
            }
        ],
        "documents": [
            {
                "type": "passport",
                "photos": [
                    "https://api.getmati.com/v1/media/ae7b963c1f23.jpg",
                    "https://api.getmati.com/v1/media/ae7b963c1f2e.jpg"
                ],
                "steps": [
                    {
                        "status": 200,
                        "id": "alteration-detection",
                    },
                    {
                        "status": 200,
                        "id": "document-reading",
                        "data": {
                            "fullName": {
                                "value": "HUGO JOSE FRANCOU"
                            },
                            "documentNumber": {
                                "value": "AAA722873"
                            },
                            "dateOfBirth": {
                                "value": "1950-07-14T00:00:00.000Z"
                            },
                        },  
                    },
                    {
                        "status": 200,
                        "id": "facematch",
                    },
                    {
                        "status": 200,
                        "id": "watchlists",
                    },
                    {
                        "status": 200,
                        "id": "mexican-curp-validation",
                        "data": {
                            "curp": "GAGF860420HDFRMR08",
                            "fullName": "GARCIA GOMEZ FERNANDO ELIAS",
                            "name": "FERNANDO ELIAS"
                    }
                ],
            },
        ],
        "id": "3452455cb0d48780"
    }

The response also contains your user's device fingerprint

    deviceFingerprint: {
                    ua: "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/76.0.3809.132 Safari/537.36",
                    browser: {
                      name: "Chrome",
                      version: "76.0.3809.132",
                      major: "76"
                    },
                    engine: {
                      name: "WebKit",
                      version: "537.36"
                    },
                    os: {
                      name: "Windows",
                      version: "10"
                    },
                    cpu: {
                      architecture: "amd64"
                    }
                  }x

If you want to access the user verification data, you need to make a GET request on the "resource" URL contained inside the webhook.

Headers Value
Authorization Basic

The response is organised in a way that it contains verification "steps". These steps are nested. For example step "document-reading" is nested inside step "document"

Steps Type Description
liveness Contains the proof of life response, making sure your user is a real person (and not a printed paper)
document-reading Will return fields read from the document: full name, date of birth, document number, etc...
facematch Face match performed between document face & user's face
watchlists Checks if there is any match found between the name extracted from the document and international watch-lists
alteration-detection Checks that the document was not altered
template-matching Checks that the presented document revision is valid
mexican-curp-validation For certain countries only (only Mexico supported for now)

How to synch your Mati dashboard with your backend?

From your Mati dashboard, you are able to modify the fields of any identity. Then, when you send an update to your backend (button on your Mati dashboard, inside identity page), Mati will send you an "update" webhook. This webhook will contain the new resource URL that has all the updated fields. Inside the "resource" URL, you should look inside each document structure, and take the "fields" to fetch the latest values.

Error codes for verification steps

Mati error codes and verification status

When you receive the verification data via webhook, you need to check for the status to be 200 (finished) and understand the error codes. By default, when there is no error, it means that the verification step was successful (no risk of fraud). When the verification step contains an error, it usually means that there is a risk of fraud.

Verification step Status Error Code Reason
template-matching 200 null N/A The document version that the user uploaded matches the expected document type version (user chose to upload a californian driving licence, and Mati checked that we received a valid version of a californian driving licence)
template-matching 200 - 400 User uploaded a document that does not match the expected version (ex: driving licence from Texas instead of California)
- - - - -
alteration-detection 200 null N/A The document that the user uploaded has no signs of fraud
alteration-detection 200 - 400 The document that the user uploaded has signs of fraud (image alteration, text alteration, etc...)
- - - - -
watchlists 200 null N/A The user was not found in any watchlist
watchlists 200 - 400 Either the user was found in a watchlist - or Mati could not extract the name from the document
- - - - -
document-reading 200 null N/A The OCR info was obtained successfully
- - - - -
facematch 200 null N/A The face in the selfie and in the ID match
facematch 200 - 400 The face in the selfie and in the ID do not match
- - - - -
mexican-curp-validation 200 null N/A The CURP matches the government database records
mexican-curp-validation 200 - 400 The CURP does not match the government database records
- - - - -
mexican-ine-validation 200 null N/A The INE number matches the government database records
mexican-ine-validation 200 - 400 The INE number does not match the government database records
- - - - -
selfie 200 null N/A There was a face in the selfie
selfie 200 - 400 There was no face in the selfie obtained
- - - - -
liveness 200 null N/A There was a real person in the video
liveness 200 - 400 There is a risk of fraud (printed paper attack, smartphone attack, etc...) and Mati cannot certify that there was a real human behind the camera

Statuses for verification steps

Each verification step takes a different amount of time. For that reason, you need to understand the lifecycle of each step. By default you should make sure that the verification step has a status 200 to analyse its results. More details here:

Verification step code Verification step name Description
0 not_stated the verification step has not started yet
100 pending the verification step is being processed
200 completed the verification step is completed, and you can analyse the result

V. FAQ

How to automate your verification process with Mati?

You are free to build your own logic, but here is the flow most companies are happy with:

1) Let the user go through Mati SDK

2) Receive the frontend callback to know when the user finished the verification flow

3) Display a beautiful waiting page to the user saying "You are under review. Please come back in a few minutes!"

4) Wait for the "verification_completed" webhook, and parse the verification information

5) If you cannot find any errors inside Mati verification steps, automatically let your user access to your service

6) If Mati found some issues with the verification, you should probably manually check the user

It's very simple, just use the sample URL on the right, and modify the metadata as you wish. If you still do not receive the metadata on your backend, just check that you are using the right quotation mark type in your URL (this is a regular mistake).

https://signup.getmati.com/?merchantToken=5ccb74e1001bd7fe76&metadata={"email":"miguel@mati.io","Client":"id3452"}

How can I open my webhook in my web browser

Yes, each webhook contains a field "matiDashboardUrl" that you can open on your Mati dashboard to visualise the verification.

What is allowed to pass to metadata?

What should I put for my "webhook secret"?

Feel free to enter any string of any length. As explained inside section II (step2), we use a webhook secret as a way to assure the authenticity of your webhook. Consider this a password that only you should know.

What happens in case a verification step fails?

Invalid verification step sample (alteration-detection)


{
    "error": {
        "code": 400,
        "message": "document is considered tempered"
    },
    "status": 200,
    "id": "alteration-detection",
},

Invalid verification step sample (liveness)



{
    "error": {
        "code": 400,
        "message": "user did not pass liveness"
    },
    "status": 200,
    "id": "liveness",
    "data": {
        "selfieUrl": "http://api.getmati.com/media/selfie/bae11202.jpg",
    }
}

Invalid verification step sample (mexican-curp-validation)



{
    "error": {
        "code": 400,
        "message": "we could not extract anything from CURP database"
    },
    "status": 200,
    "id": "mexican-curp-validation",
    "data": {
    }
},

Whenever Mati detects any risk while verifying a user, some error will be returned in at least 1 verification step. On the right, the example of some error rendered for some verification steps. So when you parse the user verification data, just try to identify any error inside any verification step. If there's none, you can automate that user verification process, and let him fully access your service.

What happens when Mati cannot read a document field?

It happens that documents are too damaged or blurry to be read. In that case Mati will render 'null' as field value to indicate that we could not read this field.

Document reading response when "documentNumber" and "dateOfBirth" could not be read


...

{
    "status": 200,
    "id": "document-reading", 
    "data": {
        "fullName": {
            "value": "HUGO JOSE FRANCOU"
        },
        "documentNumber": {
            "value": null
        },
        "dateOfBirth": {
            "value": null
        },
    },
},

...

How to download selfie & documents images?

GET request to get any image

curl --location --request GET "<your_image_url>" \
  --header "Authorization: Bearer {{ACCESS_TOKEN}}"

Once you got the verification information, you might want to store the images of selfie and documents on your server. For that, you can simply make a GET request.

Headers Value
Authorization Basic

How to know when a user finished Mati Web SDK?

How to subscribe to Mati Web SDK callback

// waiting for the script to be loaded
// for jQuery use: `$(function() { ...code... })` 
document.addEventListener('DOMContentLoaded', function(){
    // create button
    const button = document.createElement("mati-button");

    // setup attributes
    button.setAttribute("clientid", 'YOUR_CLIENT_ID');

    // setup callbacks
    button.addEventListener('mati:loaded', () => {
      console.log('loaded', /* no payload */)
    })
    button.addEventListener('mati:userFinishedSdk', ({ detail }) => {
      console.log('finished payload', detail)
    })
    button.addEventListener('mati:exitedSdk', () => {
      console.log('exited', /* no payload */)
    })

    // init button
    document.body.appendChild(button);
})

Mati Web SDK has 3 callbacks, described below.

Callback Description
mati:loaded Callback fired when popup loaded and ready to interact with user
mati:userFinishedSdk Callback fired when user clicks "done" button at the very end of Mati Web SDK flow. This indicates that the user has finished uploading all necessary information to Mati.
mati:exitedSdk Callback fired when user exits the Mati Web SDK. This indicates that the user has not finished the verification flow.