Address Verification
Address verification confirms that an applicant resides at their stated address. This is a common regulatory requirement for KYC compliance, helping prevent fraud and meet anti-money laundering obligations.
Verification Methods
TrustGate supports multiple address verification methods:
| Method | Description | Use Case |
|---|---|---|
| Document Verification | Utility bills, bank statements | Standard KYC |
| Database Lookup | Credit bureau/postal data | Quick verification |
| Manual Review | Human review of documents | Complex cases |
Accepted Documents
Primary Documents
| Document Type | Accepted Age | Required Information |
|---|---|---|
| Utility Bill | 3 months | Name, address, date |
| Bank Statement | 3 months | Name, address, date |
| Credit Card Statement | 3 months | Name, address, date |
| Government Letter | 12 months | Name, address, date |
| Tax Document | 12 months | Name, address, tax year |
Secondary Documents
| Document Type | Accepted Age | Notes |
|---|---|---|
| Rental Agreement | 12 months | Must show current address |
| Insurance Policy | 6 months | Home/auto insurance |
| Mortgage Statement | 6 months | Property must match address |
| Council Tax Bill | 12 months | UK specific |
Document Upload
Via API
curl -X POST https://api.bytrustgate.com/v1/documents \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: multipart/form-data" \
-F "applicant_id=550e8400-e29b-41d4-a716-446655440000" \
-F "type=utility_bill" \
-F "file=@/path/to/utility_bill.pdf"
Python Example
import requests
from datetime import datetime, timedelta
API_KEY = "YOUR_API_KEY"
BASE_URL = "https://api.bytrustgate.com/v1"
# Upload proof of address document
with open("utility_bill.pdf", "rb") as f:
response = requests.post(
f"{BASE_URL}/documents",
headers={"Authorization": f"Bearer {API_KEY}"},
data={
"applicant_id": applicant_id,
"type": "utility_bill",
},
files={"file": f},
)
document = response.json()
print(f"Document status: {document['status']}")
# Check extracted address
if document["status"] == "verified":
extracted_address = document["extracted_data"]["address"]
print(f"Extracted address: {extracted_address}")
OCR Extraction Results
Utility Bill Example
{
"id": "doc_456789",
"type": "utility_bill",
"status": "verified",
"extracted_data": {
"document_type": "utility_bill",
"provider": "Pacific Gas & Electric",
"utility_type": "electricity",
"account_holder": "JOHN M. DOE",
"address": {
"line1": "123 Main Street",
"line2": "Apt 4B",
"city": "San Francisco",
"state": "CA",
"postal_code": "94102",
"country": "USA"
},
"statement_date": "2025-01-01",
"due_date": "2025-01-25",
"amount_due": 125.43
},
"confidence_scores": {
"overall": 0.93,
"name": 0.96,
"address": 0.91,
"date": 0.95
}
}
Bank Statement Example
{
"id": "doc_567890",
"type": "bank_statement",
"status": "verified",
"extracted_data": {
"document_type": "bank_statement",
"institution": "Chase Bank",
"account_holder": "JOHN MICHAEL DOE",
"address": {
"line1": "123 Main Street",
"line2": "Apt 4B",
"city": "San Francisco",
"state": "CA",
"postal_code": "94102",
"country": "USA"
},
"statement_period": {
"start": "2024-12-01",
"end": "2024-12-31"
},
"account_type": "checking"
}
}
Address Matching
TrustGate automatically compares extracted addresses with applicant-provided addresses.
Match Logic
The system performs fuzzy matching to handle:
- Abbreviations (St./Street, Ave./Avenue)
- Minor spelling variations
- Missing/extra unit numbers
- Postal code format differences
Match Results
{
"address_verification": {
"status": "matched",
"confidence": 0.95,
"applicant_address": {
"line1": "123 Main St",
"city": "San Francisco",
"state": "CA",
"postal_code": "94102"
},
"document_address": {
"line1": "123 Main Street",
"line2": "Apt 4B",
"city": "San Francisco",
"state": "CA",
"postal_code": "94102"
},
"differences": [
{
"field": "line1",
"applicant": "123 Main St",
"document": "123 Main Street",
"similarity": 0.92,
"note": "Abbreviation difference"
},
{
"field": "line2",
"applicant": null,
"document": "Apt 4B",
"similarity": 0.0,
"note": "Unit number in document only"
}
]
}
}
Match Status Values
| Status | Description | Action |
|---|---|---|
matched | Addresses match within tolerance | Auto-pass |
partial_match | Some fields match, differences noted | Review recommended |
mismatch | Addresses don't match | Manual review required |
unverifiable | Cannot extract address from document | Request new document |
Document Age Validation
Documents must be recent to be valid:
from datetime import datetime, timedelta
def validate_document_age(document, max_age_months=3):
"""Check if proof of address document is within acceptable age."""
statement_date = document["extracted_data"].get("statement_date")
if not statement_date:
return False, "No date found on document"
doc_date = datetime.fromisoformat(statement_date)
max_age = timedelta(days=max_age_months * 30)
if datetime.now() - doc_date > max_age:
return False, f"Document is older than {max_age_months} months"
return True, "Document age is acceptable"
Handling International Addresses
Address Format by Country
TrustGate normalizes addresses based on country:
United States:
123 Main Street, Apt 4B
San Francisco, CA 94102
United Kingdom:
Flat 2, 45 High Street
London
SW1A 1AA
Germany:
Hauptstraße 123
10115 Berlin
Country-Specific Fields
| Country | Special Fields |
|---|---|
| USA | State (2-letter), ZIP code, ZIP+4 |
| UK | Postcode, County (optional) |
| Germany | PLZ (postal code) |
| Japan | Prefecture, ward/district |
| Australia | State (3-letter), postcode |
Configuration Options
Address Verification Settings
Configure in Settings > Workflows:
| Setting | Default | Description |
|---|---|---|
require_address_verification | true | Make address proof mandatory |
max_document_age_months | 3 | Maximum age for proof documents |
address_match_threshold | 0.85 | Minimum similarity for auto-pass |
accepted_document_types | all | Limit accepted document types |
Country-Specific Rules
{
"address_verification_rules": {
"USA": {
"max_document_age_months": 3,
"require_state": true,
"validate_zip": true
},
"GBR": {
"max_document_age_months": 3,
"require_postcode": true,
"accept_council_tax": true
},
"DEU": {
"max_document_age_months": 6,
"require_plz": true
}
}
}
Rejection Handling
Common Rejection Reasons
| Reason | Description | User Guidance |
|---|---|---|
document_too_old | Document exceeds age limit | Upload a more recent document |
address_mismatch | Address doesn't match application | Update address or upload correct document |
name_mismatch | Name doesn't match applicant | Ensure document is in your name |
unreadable | Cannot extract data | Upload clearer image |
unsupported_type | Document type not accepted | Upload utility bill or bank statement |
Handling Mismatches
def handle_address_verification_result(applicant, document):
verification = document.get("address_verification", {})
if verification["status"] == "matched":
# Address verified successfully
update_applicant_status(applicant["id"], "address_verified")
elif verification["status"] == "partial_match":
# Review differences
differences = verification.get("differences", [])
# Minor differences can be auto-approved
if all(d["similarity"] > 0.8 for d in differences):
update_applicant_status(applicant["id"], "address_verified")
else:
# Flag for review
create_case(
applicant_id=applicant["id"],
type="verification",
title="Address partial match requires review",
details=differences,
)
elif verification["status"] == "mismatch":
# Request new document or updated address
notify_applicant(
applicant["id"],
"Your proof of address doesn't match the address on your application. "
"Please upload a document showing your current address, or update your address."
)
Best Practices
Document Requirements Communication
Provide clear guidance to users:
Proof of Address Requirements:
- Document must be dated within the last 3 months
- Must show your full name and address
- Accepted: utility bills, bank statements, government letters
- NOT accepted: delivery receipts, screenshots, handwritten documents
- Must be a PDF or clear photo (minimum 1000x1000 pixels)
Multi-Document Verification
For high-risk applicants, require multiple documents:
def verify_address_enhanced(applicant_id):
"""Require two proof of address documents for high-risk applicants."""
documents = get_applicant_documents(applicant_id, type="proof_of_address")
verified_docs = [d for d in documents if d["status"] == "verified"]
if len(verified_docs) >= 2:
# Check addresses match each other
addresses = [d["extracted_data"]["address"] for d in verified_docs]
if addresses_match(addresses[0], addresses[1]):
return True, "Address verified with multiple documents"
return False, "Additional proof of address required"
Next Steps
- Document Verification - ID document verification
- Supported Documents - Full document reference
- Verification Statuses - Status lifecycle guide