How to use Address Verification
Automate and simplify address verification
Lean's Address Verification product helps businesses comply with KYC/AML regulations in the UAE and allows your customers to easily verify their address. We offer two methods to verify addresses:
- Bank Connection (via Open Banking): Retrieve the registered address directly from your customer's bank account. This can replace the need for a bank account statement to be uploaded as it is an already KYC’d address.
- Document Verification: Verify your customers address using official documents such as utility bills or bank statements. We’ll check that the customer is the owner of the document, that it is recent and genuine and then we will extract the address found - removing the need for a team to manually verify your customer's address each time.
Regardless of the verification method used, the address is returned in a consistent format, making it easy to process and store within your systems.
How does Address Verification work?
Bank Connection
For the Bank Connection method, your customer will need to consent and connect their bank account. This will be done via the LinkSDK which will enable your customer to enter their bank credentials to connect their account.
Once successfully connected, you will be able to retrieve the address held by the bank for that customer. We return the address as retrieved from the account and process it to return it with the following breakdown:
"address": {
"address_type": "RESIDENTIAL",
"building_type": "Apartment",
"apartment_or_villa_number": "511",
"building_name": "Ali abdulrahman building",
"street": null,
"area": "ABU HAIL",
"town_name": "Dubai",
"region": null,
"country": "United Arab Emirates",
"post_code": "0000",
"po_box": "0000",
"street_address": "511, Ali abdulrahman building, PO BOX 0000",
"address_line": "511, Ali abdulrahman building, PO BOX 0000, ABU HAIL, Dubai, United Arab Emirates"
},
Document Verification
The Document Verification method allows customers to verify their address by uploading a supported document. We currently accept documents in PDF format only and from the following supported types:
- DEWA utility bill
- Du and Etisalat telecom bills
- Tenancy contracts (Ejari)
- Bank statements
Important: Password-protected PDFs will be rejected. We notify End-users (your customers) where this is the reason why it was rejected.
If the uploaded document is not recognised as one of the supported types above, the verification will immediately fail.
Once a document is uploaded, it goes through the following sequential steps. If a document fails any step, the process stops and the verification will be returned as FAILED.
Step 1: Data Extraction
We extract the following required data from the document:
- Customer name
- Document issue date (and end date for Ejari)
- Address
Step 2: Genuineness Verification
In this step, we assess whether the uploaded document is genuine and has not been tampered with or altered. If we detect any signs of manipulation, the verification will fail.
We evaluate several indicators of genuineness, such as:
- Whether the document matches the expected format and template for that document type
- Presence of embedded fonts or inconsistencies in font usage
- Structural anomalies such as misaligned sections, irregular layouts, or missing fields
- Evidence of embedded data or metadata manipulation
- Changes in file properties that suggest the file has been altered after issuance
These checks help protect against the use of fraudulent or forged documents in the verification process.
Step 3: Address verification
We confirm that the extracted address includes the necessary fields to meet our address format requirements.
Step 4: Data Verification
We validate the extracted data by ensuring:
- The extracted name matches the customer name submitted in the API request
- The document is current:
- For utility bills, telecom bills, and bank statements: the issue date must be within the past 3 months
- For Ejari: the end date must be in the future
- An address was successfully extracted from the document
If any of these conditions are not met, the verification fails and the verification_status
will be returned as 'FAILED'.
Integrating Address Verification
To set up Address Verification and to handle both verification methods, there are 3 key elements:
- Implement LinkSDK
- Handle SDK callbacks and Webhook notifications
- Integrate with the required APIs for the address results
Implementing the LinkSDK
The LinkSDK is Lean’s frontend module for initiating End-user sessions for Address Verification and manages both verification methods. To integrate Leans LinkSDK please see the guides below; the LinkSDK can be integrated natively for mobile or via the Web SDK.
Set up Address Verification flow
To enable the Address Verification flow in the LinkSDK you will need to use the verify_address
intent.
Example
Lean.verifyAddress({
app_token: "e36dfb06-b007-4dcb-8b99-b9d10451ace9",
customer_id: "1eb3cfa9-197d-4eb2-9cd8-0b7ad2cee29d",
customer_name: "ALISTAIR SMITH",
sandbox: true
})
Bank Connection
Once you have set up the LinkSDK and set the Address Verification intent you need to ensure you can retrieve the results for both verification methods.
The Bank Connection method, is where your customer has selected to connect their bank account for address verification. With this method you can use our SDK callbacks, and you will need to integrate with the Retrieve Identity API to retrieve the associated customer's address.
SDK Callbacks
Please see documentation below on how our SDK callbacks work;
Getting the address for a Bank Connection
Where a customer has selected to verify their address by Bank Connection, you will need to call the Retrieve Identity API to retrieve the associated customer's address. This method simply returns the address as held by the bank for that customer without requiring the customer to upload a bank statement.
Retrieve Identity API response example
{
"status": "OK",
"data": {
"identities": [
{
"full_legal_name": "MARY SMITH",
"email_address": "[email protected]",
"mobile_number": "971585673015",
"address": {
"address_type": "RESIDENTIAL",
"building_type": "Apartment",
"apartment_or_villa_number": "511",
"building_name": "Ali abdulrahman building",
"street": null,
"area": "ABU HAIL",
"town_name": "Dubai",
"region": null,
"country": "United Arab Emirates",
"post_code": "0000",
"po_box": "0000",
"street_address": "511, Ali abdulrahman building, PO BOX 0000",
"address_line": "511, Ali abdulrahman building, PO BOX 0000, ABU HAIL, Dubai, United Arab Emirates"
},
"regional_data": {
"standard": "ARE.LEAN.V1",
"data": {
"full_name": "SANRA YOUSIF",
"mobile_number": "971585673015",
"gender": "FEMALE",
"national_identity_number": "784-1990-8478484-9",
"birth_date": "1990-05-09",
"email_address": "[email protected]",
"address": "511, Ali abdulrahman building, PO BOX 0000, ABU HAIL, Dubai, United Arab Emirates"
}
}
}
],
"page": {
"number": 0,
"size": 1,
"total_elements": 1,
"total_pages": 1
},
"type": "identities"
},
"results_id": "6dfa266b-4d33-483e-a226-aae0ce9bcd2b",
"message": "Data successfully retrieved",
"timestamp": "2023-10-20T06:58:11.457017332Z"
}
Document Verification
The Document Verification method allows your customers to verify their address by uploading a valid proof of address document (such as a utility bill or bank statement).
To implement this method, you will need to:
- Handle SDK callbacks to monitor document upload events
- Optionally listen to webhooks to receive verification outcomes
- Use the Retrieve Proof of Address Record API to retrieve the verified address data once processing is complete
This ensures a fully integrated flow where you can track progress, manage user experience, and store the verified address in your systems (at your discretion and in line with your data-governance policies).
SDK callbacks
The SDK callbacks will confirm the outcome of the document upload as either successful or failed. Where failed, the user would need to try uploading another document or connecting their bank account (note this will automatically be handled through the LinkSDK user flow).
Upload success example
{
"bank": {
"is_supported": false
},
"exit_point": "SUCCESS",
"last_api_response": "DOCUMENT_UPLOAD_PENDING",
"lean_correlation_id": "332oLi20GpDbQsV",
"message": "User successfully connected their bank",
"secondary_status": "DOCUMENT_UPLOAD_PENDING",
"status": "SUCCESS"
}
Upload failed example
{
"bank": {
"is_supported": false
},
"exit_point": "FAIL",
"last_api_response": "DOCUMENT_UPLOAD_FAILED",
"lean_correlation_id": "332oLi20GpDbQsV",
"message": "This document contains embedded files which aren't supported. Please upload a standard PDF. ",
"secondary_status": "DOCUMENT_UPLOAD_FAILED",
"status": "CANCELLED"
}
Webhooks
Once the document has been uploaded and processed we will notify you via webhook which will contain a request id. This request id is specific to the document uploaded for that customer and will be needed to retrieve the verification results from the API. We have 2 webhook notifications:
Webhook 1: Proof of address document upload started
When the document has been uploaded or failed to upload you will be notified via webhook.
Upload successful example
{
"id": "0882d6e7-ba9b-4dfc-8a85-cef412e53605",
"webhook_message_id": "996fe64e-b948-43f7-8777-70787c763f78",
"status": "OK",
"event_type": "kyc.proof_of_address.created",
"timestamp": "2025-04-07T09:37:27.284680Z",
"request": {
"id": "f1f79664-f285-45be-b3dc-1e3086597ebb",
"type": "kyc.proof_of_address.created",
"status": "PENDING",
"message": "Proof of address upload started",
"event_id": "996fe64e-b948-43f7-8777-70787c763f78",
"timestamp": "2025-04-07T09:37:27.256860319Z",
"customer_id": "e7fadbaa-0be4-4c25-9d62-770a5d325ec8"
},
"response": null
}
Upload failed example
{
"id": "3e6d0e65-a585-40f1-be38-1010255c51f6",
"webhook_message_id": "c5a9219f-e0d0-4946-a2d2-52910ebcb32a",
"status": "OK",
"event_type": "kyc.proof_of_address.created",
"timestamp": "2025-04-04T06:32:21.659912Z",
"request": {
"id": "e0e40b78-b090-4ef5-a183-eec256c954bc",
"type": "kyc.proof_of_address.created",
"status": "FAILED",
"message": "Filename is illegal",
"event_id": "c5a9219f-e0d0-4946-a2d2-52910ebcb32a",
"timestamp": "2025-04-04T06:32:21.649588178Z",
"customer_id": "e7fadbaa-0be4-4c25-9d62-770a5d325ec8"
},
"response": null
}
Webhook 2: Proof of address updated
When the document has been processed and the results are ready we will send a webhook notification to confirm if the verification was successful or failed. You will need to use the request id to retrieve the results.
Successful verification example
{
"id": "cad9eea3-f4e4-417f-8717-815223f7c3f1",
"webhook_message_id": "41919ee5-10f8-4c51-8a7e-408ae5694415",
"status": "OK",
"event_type": "kyc.proof_of_address.updated",
"timestamp": "2025-04-03T12:38:17.475122Z",
"request": {
"id": "2a957356-55d9-4e6d-84ab-706bbd6145e4",
"type": "kyc.proof_of_address.updated",
"status": "OK",
"message": "Proof of address verification was successful",
"event_id": "41919ee5-10f8-4c51-8a7e-408ae5694415",
"timestamp": "2025-04-03T12:38:17.467413373Z",
"customer_id": "e7fadbaa-0be4-4c25-9d62-770a5d325ec8"
},
"response": null
}
Failed verification example
{
"id": "40818562-3491-4760-808a-ed1498bcdc90",
"webhook_message_id": "f9473929-2596-4e6f-836a-749bb0834200",
"status": "OK",
"event_type": "kyc.proof_of_address.updated",
"timestamp": "2025-04-07T09:37:33.887478Z",
"request": {
"id": "f1f79664-f285-45be-b3dc-1e3086597ebb",
"type": "kyc.proof_of_address.updated",
"status": "FAILED",
"message": "Document has expired. Valid until: 2025-03-18",
"event_id": "f9473929-2596-4e6f-836a-749bb0834200",
"timestamp": "2025-04-07T09:37:33.881791052Z",
"customer_id": "e7fadbaa-0be4-4c25-9d62-770a5d325ec8"
},
"response": null
}
Getting the address for a Document Verification
Where a customer has selected to verify their address via the Document Verification method, you will need to call the Retrieve Proof of Address Record using the ‘request id’ to retrieve the verification response.
Request example
GET /kyc/v1/customers/<customer_id>/proof-of-address/<proof_of_address_id>
Response example
{
"id": "d121cd88-634d-4b39-bb5b-2f8aa9acaa52",
"status": "OK",
"data": {
"verification_status": "OK",
"verification_message": "Proof of Address document is successfully verified",
"customer_id": "1eb3cfa9-197d-4eb2-9cd8-0b7ad2cee29d",
"type": "PROOF_OF_ADDRESS",
"document": {
"type": "UTILITY_BILL",
"id": "62964215-e5b3-4efb-ba27-4d944119e18d",
"name": "DEWA_AARON.pdf",
"uploaded_at": "2025-03-27T09:24:36.30195553Z",
"valid_until": null,
"issuing_authority": "DEWA"
},
"kyc_checks": [
{
"step": "DATA_EXTRACTION",
"status": "OK",
"status_description": "Data extraction completed successfully"
},
{
"step": "GENUINE_VERIFICATION",
"status": "OK",
"status_description": "Genuine verification completed successfully"
},
{
"step": "ADDRESS_VERIFICATION",
"status": "OK",
"status_description": "Address verification completed successfully"
},
{
"step": "DATA_VERIFICATION",
"status": "OK",
"status_description": "Data verification completed successfully"
}
],
"extracted_data": {
"address": {
"address_type": "RESIDENTIAL",
"building_type": "Apartment",
"apartment_or_villa_number": "511",
"building_name": "Ali abdulrahman building",
"street": null,
"area": "ABU HAIL",
"town_name": "Dubai",
"region": null,
"country": "United Arab Emirates",
"post_code": "0000",
"po_box": "0000",
"street_address": "511, Ali abdulrahman building, PO BOX 0000",
"address_line": "511, Ali abdulrahman building, PO BOX 0000, ABU HAIL, Dubai, United Arab Emirates"
},
"personal_data": {
"full_name": "SANDRA YOUSIF ."
},
"document_issue_date": "2025-01-24",
"document_effective_duration_from": null,
"document_effective_duration_to": null
},
"reference_data": {
"full_name": "SANDRA YOUSIF"
}
}
}
Understanding the Document Verification response
Field | Description |
---|---|
id | This is the Document ID for the uploaded document |
status | API response status |
data.verification_status | Status of proof of address verification. Possible values are OK, FAILED, PENDING |
data.verification_message | Message indicating proof of address verification success or failure |
data.customer_id | This is the id for the customer who has uploaded their proof of address document |
data.document | Object which gives information about the uploaded document |
data.document.type | The type of document upload; TELECOM_BILL, UTILITY_BILL, BANK_STATEMENT, TENANCY_CONTRACT |
data.document.valid_until | The date until which the document is considered valid. For Ejari this is the end tenancy date for all utility and telecom bills and bank statements this is 3 months from the date of issue |
data.document.issuing_authority | This is the authority who has issued the document, for example DEWA or Du. |
kyc_checks > DATA_EXTRACTION | Indicates if data extraction from the document was successful or not |
kyc_checks > LEGITIMACY_VERIFICATION | This checks the genuineness of the document, indicating if the document is valid and has not been edited or modified |
kyc_checks > ADDRESS_VERIFICATION | This checks the relevant fields are present in the extracted address |
kyc_checks > DATA_VERIFICATION | This checks the document is within date and the name on the document matches the customer name provided |
extracted_data.address.address_line | This is the address line extracted from the document |
extracted_data.address.address_type | This identifies if the address is residential or commercial |
extracted_data.address.country | Where present, will return the country as found in the address line |
extracted_data.address.post_code | Where present, will return the PO number as found in the address line |
extracted_data.address.street_address | Where present, will return the street address as found in the address line |
extracted_data.address.town_name | Where present, will return the town name as found in the address line |
extracted_data.address.region | Where present, will return the region as found in the address line |
extracted_data.personal_data.full_name | This is the customers full name as extracted from the document uploaded |
document_issue_date | This is the date when the document was issued |
document_effective_duration_from | This is applicable to Ejari only and defines the start date of the contract |
document_effective_duration_to | This is applicable to Ejari only and defines the end date of the contract |
reference_data.full_name | This is the customers name passed in the request body when the document was uploaded |
Failed status messages on upload
This table outlines the failures that can happen when a document is uploaded and the pre-validation checks are run on the document.
Reason | Detailed Response Message | Status |
---|---|---|
No document provided | No document uploaded. Please select a PDF file to continue. | FAILED |
Missing filename | The document is missing a file name. Please try again with a named file. | FAILED |
Filename too long (>50 characters) | The file name is too long. Please shorten it and try again. | FAILED |
Unsupported file type (non-PDF) | Unsupported file type. Please upload a PDF document. | FAILED |
Invalid filename characters | Your file name contains unsupported characters. Please rename it and try again. | FAILED |
Password protected PDF | The document is password protected. Please upload a PDF that isn't password protected. | FAILED |
Corrupted PDF file | The file is either corrupted or not a valid PDF. Please upload a valid PDF document. | FAILED |
PDF contains JavaScript | This document contains unsupported content. Please upload a clean PDF file. | FAILED |
PDF contains embedded files | This document contains embedded files which aren't supported. Please upload a standard PDF. | FAILED |
File size too large (>4MB) | Uploaded file is too big | INVALID_PARAMETERS |
Wrong content type | Unsupported file type. Please upload a PDF document. | FAILED |
Missing or invalid authorisation | 401 Unauthorised (standard HTTP response) | UNAUTHORIZED |
Missing required reference data | 400 Bad Request - Invalid Parameters | INVALID_PARAMETERS |
Rate Limiting | POA is already initiated for this customer: [customerId] | RATE_LIMIT_EXCEEDED |
Failed status message by verification step
This table outlines the failures you could receive in the KYC checks that are completed as part of the document upload verification. If these errors occur, you will see these failed message detailed in the ‘Retrieve Proof of Address Record’ response.
Verification step | Detailed Response Message |
---|---|
Data Extraction | Failed to upload proof of address document |
Genuine verification | PDF contains unembedded fonts |
Genuine verification | Embedded fonts check failed |
Genuine verification | PDF contains hidden content/layers |
Genuine verification | Failed to check for hidden content: [error message] |
Genuine verification | No reference documents configured for type: [document type] |
Genuine verification | Reference document comparison verification failed |
Genuine verification | Error while matching documents |
Genuine verification | PDF appears to be image-based/scanned or invalid document |
Genuine verification | Failed to process reference document: [file path] |
Genuine verification | Suspicious metadata: Document modified after creation. Created: [timestamp]; modified: [timestamp]; interval: [diff] |
Genuine verification | Suspicious metadata: Document modified after creation |
Genuine verification | Suspicious metadata: Creation date is unknown |
Genuine verification | Suspicious metadata: Unrecognized PDF creation software |
Address Verification | Address data is missing |
Address Verification | Address line is missing |
Address Verification | Address line is incomplete. At least 3 components must be provided. Found: [count] |
Data Verification | Document has expired. Valid until: [date] |
Data Verification | Document is more than 3 months old |
Data Verification | Extracted name does not match reference name |
Advanced integration options
In addition to using the LinkSDK, Lean also supports more advanced integration options for clients who want greater control over the user experience. This includes the ability to upload documents directly to Lean via API, without using the SDK or downloading processed documents. These options are ideal for clients building fully custom experiences, integrating Lean into existing document collection flows or storing documents for regulatory audit trails.
This section outlines the steps required to implement address verification without the SDK, including how to securely upload documents to Lean and retrieve verification results via API.
Retrieving the uploaded document from Document Verification
You can retrieve the document file a customer has uploaded for proof of address by calling the proof of address endpoint and using the document id to retrieve any documents uploaded by that customer for address verification.
Example request
Curl:
curl -L 'https://api.ae02.leantech.me/files/kyc/poa/a308f630-04ef-4c26-8491-9a23fa2b3894.pdf'
-H 'Accept-Language: en'
-H 'Accept: application/pdf'
Example response
Uploaded document returned as PDF
Uploading a document to Lean via API
You can also directly integrate via API to use the Document Verification method for Address Verification. To use this integration you will need to integrate with the ‘Upload Proof of Address Document’ to upload the document directly to Lean and the ‘Retrieve Proof of Address Record’ API to retrieve the address response.
To upload the address document to Lean for processing you will need to send a request to upload to /kyc/v1/customers/<customer_id>/proof-of-address with the following parameters;
- document type
- customer name
Upload document request example
Curl:
curl -L 'https://sandbox.ae02.leantech.me/kyc/v1/customers/1eb3cfa9-197d-4eb2-9cd8-0b7ad2cee29d/proof-of-address'
-H 'Accept: application/json'
-F 'file=@"<file>"' -F 'reference_data="{
\"document_type\": \"TELECOM_BILL\",
\"full_name\": \"MELANIE SLAV\"
}";type=application/json'
Upload document response, success example
{
"id": "d739613e-c05d-4295-bfba-050c33cb71a4", // this is proof_of_address_id
"status": "PENDING",
"message": "Successfully processed file"
}
Upload document response, failed example
{
"timestamp": "2025-04-01T12:59:53.072243482Z",
"status": "INVALID_PARAMETERS",
"message": "The document is password protected. Please provide an unencrypted version",
"metadata": null
}
{
"timestamp": "2025-04-01T12:59:53.072243482Z",
"status": "RATE_LIMIT_EXCEEDED",
"message": "POA is already initiated for this customer: [customerId]",
"metadata": null
}
Once you’ve uploaded the document to Lean via API we will notify you via webhook whether the upload was successful or failed. Where successfully uploaded, we will then notify you when the processing has been completed and the results are ready. You will need the request id from the webhook notification to call the Proof of Address API for the address verification result. Full details of the webhooks and the Proof of Address API can be found above in this document.
Get list of all Document Verifications for a customer
You can retrieve a list of all Document Verifications completed for a customer using the customer ID from the ‘List Proof of Address Record’ API. This API will return all results for a customer ID where a document has been uploaded and processed for Address Verification.
Example request
Curl:
curl -L 'https://sandbox.ae02.leantech.me/kyc/v1/customers/1eb3cfa9-197d-4eb2-9cd8-0b7ad2cee29d/proof-of-address'
-H 'Accept: application/json'
Example response
{
"content": [
{
"id": "ca83ced8-63b6-4a40-89aa-840ffeb8e955",
"status": "PENDING",
"data": null
},
{
"id": "4f9c4037-e2f7-4af6-80e1-26d7dfb9b11c",
"status": "OK",
"data": {
"verification_status": "FAILED",
"verification_message": "Document has expired. Valid until: 2025-01-17",
"customer_id": "13a0258b-849d-4f89-a46e-5869995859da",
"type": "PROOF_OF_ADDRESS",
"document": {
"type": "BANK_STATEMENT",
"id": "9ae0938b-db20-4c88-913e-b1e63ef273c3",
"name": "CBD.pdf",
"uploaded_at": "2025-04-08T09:53:57.747608645Z",
"valid_until": "2025-01-17",
"issuing_authority": "BANK"
},
"kyc_checks": [
{
"step": "DATA_EXTRACTION",
"status": "OK",
"status_description": "Data extraction completed successfully"
},
{
"step": "GENUINE_VERIFICATION",
"status": "OK",
"status_description": "Legitimacy verification completed successfully"
},
{
"step": "ADDRESS_VERIFICATION",
"status": "OK",
"status_description": "Address verification completed successfully"
},
{
"step": "DATA_VERIFICATION",
"status": "FAILED",
"status_description": "Document has expired. Valid until: 2025-01-17"
}
],
"extracted_data": {
"address": {
"address_type": "RESIDENTIAL",
"building_type": "Apartment",
"apartment_or_villa_number": "511",
"building_name": "Ali abdulrahman building",
"street": null,
"area": "ABU HAIL",
"town_name": "Dubai",
"region": null,
"country": "United Arab Emirates",
"post_code": "0000",
"po_box": "0000",
"street_address": "511, Ali abdulrahman building, PO BOX 0000",
"address_line": "511, Ali abdulrahman building, PO BOX 0000, ABU HAIL, Dubai, United Arab Emirates"
},
"personal_data": {
"full_name": "SANDRA YOUSIF"
},
"document_issue_date": "2025-01-17",
"document_effective_duration_from": "2025-01-01",
"document_effective_duration_to": "2025-01-17"
},
"reference_data": {
"full_name": "SANDRA YOUSIF"
}
}
},
{
"id": "baa62855-3713-4841-94da-d96492bc4d05",
"status": "OK",
"data": {
"verification_status": "FAILED",
"verification_message": "",
"customer_id": "13a0258b-849d-4f89-a46e-5869995859da",
"type": "PROOF_OF_ADDRESS",
"document": {
"type": "BANK_STATEMENT",
"id": "a70456b1-6a08-4097-a611-67dc974e6dc2",
"name": "SANDRA_ADCB_2_CODE_REQUIRED.pdf",
"uploaded_at": "2025-04-08T09:53:47.301814515Z",
"valid_until": null,
"issuing_authority": null
},
"kyc_checks": [],
"extracted_data": null,
"reference_data": {
"full_name": "SANDRA YOUSIF"
}
}
}
],
"page": {
"number": 0,
"size": 100,
"total_elements": 3,
"total_pages": 1
}
}
Updated about 6 hours ago